#ifdef SUPPORT_MS_EXTENSIONS #pragma bss_seg(".pc_spk_file.data.bss") #pragma data_seg(".pc_spk_file.data") #pragma const_seg(".pc_spk_file.text.const") #pragma code_seg(".pc_spk_file.text") #endif #include "source_node.h" #include "media/audio_splicing.h" #include "audio_config.h" #include "jlstream.h" #include "pc_spk_file.h" #include "app_config.h" #include "effects/effects_adj.h" #include "gpio_config.h" #include "sync/audio_clk_sync.h" #include "clock_manager/clock_manager.h" #include "spinlock.h" #include "circular_buf.h" #include "pc_spk_player.h" #include "uac_stream.h" #if (LEA_BIG_CTRLER_TX_EN || LEA_BIG_CTRLER_RX_EN) #include "le_broadcast.h" #include "app_le_broadcast.h" #endif #if (TCFG_LE_AUDIO_APP_CONFIG & (LE_AUDIO_AURACAST_SOURCE_EN | LE_AUDIO_AURACAST_SINK_EN)) #include "app_le_auracast.h" #endif #define LOG_TAG_CONST USB #define LOG_TAG "[pcspk]" #define LOG_ERROR_ENABLE #define LOG_DEBUG_ENABLE /* #define LOG_INFO_ENABLE */ /* #define LOG_DUMP_ENABLE */ #define LOG_CLI_ENABLE #include "debug.h" #if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE /* #define PC_SPK_CACHE_BUF_LEN (1024 * 2) */ //足够缓存20ms的数据 #define PC_SPK_CACHE_BUF_LEN ((SPK_AUDIO_RATE/1000) * 4 * 20) /* PC SPK 在线检测 */ #define PC_SPK_ONLINE_DET_EN 1 #define PC_SPK_ONLINE_DET_TIME 3 //50->20 #define SPK_PUSH_FRAME_NUM 5 //SPK一次push的帧数,单位:uac rx中断间隔 struct pc_spk_file_hdl { void *source_node; struct stream_node *node; struct stream_snode *snode; cbuffer_t spk_cache_cbuffer; #if PC_SPK_ONLINE_DET_EN u32 irq_cnt; //进中断++,用来给定时器判断是否中断没有起 u16 det_timer_id; #endif int sr; u8 *cache_buf; u8 start; u8 data_run; u32 timestamp; }; static struct pc_spk_file_hdl *pc_spk = NULL; struct pc_spk_fmt_t { u8 init; u8 channel; u8 bit; u32 sample_rate; }; struct pc_spk_fmt_t pc_spk_fmt = { .init = 0, .channel = SPK_CHANNEL, .bit = SPK_AUDIO_RES, .sample_rate = SPK_AUDIO_RATE, }; static DEFINE_SPINLOCK(pc_spk_lock); void pc_spk_data_isr_cb(void *buf, u32 len) { struct pc_spk_file_hdl *hdl = pc_spk; struct stream_frame *frame = NULL; int wlen = 0; if (!hdl) { #if TCFG_KBOX_1T3_MODE_EN if (pc_spk_player_runing() == 0) { //打开播放器 pcspk_open_player_by_taskq(); } #else #if (LEA_BIG_CTRLER_TX_EN || LEA_BIG_CTRLER_RX_EN) if (!get_broadcast_role()) { if (pc_spk_player_runing() == 0) { //打开播放器 pcspk_open_player_by_taskq(); } } else { pc_mode_broadcast_deal_by_taskq(LE_AUDIO_MUSIC_START); } #elif (TCFG_LE_AUDIO_APP_CONFIG & (LE_AUDIO_AURACAST_SOURCE_EN | LE_AUDIO_AURACAST_SINK_EN)) if (!get_auracast_role()) { if (pc_spk_player_runing() == 0) { //打开播放器 pcspk_open_player_by_taskq(); } } else { pc_mode_broadcast_deal_by_taskq(LE_AUDIO_MUSIC_START); } #else if (pc_spk_player_runing() == 0) { //打开播放器 pcspk_open_player_by_taskq(); } #endif #endif return; } if (!hdl->start || !len) { //增加0长帧的过滤,避免引起后续节点的写异常 return; } struct stream_node *source_node = hdl->source_node; if (!hdl->cache_buf) { int cache_buf_len = len * SPK_PUSH_FRAME_NUM * 4; //4块输出buf //申请cbuffer hdl->cache_buf = zalloc(cache_buf_len); if (hdl->cache_buf) { cbuf_init(&hdl->spk_cache_cbuffer, hdl->cache_buf, cache_buf_len); } } if (cbuf_get_data_len(&hdl->spk_cache_cbuffer) == 0) { hdl->timestamp = audio_jiffies_usec(); } #if PC_SPK_ONLINE_DET_EN hdl->irq_cnt++; #endif //1ms 起一次中断,一次长度192, 中断太快,需缓存 wlen = cbuf_write(&hdl->spk_cache_cbuffer, buf, len); if (wlen != len) { /*putchar('W');*/ } u32 cache_len = cbuf_get_data_len(&hdl->spk_cache_cbuffer); if (cache_len >= len * SPK_PUSH_FRAME_NUM) { frame = source_plug_get_output_frame(source_node, cache_len); if (!frame) { return; } frame->len = cache_len; #if 1 frame->flags = FRAME_FLAG_TIMESTAMP_ENABLE | FRAME_FLAG_PERIOD_SAMPLE | FRAME_FLAG_UPDATE_TIMESTAMP; frame->timestamp = hdl->timestamp * TIMESTAMP_US_DENOMINATOR; #else frame->flags = FRAME_FLAG_SYS_TIMESTAMP_ENABLE; frame->timestamp = hdl->timestamp; #endif cbuf_read(&hdl->spk_cache_cbuffer, frame->data, frame->len); source_plug_put_output_frame(source_node, frame); hdl->data_run = 1; } } /* 定时器检测 pcspk 在线 */ static void pcspk_det_timer_cb(void *priv) { struct pc_spk_file_hdl *hdl = (struct pc_spk_file_hdl *)priv; if (hdl) { if (hdl->start) { if (hdl->irq_cnt) { hdl->irq_cnt = 0; } else { if (hdl->data_run) { //已经往后面推数据突然中断没有起的情况 hdl->data_run = 0; log_debug(">>>>>>> PCSPK LOST CONNECT <<<<<<<"); #if (LEA_BIG_CTRLER_TX_EN || LEA_BIG_CTRLER_RX_EN) if (get_broadcast_role() == 1) { //广播(发送端) log_debug(">>[PC] spk lost audio stream, broadcast audio need suspend!\n"); pc_mode_broadcast_deal_by_taskq(LE_AUDIO_MUSIC_STOP); } else { pcspk_close_player_by_taskq(); } #elif (TCFG_LE_AUDIO_APP_CONFIG & (LE_AUDIO_AURACAST_SOURCE_EN | LE_AUDIO_AURACAST_SINK_EN)) if (get_auracast_role() == 1) { //广播(发送端) log_debug(">>[PC] spk lost audio stream, broadcast audio need suspend!\n"); pc_mode_broadcast_deal_by_taskq(LE_AUDIO_MUSIC_STOP); } else { pcspk_close_player_by_taskq(); } #else pcspk_close_player_by_taskq(); #endif } } } } } /* * 申请 pc_spk_file 结构体内存空间 */ static void *pc_spk_file_init(void *source_node, struct stream_node *node) { struct pc_spk_file_hdl *hdl = NULL; if (pc_spk != NULL) { hdl = pc_spk; } else { hdl = zalloc(sizeof(*hdl)); } if (!hdl) { log_error("%s, %d, alloc memory failed!\n", __func__, __LINE__); return NULL; } node->type |= NODE_TYPE_IRQ; hdl->source_node = source_node; hdl->node = node; pc_spk = hdl; return hdl; } static int pc_spk_ioc_get_fmt(struct pc_spk_file_hdl *hdl, struct stream_fmt *fmt) { fmt->coding_type = AUDIO_CODING_PCM; if (pc_spk_fmt.channel == 2) { fmt->channel_mode = AUDIO_CH_LR; } else { fmt->channel_mode = AUDIO_CH_L; } fmt->sample_rate = pc_spk_fmt.sample_rate; fmt->bit_wide = (pc_spk_fmt.bit == 24) ? 1 : 0; fmt->pcm_24bit_type = (pc_spk_fmt.bit == 24) ? PCM_24BIT_DATA_3BYTE : PCM_24BIT_DATA_4BYTE; //log_debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> fmt->bit_wide : %d\n", fmt->bit_wide); return 0; } static int pc_spk_ioc_set_fmt(struct pc_spk_file_hdl *hdl, struct stream_fmt *fmt) { return -EINVAL; } //打开pcspk 在线检测定时器 static void pcspk_open_det_timer(void) { #if PC_SPK_ONLINE_DET_EN struct pc_spk_file_hdl *hdl = pc_spk; //申请定时器 if (hdl) { if (!hdl->det_timer_id) { hdl->det_timer_id = usr_timer_add(hdl, pcspk_det_timer_cb, PC_SPK_ONLINE_DET_TIME, 0); } } #endif } //关闭 pcspk 在线检测定时器 static void pcspk_close_det_timer(void) { #if PC_SPK_ONLINE_DET_EN struct pc_spk_file_hdl *hdl = pc_spk; //申请定时器 if (hdl) { if (hdl->det_timer_id) { usr_timer_del(hdl->det_timer_id); hdl->det_timer_id = 0; } } #endif } #if 1 static int pc_spk_ioctl(void *_hdl, int cmd, int arg) { u32 i = 0; int ret = 0; struct pc_spk_file_hdl *hdl = (struct pc_spk_file_hdl *)_hdl; switch (cmd) { case NODE_IOC_GET_FMT: pc_spk_ioc_get_fmt(hdl, (struct stream_fmt *)arg); break; case NODE_IOC_SET_FMT: ret = pc_spk_ioc_set_fmt(hdl, (struct stream_fmt *)arg); break; case NODE_IOC_SET_PRIV_FMT: ret = pc_spk_ioc_set_fmt(hdl, (struct stream_fmt *)arg); break; case NODE_IOC_START: if (hdl->start == 0) { pcspk_open_det_timer(); hdl->data_run = 0; hdl->start = 1; } break; case NODE_IOC_SUSPEND: case NODE_IOC_STOP: if (hdl->start) { hdl->start = 0; } break; } return ret; } #endif static void pc_spk_release(void *_hdl) { struct pc_spk_file_hdl *hdl = (struct pc_spk_file_hdl *)_hdl; spin_lock(&pc_spk_lock); if (!hdl) { hdl = pc_spk; if (!hdl) { spin_unlock(&pc_spk_lock); return; } } pcspk_close_det_timer(); free(hdl->cache_buf); hdl->cache_buf = NULL; free(hdl); hdl = NULL; pc_spk = NULL; spin_unlock(&pc_spk_lock); } u8 is_pc_spk_file_start(void) { struct pc_spk_file_hdl *hdl = pc_spk; if (!hdl) { return 0; } return (hdl->start); } // 设置pc mic 的数据格式,传入0不设置 void pc_spk_set_fmt(u8 channel, u8 bit, u32 sample_rate) { log_info("----------- Call %s, bit:%d, sr:%d\n", __func__, bit, sample_rate); pc_spk_fmt.init = 1; if (channel != 0) { pc_spk_fmt.channel = channel; } if (bit != 0) { pc_spk_fmt.bit = bit; } if (sample_rate != 0) { pc_spk_fmt.sample_rate = sample_rate; } } u32 pc_spk_get_fmt_sample_rate(void) { return pc_spk_fmt.sample_rate; } REGISTER_SOURCE_NODE_PLUG(pc_spk_file_plug) = { .uuid = NODE_UUID_PC_SPK, .init = pc_spk_file_init, .ioctl = pc_spk_ioctl, .release = pc_spk_release, }; #endif