/***********************************Jieli tech************************************************ File : localtws_dec.c By : Huxi brief: Email: huxi@zh-jieli.com date : 2020-07 ********************************************************************************************/ #include "asm/includes.h" #include "media/includes.h" #include "system/includes.h" #include "classic/tws_api.h" #include "classic/tws_local_media_sync.h" #include "localtws/localtws.h" #include "clock_cfg.h" #include "app_config.h" #include "audio_config.h" #include "audio_dec.h" #include "media/audio_eq_drc_apply.h" #include "audio_effect/audio_eq_drc_demo.h" #if TCFG_DEC2TWS_ENABLE #define LOCALTWS_LOG_ENABLE #ifdef LOCALTWS_LOG_ENABLE #define LOCALTWS_LOG log_i //y_printf #define LOCALTWS_LOG_CHAR putchar #else #define LOCALTWS_LOG(...) #define LOCALTWS_LOG_CHAR(...) #endif ////////////////////////////////////////////////////////////////////////////// // struct localtws_dec_hdl { struct audio_stream *stream; // 音频流 struct localtws_decoder local_dec; // local解码句柄 struct audio_res_wait wait; // 资源等待句柄 struct audio_eq *eq; //eq drc句柄 struct audio_drc *drc; // drc句柄 struct convert_data *convert; struct audio_mixer_ch mix_ch; // 叠加句柄 u32 id; // 唯一标识符,随机值 u32 media_value; // localtws媒体信息 struct audio_wireless_sync *sync; }; static struct localtws_dec_hdl *localtws_dec = NULL; ////////////////////////////////////////////////////////////////////////////// // extern struct audio_decoder_task decode_task; #if TCFG_DEC2TWS_TASK_ENABLE extern struct audio_decoder_task localtws_decode_task; #define LOCALTWS_TASK localtws_decode_task #else /*TCFG_DEC2TWS_TASK_ENABLE*/ #define LOCALTWS_TASK decode_task #endif /*TCFG_DEC2TWS_TASK_ENABLE*/ extern void tws_api_local_media_trans_clear_no_ready(void); extern int tws_api_local_media_trans_get_total_buffer_size(void); extern void bt_drop_a2dp_frame_start(void); extern int a2dp_media_clear_packet(); extern struct audio_wireless_sync *audio_localtws_sync_open(int sample_rate, int output_sample_rate, u8 channels); extern void audio_localtws_sync_close(struct audio_wireless_sync *localtws_sync); extern u8 is_tws_active_device(void); extern void sys_auto_shut_down_disable(void); /////////////////////////////////////////////////////////////////////////////////// struct local_dec_type { u32 type; u32 clk; }; const struct local_dec_type local_dec_clk_tb[] = { {AUDIO_CODING_SBC, DEC_TWS_SBC_CLK}, {AUDIO_CODING_MP3, DEC_MP3_CLK}, {AUDIO_CODING_WMA, DEC_WMA_CLK}, {AUDIO_CODING_M4A, DEC_M4A_CLK}, }; /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /**@brief localtws解码时钟添加 @param type: 解码类型 @return @note */ /*----------------------------------------------------------------------------*/ static void local_dec_clock_add(u32 type) { LOCALTWS_LOG("local_dec_clock_add : 0x%x \n", type); int i = 0; for (i = 0; i < ARRAY_SIZE(local_dec_clk_tb); i++) { if (type == local_dec_clk_tb[i].type) { clock_add(local_dec_clk_tb[i].clk); return; } } } /*----------------------------------------------------------------------------*/ /**@brief localtws解码时钟移除 @param type: 解码类型 @return @note */ /*----------------------------------------------------------------------------*/ static void local_dec_clock_remove(u32 type) { LOCALTWS_LOG("local_dec_clock_remove : 0x%x \n", type); int i = 0; for (i = 0; i < ARRAY_SIZE(local_dec_clk_tb); i++) { if (type == local_dec_clk_tb[i].type) { clock_remove(local_dec_clk_tb[i].clk); return; } } } /*----------------------------------------------------------------------------*/ /**@brief localtws激活前级解码/编码 @param @return @note 弱函数重定义 */ /*----------------------------------------------------------------------------*/ #if 0 void localtws_decoder_resume_pre(void) { audio_stream_resume(&g_localtws.push.entry); #ifdef TCFG_PCM_ENC2TWS_ENABLE localtws_enc_resume(); #endif } #endif /*----------------------------------------------------------------------------*/ /**@brief localtws解码输出重启 @param ms: 重启静音时长 @return @note 弱函数重定义 */ /*----------------------------------------------------------------------------*/ void localtws_decoder_output_reset(u32 ms) { app_audio_output_reset(ms); } /*----------------------------------------------------------------------------*/ /**@brief localtws解码激活 @param @return @note */ /*----------------------------------------------------------------------------*/ void localtws_dec_resume(void) { if (localtws_dec && localtws_dec->local_dec.status) { audio_decoder_resume(&localtws_dec->local_dec.decoder); } } /*----------------------------------------------------------------------------*/ /**@brief localtws已经打开 @param @return true: 打开 @return false: 没有打开 @note */ /*----------------------------------------------------------------------------*/ u8 localtws_dec_is_open(void) { if (localtws_dec) { return true; } return false; } /*----------------------------------------------------------------------------*/ /**@brief localtws抛弃数据 @param @return true: 抛弃数据 @return false: 不抛弃 @note */ /*----------------------------------------------------------------------------*/ int localtws_media_dat_abandon(void) { if ((localtws_dec) && (localtws_dec->local_dec.status) && (localtws_dec->local_dec.tmp_pause)) { // 从机,暂停,抛弃中间数据包 return true; } return false; } /*----------------------------------------------------------------------------*/ /**@brief localtws解码释放 @param @return @note */ /*----------------------------------------------------------------------------*/ static void localtws_dec_release() { audio_decoder_task_del_wait(&LOCALTWS_TASK, &localtws_dec->wait); clock_remove(DEC_TWS_SBC_CLK); local_irq_disable(); free(localtws_dec); localtws_dec = NULL; g_localtws.tws_send_pause = 0; local_irq_enable(); } /*----------------------------------------------------------------------------*/ /**@brief localtws解码事件回调 @param *decoder: 解码器句柄 @param argc: 参数个数 @param *argv: 参数 @note */ /*----------------------------------------------------------------------------*/ static void localtws_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv) { switch (argv[0]) { case AUDIO_DEC_EVENT_END: LOCALTWS_LOG("AUDIO_DEC_EVENT_END\n"); localtws_dec_close(1); //audio_decoder_resume_all(&LOCALTWS_TASK); break; } } /*----------------------------------------------------------------------------*/ /**@brief localtws解码数据流激活 @param *p: 私有句柄 @return @note */ /*----------------------------------------------------------------------------*/ static void localtws_dec_out_stream_resume(void *p) { struct localtws_dec_hdl *dec = p; audio_decoder_resume(&dec->local_dec.decoder); } /*----------------------------------------------------------------------------*/ /**@brief localtws解码开始 @param @return 0:成功 @note */ /*----------------------------------------------------------------------------*/ static int localtws_dec_start() { int err; struct localtws_dec_hdl *dec = localtws_dec; if (!dec) { return -EINVAL; } struct audio_fmt fmt = {0}; localtws_media_get_info((u8 *)&dec->media_value, &fmt); dec->local_dec.dec_type = fmt.coding_type; dec->local_dec.sample_rate = fmt.sample_rate; dec->local_dec.ch_num = fmt.channel; LOCALTWS_LOG("localtws_dec_start: in, type:0x%x \n", dec->local_dec.dec_type); LOCALTWS_LOG("sr:%d, ch:%d, outch:%d \n", dec->local_dec.sample_rate, dec->local_dec.ch_num, dec->local_dec.output_ch_num); // 打开file解码器 err = localtws_decoder_open(&dec->local_dec, &LOCALTWS_TASK); if (err) { goto __err1; } audio_decoder_set_event_handler(&dec->local_dec.decoder, localtws_dec_event_handler, dec->id); audio_mode_main_dec_open(AUDIO_MODE_MAIN_STATE_DEC_LOCALTWS); // 设置叠加功能 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->local_dec.sample_rate); dec->sync = audio_localtws_sync_open(dec->local_dec.sample_rate, audio_mixer_get_sample_rate(&mixer), dec->local_dec.output_ch_num); localtws_decoder_stream_sync_enable(&dec->local_dec, dec->sync->context, 200, is_tws_active_device); if (dec->local_dec.dec_type != AUDIO_CODING_SBC) { #if TCFG_EQ_ENABLE && TCFG_MUSIC_MODE_EQ_ENABLE dec->eq = music_eq_open(dec->local_dec.sample_rate, dec->local_dec.output_ch_num);// eq #if TCFG_DRC_ENABLE && TCFG_MUSIC_MODE_DRC_ENABLE dec->drc = music_drc_open(dec->local_dec.sample_rate, dec->local_dec.output_ch_num);//drc #endif/*TCFG_MUSIC_MODE_DRC_ENABLE*/ if (dec->eq && dec->eq->out_32bit) { dec->convert = convet_data_open(0, 512); } #endif } // 数据流串联 struct audio_stream_entry *entries[8] = {NULL}; u8 entry_cnt = 0; entries[entry_cnt++] = &dec->local_dec.decoder.entry; if (dec->sync) { entries[entry_cnt++] = dec->sync->entry; } if (dec->eq) { entries[entry_cnt++] = &dec->eq->entry; if (dec->drc) { entries[entry_cnt++] = &dec->drc->entry; } if (dec->convert) { entries[entry_cnt++] = &dec->convert->entry; } } if (dec->sync) { entries[entry_cnt++] = dec->sync->resample_entry; } entries[entry_cnt++] = &dec->mix_ch.entry; dec->stream = audio_stream_open(dec, localtws_dec_out_stream_resume); audio_stream_add_list(dec->stream, entries, entry_cnt); audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC); dec->local_dec.status = 1; if (is_tws_active_device()) { /*audio_decoder_set_run_max(&dec->local_dec.decoder, 10);*/ } err = audio_decoder_start(&dec->local_dec.decoder); if (err) { goto __err3; } localtws_drop_frame_stop(); bt_drop_a2dp_frame_start(); local_dec_clock_add(dec->local_dec.decoder.dec_ops->coding_type); clock_set_cur(); return 0; __err3: dec->local_dec.status = 0; #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 convet_data_close(dec->convert); #endif audio_mixer_ch_close(&dec->mix_ch); if (dec->stream) { audio_stream_close(dec->stream); dec->stream = NULL; } localtws_decoder_close(&dec->local_dec); __err1: localtws_dec_release(); return err; } static void localtws_dec_res_put(struct localtws_dec_hdl *dec) { if (!dec->local_dec.status) { return; } os_mutex_pend(&g_localtws.mutex, 0); g_localtws.drop_frame_start = 1; dec->local_dec.status = 0; localtws_decoder_close(&dec->local_dec); #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 convet_data_close(dec->convert); #endif if (dec->sync) { audio_localtws_sync_close(dec->sync); dec->sync = NULL; } audio_mixer_ch_close(&dec->mix_ch); if (dec->stream) { audio_stream_close(dec->stream); dec->stream = NULL; } local_dec_clock_remove(dec->local_dec.decoder.dec_ops->coding_type); /* g_localtws.media_value = 0; */ if (g_localtws.tmrout) { sys_hi_timeout_del(g_localtws.tmrout); g_localtws.tmrout = 0; } tws_api_local_media_trans_clear(); localtws_drop_frame_start(); os_mutex_post(&g_localtws.mutex); } /*----------------------------------------------------------------------------*/ /**@brief localtws解码资源等待 @param *wait: 句柄 @param event: 事件 @return 0:成功 @note 用于多解码打断处理 */ /*----------------------------------------------------------------------------*/ static int localtws_dec_wait_res_handler(struct audio_res_wait *wait, int event) { int err = 0; struct localtws_dec_hdl *dec = localtws_dec; #if 0 if (event == AUDIO_RES_GET) { if (dec->local_dec.status == 0) { tws_api_local_media_set_limit_size(LOCALTWS_MEDIA_BUF_LIMIT_LEN); err = localtws_dec_start(); } else if (dec->local_dec.tmp_pause) { tws_api_local_media_set_limit_size(LOCALTWS_MEDIA_BUF_LIMIT_LEN); localtws_drop_frame_stop(); dec->local_dec.tmp_pause = 0; /* audio_mixer_ch_open(&dec->mix_ch, &mixer); */ audio_output_set_start_volume(APP_AUDIO_STATE_MUSIC); /*audio_output_start(dec->src_out_sr, 1);*/ if (dec->local_dec.status) { err = audio_decoder_start(&dec->local_dec.decoder); } } } else if (event == AUDIO_RES_PUT) { /* LOCALTWS_LOG("localtws AUDIO_RES_PUT\n"); */ if (dec->local_dec.status) { dec->local_dec.tmp_pause = 1; err = audio_decoder_pause(&dec->local_dec.decoder); os_time_dly(2); // 先暂停再清数据,避免清了数据后dec还在output tws_api_local_media_trans_clear(); localtws_drop_frame_start(); /* audio_mixer_ch_close(&dec->mix_ch); */ } } #else y_printf("%s,%d, evt:%d \n", __func__, __LINE__, event); if (event == AUDIO_RES_GET) { tws_api_local_media_set_limit_size(LOCALTWS_MEDIA_BUF_LIMIT_LEN); err = localtws_dec_start(); localtws_decoder_resume_pre(); } else if (event == AUDIO_RES_PUT) { if (dec->local_dec.status) { localtws_dec_res_put(dec); } } #endif return err; } /*----------------------------------------------------------------------------*/ /**@brief 打开localtws解码 @param : @return @note */ /*----------------------------------------------------------------------------*/ int localtws_dec_open(u32 value) { if (localtws_dec && (localtws_dec->media_value != value)) { localtws_dec_close(0); } os_mutex_pend(&g_localtws.mutex, 0); if (!localtws_dec) { localtws_dec_close(0); localtws_dec = zalloc(sizeof(struct localtws_dec_hdl)); ASSERT(localtws_dec); } else { os_mutex_post(&g_localtws.mutex); return 0; } int err; struct localtws_dec_hdl *dec = localtws_dec; LOCALTWS_LOG(" ****** localtws_dec_open: in, \n"); sys_auto_shut_down_disable(); if (!dec) { os_mutex_post(&g_localtws.mutex); return -EPERM; } #if 1 a2dp_dec_close(); esco_dec_close(); g_localtws.drop_frame_start = 0; #endif dec->id = rand32(); dec->media_value = value; dec->local_dec.ch_type = AUDIO_CH_MAX; dec->local_dec.output_ch_num = audio_output_channel_num(); dec->local_dec.output_ch_type = audio_output_channel_type(); dec->wait.priority = 1; #if DEC_MIX_ENABLE dec->wait.preemption = 0; dec->wait.protect = 1; #else dec->wait.preemption = 1; #endif//DEC_MIX_ENABLE dec->wait.handler = localtws_dec_wait_res_handler; err = audio_decoder_task_add_wait(&LOCALTWS_TASK, &dec->wait); os_mutex_post(&g_localtws.mutex); return err; } /*----------------------------------------------------------------------------*/ /**@brief 关闭localtws解码 @param drop_frame_start: 是否中止传输 @return 0:成功 @note */ /*----------------------------------------------------------------------------*/ int localtws_dec_close(u8 drop_frame_start) { os_mutex_pend(&g_localtws.mutex, 0); /* LOCALTWS_LOG("localtws_dec_close start\n"); */ if (!localtws_dec) { os_mutex_post(&g_localtws.mutex); return 0; } if (drop_frame_start) { g_localtws.drop_frame_start = 1; // 关闭过程中可能刚好会有数据过来 } if (localtws_dec->local_dec.status) { localtws_dec->local_dec.status = 0; localtws_decoder_close(&localtws_dec->local_dec); #if TCFG_EQ_ENABLE &&TCFG_BT_MUSIC_EQ_ENABLE music_eq_close(localtws_dec->eq); #if TCFG_DRC_ENABLE && TCFG_BT_MUSIC_DRC_ENABLE music_drc_close(localtws_dec->drc); #endif convet_data_close(localtws_dec->convert); #endif audio_mixer_ch_close(&localtws_dec->mix_ch); if (localtws_dec->sync) { audio_localtws_sync_close(localtws_dec->sync); localtws_dec->sync = NULL; } if (localtws_dec->stream) { audio_stream_close(localtws_dec->stream); localtws_dec->stream = NULL; } local_dec_clock_remove(localtws_dec->local_dec.decoder.dec_ops->coding_type); } /* g_localtws.media_value = 0; */ if (g_localtws.tmrout) { sys_hi_timeout_del(g_localtws.tmrout); g_localtws.tmrout = 0; } localtws_dec_release(); tws_api_local_media_trans_clear(); if (drop_frame_start) { g_localtws.drop_frame_start = 1; localtws_drop_frame_start(); } else { localtws_drop_frame_stop(); g_localtws.drop_frame_start = 0; } clock_set_cur(); LOCALTWS_LOG("***** localtws_dec_close: exit\n"); os_mutex_post(&g_localtws.mutex); return 1; } /*----------------------------------------------------------------------------*/ /**@brief localtws暂停 @param : @return @note */ /*----------------------------------------------------------------------------*/ void localtws_dec_pause(void) { g_localtws.tws_send_pause = 1; #ifdef TCFG_PCM_ENC2TWS_ENABLE localtws_enc_clear(); #endif localtws_media_send_pause(100); g_localtws.tws_send_pause = 2; } /*----------------------------------------------------------------------------*/ /**@brief localtws已经开始解码 @param @return true: 已经开始解码 @return false: 没有开始解码 @note */ /*----------------------------------------------------------------------------*/ int localtws_dec_out_is_start(void) { if ((!localtws_dec) || (!localtws_dec->local_dec.status)) { return false; } if (localtws_dec->local_dec.read_en) { return true; } return false; } /*----------------------------------------------------------------------------*/ /**@brief localtws解码idle判断 @param @return 1: idle @return 0: busy @note */ /*----------------------------------------------------------------------------*/ static u8 localtws_dec_idle_query() { if (localtws_dec) { return 0; } return 1; } REGISTER_LP_TARGET(localtws_dec_lp_target) = { .name = "local_dec", .is_idle = localtws_dec_idle_query, }; #endif /*(defined(TCFG_DEC2TWS_ENABLE) && (TCFG_DEC2TWS_ENABLE))*/