#include "asm/includes.h" #include "media/includes.h" #include "system/includes.h" #include "media/a2dp_decoder.h" #include "media/esco_decoder.h" #include "classic/tws_api.h" #include "app_config.h" #include "audio_config.h" #include "audio_dec.h" #include "audio_digital_vol.h" #include "clock_cfg.h" #include "btstack/a2dp_media_codec.h" #include "media/audio_eq_drc_apply.h" #include "media/audio_equalloudness.h" #include "media/audio_vbass.h" #include "aec_user.h" #include "audio_enc.h" #include "bt_tws.h" #include "media/convert_data.h" #include "audio_effect/audio_dynamic_eq_demo.h" #include "media/effects_adj.h" #include "audio_effect/audio_eff_default_parm.h" #if TCFG_ESCO_PLC #include "PLC.h" #define PLC_FRAME_LEN 60 #endif/*TCFG_ESCO_PLC*/ #ifdef TCFG_ESCO_NOISEGATE /*小于CONST_NOISE_GATE的当成噪声处理,防止清0近端声音*/ #define LIMITER_NOISE_GATE -55000 /*-12000 = -12dB,放大1000倍,(-30000参考)*/ /*低于噪声门限阈值的增益 */ #define LIMITER_NOISE_GAIN (0 << 30) /*(0~1)*2^30*/ #endif //TCFG_ESCO_NOISEGATE #if TCFG_APP_FM_EMITTER_EN #if !TCFG_PHONE_DRC_ENABLE #undef TCFG_PHONE_DRC_ENABLE #define TCFG_PHONE_DRC_ENABLE 1 //做点烟器时,通话下行开启限幅器处理,need en TCFG_DRC_ENABLE #endif #endif /*TCFG_APP_FM_EMITTER_EN*/ #ifndef TCFG_PHONE_DRC_ENABLE #define TCFG_PHONE_DRC_ENABLE 0 #endif #define ESCO_DRC_EN TCFG_PHONE_DRC_ENABLE //通话下行增加限幅器处理,默认关闭,need en TCFG_DRC_ENABLE #if (!TCFG_DRC_ENABLE || !TCFG_PHONE_EQ_ENABLE) #undef ESCO_DRC_EN #define ESCO_DRC_EN 0 #endif #define TCFG_ESCO_USE_SPEC_MIX_LEN 0 extern const int CONFIG_A2DP_DELAY_TIME; extern const int config_mixer_en; #define AUDIO_DEC_BT_MIXER_EN config_mixer_en ////////////////////////////////////////////////////////////////////////////// struct a2dp_dec_hdl { struct a2dp_decoder dec; // a2dp解码句柄 struct audio_res_wait wait; // 资源等待句柄 struct audio_mixer_ch mix_ch; // 叠加句柄 struct audio_stream *stream; // 音频流 #if AUDIO_SURROUND_CONFIG surround_hdl *surround; //环绕音效句柄 #endif #if AUDIO_VBASS_CONFIG struct aud_gain_process *vbass_prev_gain; NOISEGATE_API_STRUCT *ns_gate; vbass_hdl *vbass; //虚拟低音句柄 #endif #if TCFG_EQ_ENABLE && TCFG_AUDIO_OUT_EQ_ENABLE struct audio_eq *high_bass; struct audio_drc *hb_drc;//高低音后的drc #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE struct convert_data *hb_convert; #endif #endif struct audio_eq *eq; //eq drc句柄 struct audio_drc *drc; // drc句柄 #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE struct convert_data *convert; #endif #if defined(MUSIC_EXT_EQ_AFTER_DRC) && MUSIC_EXT_EQ_AFTER_DRC struct audio_eq *ext_eq; //eq drc句柄 扩展eq #endif #if defined(TCFG_DYNAMIC_EQ_ENABLE) && TCFG_DYNAMIC_EQ_ENABLE struct audio_eq *eq2; //eq drc句柄 struct dynamic_eq_hdl *dy_eq; struct convert_data *convert2; #endif #if defined(TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE) && TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE struct aud_gain_process *gain; #endif struct audio_wireless_sync *sync; u8 closing; u8 preempted; u8 slience; int slience_time; u32 slience_end_time; struct audio_stream_entry *slience_entry; }; struct esco_dec_hdl { struct esco_decoder dec; // esco解码句柄 struct audio_res_wait wait; // 资源等待句柄 struct audio_mixer_ch mix_ch; // 叠加句柄 struct audio_stream *stream; // 音频流 struct audio_eq *eq; //eq drc句柄 struct audio_drc *drc; // drc句柄 #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE struct convert_data *convert;//32转16bit #endif struct channel_switch *ch_switch;//声道变换 u32 tws_mute_en : 1; // 静音 u32 remain : 1; // 未输出完成 #if TCFG_ESCO_PLC void *plc; // 丢包修护 #endif #ifdef TCFG_ESCO_NOISEGATE void *noisegate; // 噪声抑制 #endif struct audio_wireless_sync *sync; }; ////////////////////////////////////////////////////////////////////////////// struct a2dp_dec_hdl *bt_a2dp_dec = NULL; struct esco_dec_hdl *bt_esco_dec = NULL; static u8 a2dp_suspend = 0; static u16 drop_a2dp_timer = 0; extern s16 mix_buff[]; extern struct audio_dac_hdl dac_hdl; extern struct audio_dac_channel default_dac; ////////////////////////////////////////////////////////////////////////////// struct audio_wireless_sync *a2dp_output_sync_open(int sample_rate, int output_sample_rate, u8 channel); void a2dp_output_sync_close(struct audio_wireless_sync *a2dp_sync); struct audio_wireless_sync *esco_output_sync_open(int sample_rate, int output_sample_rate, u8 channels); void esco_output_sync_close(struct audio_wireless_sync *esco_sync); extern int lmp_private_esco_suspend_resume(int flag); static void bt_dec_stream_run_stop(struct audio_decoder *decoder) { #if AUDIO_DAC_MULTI_CHANNEL_ENABLE struct audio_data_frame frame = {0}; struct audio_data_frame output = {0}; frame.stop = 1; frame.channel = audio_output_channel_num(); frame.sample_rate = app_audio_output_samplerate_get(); /* audio_stream_run(&default_dac.entry, &frame); */ default_dac.entry.data_handler(&default_dac.entry, &frame, &output); audio_stream_del_entry(&default_dac.entry); #else /*AUDIO_DAC_MULTI_CHANNEL_ENABLE*/ audio_dac_stop(&dac_hdl); #endif /*AUDIO_DAC_MULTI_CHANNEL_ENABLE*/ } static int audio_dec_slience_data_handler(struct audio_stream_entry *entry, struct audio_data_frame *in, struct audio_data_frame *out) { out->data = in->data; out->data_len = in->data_len; if (in->offset == 0) { if (bt_a2dp_dec->slience == 0) { bt_a2dp_dec->slience_end_time = jiffies + msecs_to_jiffies(bt_a2dp_dec->slience_time); memset(in->data, 0, in->data_len); bt_a2dp_dec->slience = 1; } else if (bt_a2dp_dec->slience == 1) { if (time_after(jiffies, bt_a2dp_dec->slience_end_time)) { bt_a2dp_dec->slience = 2; } memset(in->data, 0, in->data_len); } } return in->data_len; } static void audio_dec_slience_process_len(struct audio_stream_entry *entry, int len) { } static struct audio_stream_entry *audio_dec_slience_stream_entry(struct a2dp_dec_hdl *dec, int time) { struct audio_stream_entry *entry = zalloc(sizeof(struct audio_stream_entry)); entry->data_handler = audio_dec_slience_data_handler; entry->data_process_len = audio_dec_slience_process_len; dec->slience = 0; dec->slience_entry = entry; dec->slience_time = time; return entry; } static void audio_dec_slience_entry_free(struct a2dp_dec_hdl *dec) { if (dec->slience_entry) { audio_stream_del_entry(dec->slience_entry); free(dec->slience_entry); dec->slience_entry = NULL; } } /*----------------------------------------------------------------------------*/ /**@brief a2dp解码close @param @return @note */ /*----------------------------------------------------------------------------*/ static void a2dp_audio_res_close(void) { if (bt_a2dp_dec->dec.start == 0) { log_i("bt_a2dp_dec->dec.start == 0"); return ; } if (!bt_a2dp_dec->closing) { bt_a2dp_dec->preempted = 1; } bt_a2dp_dec->dec.start = 0; a2dp_decoder_close(&bt_a2dp_dec->dec); #if AUDIO_SURROUND_CONFIG surround_close_demo(bt_a2dp_dec->surround); #endif #if AUDIO_VBASS_CONFIG audio_gain_close_demo(bt_a2dp_dec->vbass_prev_gain); audio_noisegate_close_demo(bt_a2dp_dec->ns_gate); audio_vbass_close_demo(bt_a2dp_dec->vbass); #endif #if TCFG_EQ_ENABLE && TCFG_AUDIO_OUT_EQ_ENABLE high_bass_eq_close(bt_a2dp_dec->high_bass); high_bass_drc_close(bt_a2dp_dec->hb_drc); #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE convet_data_close(bt_a2dp_dec->hb_convert); #endif #endif #if TCFG_EQ_ENABLE &&TCFG_BT_MUSIC_EQ_ENABLE music_eq_close(bt_a2dp_dec->eq); #if TCFG_DRC_ENABLE && TCFG_BT_MUSIC_DRC_ENABLE music_drc_close(bt_a2dp_dec->drc); #endif #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE convet_data_close(bt_a2dp_dec->convert); #endif #if defined(MUSIC_EXT_EQ_AFTER_DRC) && MUSIC_EXT_EQ_AFTER_DRC music_ext_eq_close(bt_a2dp_dec->ext_eq); #endif #if defined(TCFG_DYNAMIC_EQ_ENABLE) && TCFG_DYNAMIC_EQ_ENABLE music_eq2_close(bt_a2dp_dec->eq2); audio_dynamic_eq_ctrl_close(bt_a2dp_dec->dy_eq); convet_data_close(bt_a2dp_dec->convert2); #endif #if defined(TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE) && TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE audio_gain_close_demo(bt_a2dp_dec->gain); #endif #endif a2dp_output_sync_close(bt_a2dp_dec->sync); bt_a2dp_dec->sync = NULL; if (AUDIO_DEC_BT_MIXER_EN) { audio_mixer_ch_close(&bt_a2dp_dec->mix_ch); } else { default_dac.entry.prob_handler = NULL; bt_dec_stream_run_stop(&bt_a2dp_dec->dec.decoder); } audio_dec_slience_entry_free(bt_a2dp_dec); #if SYS_DIGVOL_GROUP_EN sys_digvol_group_ch_close("music_a2dp"); #endif // 先关闭各个节点,最后才close数据流 if (bt_a2dp_dec->stream) { audio_stream_close(bt_a2dp_dec->stream); bt_a2dp_dec->stream = NULL; } app_audio_state_exit(APP_AUDIO_STATE_MUSIC); } /*----------------------------------------------------------------------------*/ /**@brief a2dp解码释放 @param @return @note */ /*----------------------------------------------------------------------------*/ static void a2dp_dec_release() { audio_decoder_task_del_wait(&decode_task, &bt_a2dp_dec->wait); a2dp_drop_frame_stop(); if (bt_a2dp_dec->dec.coding_type == AUDIO_CODING_SBC) { clock_remove(DEC_SBC_CLK); } else if (bt_a2dp_dec->dec.coding_type == AUDIO_CODING_AAC) { clock_remove(DEC_AAC_CLK); } local_irq_disable(); free(bt_a2dp_dec); bt_a2dp_dec = NULL; local_irq_enable(); } /*----------------------------------------------------------------------------*/ /**@brief a2dp解码事件返回 @param *decoder: 解码器句柄 @param argc: 参数个数 @param *argv: 参数 @return @note */ /*----------------------------------------------------------------------------*/ static void a2dp_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv) { switch (argv[0]) { case AUDIO_DEC_EVENT_END: log_i("AUDIO_DEC_EVENT_END\n"); a2dp_dec_close(); break; } } /*----------------------------------------------------------------------------*/ /**@brief a2dp解码数据流激活 @param *p: 私有句柄 @return @note */ /*----------------------------------------------------------------------------*/ static void a2dp_dec_out_stream_resume(void *p) { struct a2dp_dec_hdl *dec = (struct a2dp_dec_hdl *)p; audio_decoder_resume(&dec->dec.decoder); } /*----------------------------------------------------------------------------*/ /**@brief a2dp接受回调 @param @return @note 蓝牙库里面接受到了a2dp音频 */ /*----------------------------------------------------------------------------*/ void a2dp_rx_notice_to_decode(void) { if (bt_a2dp_dec && bt_a2dp_dec->dec.start) { a2dp_decoder_resume_from_bluetooth(&bt_a2dp_dec->dec); } } /*----------------------------------------------------------------------------*/ /**@brief a2dp解码输出到dac时的预处理 @param *entry: 数据流节点 @param *in: 输入数据 @return @note 应用在没有使用mixer情况下传输sync标志 */ /*----------------------------------------------------------------------------*/ static int a2dp_to_dac_probe_handler(struct audio_stream_entry *entry, struct audio_data_frame *in) { if (!in->stop/* && in->data_len*/) { if (bt_a2dp_dec->sync) { in->data_sync = 1; } } return 0; } #if 0 // 解码输出数据流节点数据处理回调示例 static int demo_decoder_data_handler(struct audio_stream_entry *entry, struct audio_data_frame *in, struct audio_data_frame *out) { struct audio_decoder *decoder = container_of(entry, struct audio_decoder, entry); // 自定义数据处理 // ... put_buf(in->data, 16); // 输出到数据流示例。 // 如果不使用audio_stream流程,输出后,需要把实际输出长度更新到decoder->process_len decoder->process_len = 0; audio_stream_run(&decoder->entry, in); int wlen = decoder->process_len; return wlen; } #endif #if 0 // 数据流预处理回调示例 static int demo_stream_mix_prob_handler(struct audio_stream_entry *entry, struct audio_data_frame *in) { // 该函数中如果返回负数,数据流将截止运行,解码会被挂起 // 对数据进行处理,如打印一下数据 /* put_buf(in->data, in->data_len); */ put_buf(in->data, 16); /* memset(in->data, 0, in->data_len); */ return 0; } #endif #if 0 // 保存原来的数据流数据处理 static void *demo_data_handler_save; // 数据流data_handler处理 static int demo_new_data_handler(struct audio_stream_entry *entry, struct audio_data_frame *in, struct audio_data_frame *out) { // 对数据进行处理 put_buf(in->data, 8); // 调用原来的接口输出,这里就可以保存一下是否输出完,就可以做比较多的处理了 int wlen = ((int (*)(struct audio_stream_entry *, struct audio_data_frame *, struct audio_data_frame *))demo_data_handler_save)(entry, in, out); return wlen; } #endif /*----------------------------------------------------------------------------*/ /**@brief 开始a2dp解码 @param @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ static int a2dp_dec_start(void) { int err; struct audio_fmt *fmt; struct a2dp_dec_hdl *dec = bt_a2dp_dec; u8 ch_num = 0; u8 ch_type = 0; if (!bt_a2dp_dec) { return -EINVAL; } log_i("a2dp_dec_start: in\n"); // 打开a2dp解码 err = a2dp_decoder_open(&dec->dec, &decode_task); if (err) { goto __err1; } // 使能事件回调 audio_decoder_set_event_handler(&dec->dec.decoder, a2dp_dec_event_handler, 0); // 获取解码格式 err = audio_decoder_get_fmt(&dec->dec.decoder, &fmt); if (err) { goto __err2; } // 设置输出声道数和声道类型 ch_num = audio_output_channel_num(); ch_type = audio_output_channel_type(); a2dp_decoder_set_output_channel(&dec->dec, ch_num, ch_type); if (AUDIO_DEC_BT_MIXER_EN) { audio_mode_main_dec_open(AUDIO_MODE_MAIN_STATE_DEC_A2DP); // 配置mixer通道参数 audio_mixer_ch_open_head(&dec->mix_ch, &mixer); // 挂载到mixer最前面 audio_mixer_ch_set_src(&dec->mix_ch, 1, 0); audio_mixer_ch_set_no_wait(&dec->mix_ch, 1, 20); // 超时自动丢数 audio_mixer_ch_sample_sync_enable(&dec->mix_ch, 1); // 标志为sync通道 audio_mixer_ch_set_sample_rate(&dec->mix_ch, fmt->sample_rate); } #if AUDIO_SURROUND_CONFIG //环绕音效 dec->surround = surround_open_demo(AEID_MUSIC_SURROUND, ch_type); #endif #if AUDIO_VBASS_CONFIG dec->vbass_prev_gain = audio_gain_open_demo(AEID_MUSIC_VBASS_PREV_GAIN, ch_num); dec->ns_gate = audio_noisegate_open_demo(AEID_MUSIC_NS_GATE, fmt->sample_rate, ch_num); //虚拟低音 dec->vbass = audio_vbass_open_demo(AEID_MUSIC_VBASS, fmt->sample_rate, ch_num); #endif #if TCFG_EQ_ENABLE && TCFG_AUDIO_OUT_EQ_ENABLE dec->high_bass = high_bass_eq_open(fmt->sample_rate, ch_num); dec->hb_drc = high_bass_drc_open(fmt->sample_rate, ch_num); #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE if (dec->hb_drc && dec->hb_drc->run32bit) { dec->hb_convert = convet_data_open(0, 512); } #endif #endif #if TCFG_EQ_ENABLE && TCFG_BT_MUSIC_EQ_ENABLE dec->eq = music_eq_open(fmt->sample_rate, ch_num);// eq #if TCFG_DRC_ENABLE && TCFG_BT_MUSIC_DRC_ENABLE dec->drc = music_drc_open(fmt->sample_rate, ch_num);//drc #endif/*TCFG_BT_MUSIC_DRC_ENABLE*/ #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE if (dec->eq && dec->eq->out_32bit) { dec->convert = convet_data_open(0, 512); } #endif #if defined(MUSIC_EXT_EQ_AFTER_DRC) && MUSIC_EXT_EQ_AFTER_DRC dec->ext_eq = music_ext_eq_open(fmt->sample_rate, ch_num); #endif #if defined(TCFG_DYNAMIC_EQ_ENABLE) && TCFG_DYNAMIC_EQ_ENABLE dec->eq2 = music_eq2_open(fmt->sample_rate, ch_num);// eq dec->dy_eq = audio_dynamic_eq_ctrl_open(AEID_MUSIC_DYNAMIC_EQ, fmt->sample_rate, ch_num);//动态eq dec->convert2 = convet_data_open(0, 512); #endif/*TCFG_DYNAMIC_EQ_ENABLE*/ #if defined(TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE) && TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE dec->gain = audio_gain_open_demo(AEID_MUSIC_GAIN, ch_num); #endif #endif/*TCFG_BT_MUSIC_EQ_ENABLE*/ // sync初始化 if (AUDIO_DEC_BT_MIXER_EN) { dec->sync = a2dp_output_sync_open(fmt->sample_rate, audio_mixer_get_sample_rate(&mixer), ch_num); } else { dec->sync = a2dp_output_sync_open(fmt->sample_rate, fmt->sample_rate, ch_num); } /*使能同步,配置延时时间*/ a2dp_decoder_stream_sync_enable(&dec->dec, dec->sync->context, fmt->sample_rate, CONFIG_A2DP_DELAY_TIME); #if 0 // 获取解码输出数据示例 // 可以重新实现data_handler,在data_handler中再调用数据流输出 // 或者可以查看紧接着dec->dec.decoder.entry之后的数据流预处理数据 dec->dec.decoder.entry.data_handler = demo_decoder_data_handler; #endif #if 0 // 获取节点数据示例1 // 获取传入数据流节点中的数据仅需实现prob_handler接口就可以了 // 该方式仅用于查看节点数据,或者做一些清零之类的简单动作 // 这里以获取传入mix节点的数据为例 dec->mix_ch.entry.prob_handler = demo_stream_mix_prob_handler; #endif #if 0 // 获取节点数据示例2 // 可以用变量保存原来的数据处理接口,然后重新赋值新的数据处理 // 这里以获取mix节点的数据为例 demo_data_handler_save = (void *)dec->mix_ch.entry.data_handler; dec->mix_ch.entry.data_handler = demo_new_data_handler; #endif // 数据流串联 struct audio_stream_entry *entries[16] = {NULL}; u8 entry_cnt = 0; u8 rl_rr_entry_start = 0; entries[entry_cnt++] = &dec->dec.decoder.entry; #if SYS_DIGVOL_GROUP_EN void *dvol_entry = sys_digvol_group_ch_open("music_a2dp", -1, NULL); entries[entry_cnt++] = dvol_entry; #endif // SYS_DIGVOL_GROUP_EN if (dec->sync) { entries[entry_cnt++] = dec->sync->entry; entries[entry_cnt++] = dec->sync->resample_entry; } #if AUDIO_VBASS_CONFIG if (dec->vbass_prev_gain) { entries[entry_cnt++] = &dec->vbass_prev_gain->entry; } if (dec->ns_gate) { entries[entry_cnt++] = &dec->ns_gate->entry; } if (dec->vbass) { entries[entry_cnt++] = &dec->vbass->entry; } #endif #if TCFG_EQ_ENABLE && TCFG_AUDIO_OUT_EQ_ENABLE if (dec->high_bass) { //高低音 entries[entry_cnt++] = &dec->high_bass->entry; } if (dec->hb_drc) { //高低音后drc entries[entry_cnt++] = &dec->hb_drc->entry; #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE if (dec->hb_convert) { entries[entry_cnt++] = &dec->hb_convert->entry; } #endif } #endif rl_rr_entry_start = entry_cnt - 1;//记录eq的上一个节点 #if defined(TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE) && TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE if (dec->gain) { entries[entry_cnt++] = &dec->gain->entry; } #endif #if AUDIO_SURROUND_CONFIG if (dec->surround) { entries[entry_cnt++] = &dec->surround->entry; } #endif #if TCFG_EQ_ENABLE && TCFG_BT_MUSIC_EQ_ENABLE if (dec->eq) { entries[entry_cnt++] = &dec->eq->entry; if (dec->drc) { entries[entry_cnt++] = &dec->drc->entry; } #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE if (dec->convert) { entries[entry_cnt++] = &dec->convert->entry; } #endif #if defined(MUSIC_EXT_EQ_AFTER_DRC) && MUSIC_EXT_EQ_AFTER_DRC if (dec->ext_eq) { entries[entry_cnt++] = &dec->ext_eq->entry; } #endif #if defined(TCFG_DYNAMIC_EQ_ENABLE) && TCFG_DYNAMIC_EQ_ENABLE if (dec->eq2) { entries[entry_cnt++] = &dec->eq2->entry; } if (dec->dy_eq && dec->dy_eq->dy_eq) { entries[entry_cnt++] = &dec->dy_eq->dy_eq->entry; } if (dec->convert2) { entries[entry_cnt++] = &dec->convert2->entry; } #endif } #endif #if TCFG_USER_TWS_ENABLE if (dec->preempted) { dec->preempted = 0; entries[entry_cnt++] = audio_dec_slience_stream_entry(dec, 700); } #endif if (AUDIO_DEC_BT_MIXER_EN) { entries[entry_cnt++] = &dec->mix_ch.entry; } else { default_dac.entry.prob_handler = a2dp_to_dac_probe_handler; entries[entry_cnt++] = &default_dac.entry; } // 创建数据流,把所有节点连接起来 dec->stream = audio_stream_open(dec, a2dp_dec_out_stream_resume); audio_stream_add_list(dec->stream, entries, entry_cnt); // 设置音频输出类型 audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC); log_i("dec->ch:%d, fmt->channel:%d\n", dec->dec.ch, fmt->channel); // 关闭丢数 a2dp_drop_frame_stop(); #if TCFG_USER_TWS_ENABLE if (tws_network_audio_was_started()) { /*a2dp播放中副机加入*/ tws_network_local_audio_start(); a2dp_decoder_join_tws(&dec->dec); } #endif // 开始解码 dec->dec.start = 1; err = audio_decoder_start(&dec->dec.decoder); if (err) { goto __err3; } clock_set_cur(); return 0; __err3: dec->dec.start = 0; #if AUDIO_SURROUND_CONFIG surround_close_demo(dec->surround); #endif #if AUDIO_VBASS_CONFIG audio_gain_close_demo(dec->vbass_prev_gain); audio_noisegate_close_demo(dec->ns_gate); audio_vbass_close_demo(dec->vbass); #endif #if TCFG_EQ_ENABLE && TCFG_AUDIO_OUT_EQ_ENABLE high_bass_eq_close(dec->high_bass); high_bass_drc_close(dec->hb_drc); #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE convet_data_close(dec->hb_convert); #endif #endif #if TCFG_EQ_ENABLE && TCFG_BT_MUSIC_EQ_ENABLE music_eq_close(dec->eq); #if TCFG_DRC_ENABLE && TCFG_BT_MUSIC_DRC_ENABLE music_drc_close(dec->drc); #endif #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE convet_data_close(dec->convert); #endif #if defined(MUSIC_EXT_EQ_AFTER_DRC) && MUSIC_EXT_EQ_AFTER_DRC music_ext_eq_close(dec->ext_eq); #endif #if defined(TCFG_DYNAMIC_EQ_ENABLE) && TCFG_DYNAMIC_EQ_ENABLE music_eq2_close(dec->eq2); audio_dynamic_eq_ctrl_close(dec->dy_eq); convet_data_close(dec->convert2); #endif #if defined(TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE) && TCFG_PHASER_GAIN_AND_CH_SWAP_ENABLE audio_gain_close_demo(dec->gain); #endif #endif if (AUDIO_DEC_BT_MIXER_EN) { audio_mixer_ch_close(&dec->mix_ch); } else { bt_dec_stream_run_stop(&dec->dec.decoder); } if (dec->sync) { a2dp_output_sync_close(dec->sync); dec->sync = NULL; } #if SYS_DIGVOL_GROUP_EN sys_digvol_group_ch_close("music_a2dp"); #endif // SYS_DIGVOL_GROUP_EN // 先关闭各个节点,最后才close数据流 if (dec->stream) { audio_stream_close(dec->stream); dec->stream = NULL; } __err2: a2dp_decoder_close(&dec->dec); __err1: a2dp_dec_release(); return err; } /*----------------------------------------------------------------------------*/ /**@brief a2dp解码资源等待 @param *wait: 句柄 @param event: 事件 @return 0:成功 @note 用于多解码打断处理 */ /*----------------------------------------------------------------------------*/ static int a2dp_wait_res_handler(struct audio_res_wait *wait, int event) { int err = 0; log_i("a2dp_wait_res_handler: %d\n", event); if (event == AUDIO_RES_GET) { err = a2dp_dec_start(); } else if (event == AUDIO_RES_PUT) { if (bt_a2dp_dec->dec.start) { a2dp_audio_res_close(); a2dp_drop_frame_start(); } } return err; } /*----------------------------------------------------------------------------*/ /**@brief 打开a2dp解码 @param media_type: 媒体类型 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int a2dp_dec_open(int media_type) { struct a2dp_dec_hdl *dec; if (bt_a2dp_dec) { return 0; } log_i("a2dp_dec_open: %d\n", media_type); if (a2dp_suspend) { #if (TCFG_USER_TWS_ENABLE) if (tws_api_get_role() == TWS_ROLE_MASTER) #endif//TCFG_USER_TWS_ENABLE { if (drop_a2dp_timer == 0) { drop_a2dp_timer = sys_timer_add(NULL, a2dp_media_clear_packet_before_seqn, 100); } } return 0; } dec = zalloc(sizeof(*dec)); if (!dec) { return -ENOMEM; } switch (media_type) { case A2DP_CODEC_SBC: log_i("a2dp_media_type:SBC"); dec->dec.coding_type = AUDIO_CODING_SBC; clock_add(DEC_SBC_CLK); break; case A2DP_CODEC_MPEG24: log_i("a2dp_media_type:AAC"); dec->dec.coding_type = AUDIO_CODING_AAC; clock_add(DEC_AAC_CLK); break; default: log_i("a2dp_media_type unsupoport:%d", media_type); free(dec); return -EINVAL; } bt_a2dp_dec = dec; dec->wait.priority = 1; // 解码优先级 dec->wait.preemption = 0; // 不使能直接抢断解码 dec->wait.snatch_same_prio = 1; // 可抢断同优先级解码 dec->wait.handler = a2dp_wait_res_handler; audio_decoder_task_add_wait(&decode_task, &dec->wait); if (bt_a2dp_dec && (bt_a2dp_dec->dec.start == 0)) { a2dp_drop_frame_start(); } return 0; } /*----------------------------------------------------------------------------*/ /**@brief 关闭a2dp解码 @param @return 0: 没有a2dp解码 @return 1: 成功 @note */ /*----------------------------------------------------------------------------*/ int a2dp_dec_close(void) { if (drop_a2dp_timer) { sys_timer_del(drop_a2dp_timer); drop_a2dp_timer = 0; } if (!bt_a2dp_dec) { return 0; } bt_a2dp_dec->closing = 1; if (bt_a2dp_dec->dec.start) { a2dp_audio_res_close(); } a2dp_dec_release();/*free bt_a2dp_dec*/ clock_set_cur(); log_i("a2dp_dec_close: exit\n"); return 1; } /*----------------------------------------------------------------------------*/ /**@brief a2dp挂起 @param *p: 私有参数 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int a2dp_tws_dec_suspend(void *p) { r_printf("a2dp_tws_dec_suspend\n"); /*mem_stats();*/ if (a2dp_suspend) { return -EINVAL; } a2dp_suspend = 1; if (bt_a2dp_dec) { a2dp_dec_close(); a2dp_media_clear_packet_before_seqn(0); #if (TCFG_USER_TWS_ENABLE) if (tws_api_get_role() == 0) #endif//TCFG_USER_TWS_ENABLE { drop_a2dp_timer = sys_timer_add(NULL, a2dp_media_clear_packet_before_seqn, 100); } } int err = audio_decoder_fmt_lock(&decode_task, AUDIO_CODING_AAC); if (err) { log_e("AAC_dec_lock_faild\n"); } return err; } /*----------------------------------------------------------------------------*/ /**@brief a2dp挂起激活 @param @return @note */ /*----------------------------------------------------------------------------*/ void a2dp_tws_dec_resume(void) { r_printf("a2dp_tws_dec_resume\n"); if (a2dp_suspend) { a2dp_suspend = 0; if (drop_a2dp_timer) { sys_timer_del(drop_a2dp_timer); drop_a2dp_timer = 0; } audio_decoder_fmt_unlock(&decode_task, AUDIO_CODING_AAC); int type = a2dp_media_get_codec_type(); printf("codec_type: %d\n", type); if (type >= 0) { #if (TCFG_USER_TWS_ENABLE) if (tws_api_get_role() == 0) #endif//TCFG_USER_TWS_ENABLE { a2dp_media_clear_packet_before_seqn(0); } /* a2dp_resume_time = jiffies + msecs_to_jiffies(80); */ a2dp_dec_open(type); } } } #if TCFG_ESCO_PLC /*----------------------------------------------------------------------------*/ /**@brief esco丢包修护初始化 @param @return 丢包修护句柄 @note */ /*----------------------------------------------------------------------------*/ static void *esco_plc_init(void) { void *plc = malloc(PLC_query()); /*buf_size:1040*/ //plc = zalloc_mux(PLC_query()); log_i("PLC_buf:0x%x,size:%d\n", (int)plc, PLC_query()); if (!plc) { return NULL; } int err = PLC_init(plc); if (err) { log_i("PLC_init err:%d", err); free(plc); plc = NULL; } return plc; } /*----------------------------------------------------------------------------*/ /**@brief esco丢包修护关闭 @param *plc: 丢包修护句柄 @return @note */ /*----------------------------------------------------------------------------*/ static void esco_plc_close(void *plc) { free(plc); } /*----------------------------------------------------------------------------*/ /**@brief esco丢包修护运行 @param *data: 数据 @param len: 数据长度 @param repair: 修护标记 @return @note */ /*----------------------------------------------------------------------------*/ static void esco_plc_run(s16 *data, u16 len, u8 repair) { u16 repair_point, tmp_point; s16 *p_in, *p_out; p_in = data; p_out = data; tmp_point = len / 2; #if 0 //debug static u16 repair_cnt = 0; if (repair) { repair_cnt++; y_printf("[E%d]", repair_cnt); } else { repair_cnt = 0; } //log_i("[%d]",point); #endif/*debug*/ while (tmp_point) { repair_point = (tmp_point > PLC_FRAME_LEN) ? PLC_FRAME_LEN : tmp_point; tmp_point = tmp_point - repair_point; PLC_run(p_in, p_out, repair_point, repair); p_in += repair_point; p_out += repair_point; } } #endif /*----------------------------------------------------------------------------*/ /**@brief esco解码输出数据处理 @param *entry: 数据流入口 @param *in: 输入数据 @param *out: 输出数据 @return 处理了多长数据 @note */ /*----------------------------------------------------------------------------*/ static int esco_dec_data_handler(struct audio_stream_entry *entry, struct audio_data_frame *in, struct audio_data_frame *out) { struct audio_decoder *decoder = container_of(entry, struct audio_decoder, entry); struct esco_decoder *esco_dec = container_of(decoder, struct esco_decoder, decoder); struct esco_dec_hdl *dec = container_of(esco_dec, struct esco_dec_hdl, dec); if (dec->remain == 0) { if (dec->tws_mute_en) { memset(in->data, 0, in->data_len); } #if TCFG_ESCO_PLC if (dec->plc && out && out->data) { esco_plc_run(in->data, in->data_len, *(u8 *)out->data); } #endif/*TCFG_ESCO_PLC*/ #ifdef TCFG_ESCO_NOISEGATE if (dec->noisegate) { run_noisegate(dec->noisegate, in->data, in->data, in->data_len); } #endif /*TCFG_ESCO_NOISEGATE*/ } out->no_subsequent = 1; struct audio_data_frame out_frame; memcpy(&out_frame, in, sizeof(struct audio_data_frame)); audio_stream_run(&decoder->entry, &out_frame); int wlen = decoder->process_len; /* int wlen = esco_decoder_output_handler(&dec->dec, in); */ if (in->data_len != wlen) { dec->remain = 1; } else { dec->remain = 0; } return wlen; } /*----------------------------------------------------------------------------*/ /**@brief esco解码释放 @param @return @note */ /*----------------------------------------------------------------------------*/ void esco_dec_release() { audio_decoder_task_del_wait(&decode_task, &bt_esco_dec->wait); if (bt_esco_dec->dec.coding_type == AUDIO_CODING_MSBC) { clock_remove(DEC_MSBC_CLK); } else if (bt_esco_dec->dec.coding_type == AUDIO_CODING_CVSD) { clock_remove(DEC_CVSD_CLK); } local_irq_disable(); free(bt_esco_dec); bt_esco_dec = NULL; local_irq_enable(); } /*----------------------------------------------------------------------------*/ /**@brief esco解码事件返回 @param *decoder: 解码器句柄 @param argc: 参数个数 @param *argv: 参数 @return @note */ /*----------------------------------------------------------------------------*/ static void esco_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv) { switch (argv[0]) { case AUDIO_DEC_EVENT_END: log_i("AUDIO_DEC_EVENT_END\n"); esco_dec_close(); break; } } static int esco_to_dac_probe_handler(struct audio_stream_entry *entry, struct audio_data_frame *in) { if (!in->stop) { if (bt_esco_dec->sync) { in->data_sync = 1; } } return 0; } /*----------------------------------------------------------------------------*/ /**@brief esco解码close @param @return @note */ /*----------------------------------------------------------------------------*/ extern void audio_aec_ref_src_close(); static void esco_audio_res_close(void) { /* *先关闭aec,里面有复用到enc的buff,再关闭enc, *如果没有buf复用,则没有先后顺序要求。 */ if (!bt_esco_dec->dec.start) { return ; } bt_esco_dec->dec.start = 0; bt_esco_dec->dec.enc_start = 0; audio_aec_close(); esco_enc_close(); esco_decoder_close(&bt_esco_dec->dec); #if TCFG_EQ_ENABLE &&TCFG_PHONE_EQ_ENABLE esco_eq_close(bt_esco_dec->eq); #if TCFG_DRC_ENABLE && ESCO_DRC_EN esco_drc_close(bt_esco_dec->drc); #else audio_drc_code_movable_load(); #endif #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE convet_data_close(bt_esco_dec->convert); #endif #endif spectrum_switch_demo(1);//打开频谱计算 channel_switch_close(&bt_esco_dec->ch_switch); esco_output_sync_close(bt_esco_dec->sync); bt_esco_dec->sync = NULL; if (AUDIO_DEC_BT_MIXER_EN) { audio_mixer_ch_close(&bt_esco_dec->mix_ch); } else { default_dac.entry.prob_handler = NULL; bt_dec_stream_run_stop(&bt_esco_dec->dec.decoder); } #if TCFG_ESCO_PLC if (bt_esco_dec->plc) { esco_plc_close(bt_esco_dec->plc); bt_esco_dec->plc = NULL; } #endif/*TCFG_ESCO_PLC*/ #if TCFG_ESCO_NOISEGATE if (bt_esco_dec->noisegate) { close_noisegate(bt_esco_dec->noisegate); bt_esco_dec->noisegate = NULL; } #endif /*TCFG_ESCO_NOISEGATE*/ #if SYS_DIGVOL_GROUP_EN sys_digvol_group_ch_close("call_esco"); #endif // SYS_DIGVOL_GROUP_EN // 先关闭各个节点,最后才close数据流 if (bt_esco_dec->stream) { audio_stream_close(bt_esco_dec->stream); bt_esco_dec->stream = NULL; } #if TCFG_ESCO_USE_SPEC_MIX_LEN /*恢复mix_buf的长度*/ audio_mixer_set_output_buf(&mixer, mix_buff, AUDIO_MIXER_LEN); #endif /*TCFG_ESCO_USE_SPEC_MIX_LEN*/ app_audio_state_exit(APP_AUDIO_STATE_CALL); bt_esco_dec->dec.start = 0; } /*----------------------------------------------------------------------------*/ /**@brief esco解码数据流激活 @param *p: 私有句柄 @return @note */ /*----------------------------------------------------------------------------*/ static void esco_dec_out_stream_resume(void *p) { struct esco_dec_hdl *dec = (struct esco_dec_hdl *)p; audio_decoder_resume(&dec->dec.decoder); } /*----------------------------------------------------------------------------*/ /**@brief esco接受回调 @param @return @note 蓝牙库里面接受到了esco音频 */ /*----------------------------------------------------------------------------*/ void esco_rx_notice_to_decode(void) { if (bt_esco_dec && bt_esco_dec->dec.start) { /* audio_decoder_resume(&bt_esco_dec->dec.decoder); */ if (bt_esco_dec->dec.wait_resume) { bt_esco_dec->dec.wait_resume = 0; audio_decoder_resume(&bt_esco_dec->dec.decoder); } } } /*----------------------------------------------------------------------------*/ /**@brief 开始esco解码 @param @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ static int esco_dec_start() { int err; struct esco_dec_hdl *dec = bt_esco_dec; if (!bt_esco_dec) { return -EINVAL; } // 打开esco解码 err = esco_decoder_open(&dec->dec, &decode_task); if (err) { goto __err1; } // 使能事件回调 audio_decoder_set_event_handler(&dec->dec.decoder, esco_dec_event_handler, 0); #if TCFG_ESCO_USE_SPEC_MIX_LEN /* *(1)bt_esco_dec输出是120或者240,所以通话的时候,修改mix_buff的长度,提高效率 *(2)其他大部分时候解码输出是512的倍数,通话结束,恢复mix_buff的长度,提高效率 */ audio_mixer_set_output_buf(&mixer, mix_buff, AUDIO_MIXER_LEN / 240 * 240); #endif /*TCFG_ESCO_USE_SPEC_MIX_LEN*/ if (AUDIO_DEC_BT_MIXER_EN) { audio_mode_main_dec_open(AUDIO_MODE_MAIN_STATE_DEC_ESCO); // 配置mixer通道参数 audio_mixer_ch_open_head(&dec->mix_ch, &mixer); // 挂载到mixer最前面 audio_mixer_ch_set_src(&dec->mix_ch, 1, 0); audio_mixer_ch_set_no_wait(&dec->mix_ch, 1, 10); // 超时自动丢数 audio_mixer_ch_sample_sync_enable(&dec->mix_ch, 1); audio_mixer_ch_set_sample_rate(&dec->mix_ch, dec->dec.sample_rate); audio_mixer_ch_set_aud_ch_out(&dec->mix_ch, 0, BIT(0) | BIT(1)); } else { if (dec->dec.ch_num != dec->dec.out_ch_num) { u8 out_ch_type = AUDIO_CH_DIFF; if (dec->dec.out_ch_num == 4) { out_ch_type = AUDIO_CH_QUAD; } else if (dec->dec.out_ch_num == 2) { out_ch_type = AUDIO_CH_LR; } dec->ch_switch = channel_switch_open(out_ch_type, 512); } } // eq、drc音效 #if TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE u8 bit_wide = 0; if (ESCO_DRC_EN) { bit_wide = 1; } dec->eq = esco_eq_open(dec->dec.sample_rate, dec->dec.ch_num, bit_wide);// eq #if TCFG_DRC_ENABLE && ESCO_DRC_EN dec->drc = esco_drc_open(dec->dec.sample_rate, dec->dec.ch_num, bit_wide);//drc #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE if (bit_wide) { dec->convert = convet_data_open(0, 512); } #endif/*TCFG_DRC_ENABLE*/ #else audio_drc_code_movable_unload(); #endif/*TCFG_DRC_ENABLE && ESCO_DRC_EN*/ #endif/*TCFG_PHONE_EQ_ENABLE*/ spectrum_switch_demo(0);//关闭频谱计算 dec->dec.decoder.entry.data_handler = esco_dec_data_handler; // sync初始化 if (AUDIO_DEC_BT_MIXER_EN) { dec->sync = esco_output_sync_open(dec->dec.sample_rate, audio_mixer_get_sample_rate(&mixer), dec->dec.ch_num); } else { dec->sync = esco_output_sync_open(dec->dec.sample_rate, dec->dec.sample_rate, dec->dec.ch_num); } /*使能同步,配置延时时间*/ esco_decoder_stream_sync_enable(&dec->dec, dec->sync->context, dec->dec.sample_rate, 25); // 数据流串联 struct audio_stream_entry *entries[16] = {NULL}; u8 entry_cnt = 0; entries[entry_cnt++] = &dec->dec.decoder.entry; if (dec->sync) { entries[entry_cnt++] = dec->sync->entry; } #if TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE if (dec->eq) { entries[entry_cnt++] = &dec->eq->entry; if (dec->drc) { entries[entry_cnt++] = &dec->drc->entry; } #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE if (dec->convert) { entries[entry_cnt++] = &dec->convert->entry; } #endif } #endif if (dec->sync) { entries[entry_cnt++] = dec->sync->resample_entry; } #if SYS_DIGVOL_GROUP_EN void *dvol_entry = sys_digvol_group_ch_open("call_esco", -1, NULL); entries[entry_cnt++] = dvol_entry; #endif // SYS_DIGVOL_GROUP_EN if (dec->ch_switch) { entries[entry_cnt++] = &dec->ch_switch->entry; } if (AUDIO_DEC_BT_MIXER_EN) { entries[entry_cnt++] = &dec->mix_ch.entry; } else { default_dac.entry.prob_handler = esco_to_dac_probe_handler; entries[entry_cnt++] = &default_dac.entry; } // 创建数据流,把所有节点连接起来 dec->stream = audio_stream_open(dec, esco_dec_out_stream_resume); audio_stream_add_list(dec->stream, entries, entry_cnt); // 设置音频输出类型 audio_output_set_start_volume(APP_AUDIO_STATE_CALL); #if TCFG_ESCO_PLC // 丢包修护 dec->plc = esco_plc_init(); #endif #if TCFG_ESCO_NOISEGATE NOISEGATE_PARM esco_noisegate_parm = { .attackTime = 300, .releaseTime = 5, .threshold = LIMITER_NOISE_GATE, .low_th_gain = LIMITER_NOISE_GAIN, .sampleRate = dec->dec.sample_rate, .channel = 1, }; dec->noisegate = open_noisegate(&esco_noisegate_parm, 0, 0); #endif /*TCFG_ESCO_NOISEGATE*/ #if TCFG_USER_TWS_ENABLE if (tws_network_audio_was_started()) { tws_network_local_audio_start(); esco_decoder_join_tws(&dec->dec); } #endif lmp_private_esco_suspend_resume(2); // 开始解码 dec->dec.start = 1; err = audio_decoder_start(&dec->dec.decoder); if (err) { goto __err3; } dec->dec.frame_get = 0; err = audio_aec_init(dec->dec.sample_rate); if (err) { log_i("audio_aec_init failed:%d", err); //goto __err3; } err = esco_enc_open(dec->dec.coding_type, dec->dec.esco_len); if (err) { log_i("audio_enc_open failed:%d", err); //goto __err3; } dec->dec.enc_start = 1; clock_set_cur(); return 0; __err3: dec->dec.start = 0; #if TCFG_EQ_ENABLE &&TCFG_PHONE_EQ_ENABLE esco_eq_close(dec->eq); #if TCFG_DRC_ENABLE && ESCO_DRC_EN esco_drc_close(dec->drc); #else audio_drc_code_movable_load(); #endif #if defined(TCFG_DRC_ENABLE) && TCFG_DRC_ENABLE convet_data_close(dec->convert); #endif #endif spectrum_switch_demo(1);//打开频谱计算 channel_switch_close(&dec->ch_switch); if (AUDIO_DEC_BT_MIXER_EN) { audio_mixer_ch_close(&dec->mix_ch); } else { bt_dec_stream_run_stop(&dec->dec.decoder); } if (dec->sync) { esco_output_sync_close(dec->sync); dec->sync = NULL; } #if SYS_DIGVOL_GROUP_EN sys_digvol_group_ch_close("call_esco"); #endif // SYS_DIGVOL_GROUP_EN if (dec->stream) { audio_stream_close(dec->stream); dec->stream = NULL; } __err2: esco_decoder_close(&dec->dec); __err1: esco_dec_release(); return err; } /*----------------------------------------------------------------------------*/ /**@brief esco解码资源等待 @param *wait: 句柄 @param event: 事件 @return 0:成功 @note 用于多解码打断处理 */ /*----------------------------------------------------------------------------*/ static int esco_wait_res_handler(struct audio_res_wait *wait, int event) { int err = 0; log_d("esco_wait_res_handler %d\n", event); if (event == AUDIO_RES_GET) { err = esco_dec_start(); } else if (event == AUDIO_RES_PUT) { if (bt_esco_dec->dec.start) { lmp_private_esco_suspend_resume(1); esco_audio_res_close(); } } return err; } /*----------------------------------------------------------------------------*/ /**@brief 打开esco解码 @param *param: 媒体信息 @param mutw: 静音 @return 0: 成功 @note */ /*----------------------------------------------------------------------------*/ int esco_dec_open(void *param, u8 mute) { int err; struct esco_dec_hdl *dec; u32 esco_param = *(u32 *)param; int esco_len = esco_param >> 16; int codec_type = esco_param & 0x000000ff; log_i("esco_dec_open, type=%d,len=%d\n", codec_type, esco_len); dec = zalloc(sizeof(*dec)); if (!dec) { return -ENOMEM; } #if TCFG_DEC2TWS_ENABLE localtws_media_disable(); #endif bt_esco_dec = dec; dec->tws_mute_en = mute; dec->dec.esco_len = esco_len; dec->dec.out_ch_num = audio_output_channel_num(); if (codec_type == 3) { dec->dec.coding_type = AUDIO_CODING_MSBC; dec->dec.sample_rate = 16000; dec->dec.ch_num = 1; clock_add(DEC_MSBC_CLK); } else if (codec_type == 2) { dec->dec.coding_type = AUDIO_CODING_CVSD; dec->dec.sample_rate = 8000; dec->dec.ch_num = 1; clock_add(DEC_CVSD_CLK); } dec->wait.priority = 2; // 解码优先级 dec->wait.preemption = 0; // 不使能直接抢断解码 dec->wait.snatch_same_prio = 1; // 可抢断同优先级解码 dec->wait.handler = esco_wait_res_handler; err = audio_decoder_task_add_wait(&decode_task, &dec->wait); if (bt_esco_dec && (bt_esco_dec->dec.start == 0)) { lmp_private_esco_suspend_resume(1); } #if AUDIO_OUTPUT_AUTOMUTE extern void mix_out_automute_skip(u8 skip); mix_out_automute_skip(1); #endif return err; } /*----------------------------------------------------------------------------*/ /**@brief 关闭esco解码 @param : @return @note */ /*----------------------------------------------------------------------------*/ void esco_dec_close() { if (!bt_esco_dec) { return; } esco_audio_res_close(); esco_dec_release(); log_i("esco_dec_close: exit\n"); #if AUDIO_OUTPUT_AUTOMUTE extern void mix_out_automute_skip(u8 skip); mix_out_automute_skip(0); #endif clock_set_cur(); #if TCFG_DEC2TWS_ENABLE localtws_media_enable(); #endif } /*----------------------------------------------------------------------------*/ /**@brief 蓝牙音频正在运行 @param @return 1: 正在运行 @note */ /*----------------------------------------------------------------------------*/ u8 bt_audio_is_running(void) { return (bt_a2dp_dec || bt_esco_dec); } /*----------------------------------------------------------------------------*/ /**@brief 蓝牙播放正在运行 @param @return 1: 正在运行 @note */ /*----------------------------------------------------------------------------*/ u8 bt_media_is_running(void) { return bt_a2dp_dec != NULL; } /*----------------------------------------------------------------------------*/ /**@brief 蓝牙电话正在运行 @param @return 1: 正在运行 @note */ /*----------------------------------------------------------------------------*/ u8 bt_phone_dec_is_running() { return bt_esco_dec != NULL; } /*----------------------------------------------------------------------------*/ /**@brief 蓝牙解码idle判断 @param @return 1: idle @return 0: busy @note */ /*----------------------------------------------------------------------------*/ static u8 bt_dec_idle_query() { if (bt_audio_is_running()) { return 0; } return 1; } REGISTER_LP_TARGET(bt_dec_lp_target) = { .name = "bt_dec", .is_idle = bt_dec_idle_query, };