#include "asm/includes.h" #include "media/includes.h" #include "system/includes.h" #include "encode/encode_write.h" #include "asm/audio_src.h" #include "audio_enc.h" #include "app_main.h" #include "app_action.h" #include "clock_cfg.h" #include "dev_manager.h" #include "btstack/btstack_task.h" #include "btstack/avctp_user.h" #if TCFG_ENC_WRITE_FILE_ENABLE #define PCM_ENC2FILE_PCM_LEN (3 * 1024) #define PCM_ENC2FILE_FILE_LEN (8 * 1024) #define PCM_ENC2FILE_PCM_LEN_OVERLAY (2 * 1024) #define PCM_ENC2FILE_FILE_LEN_OVERLAY (3 * 1024) #define WAV_FILE_HEAD_LEN 90 #define PCM2FILE_ENC_BUF_COUNT 1 //wav录音头部信息定时更新时间设置, 单位ms #define UPDATA_WAV_HEAD_TIME (5000) extern struct audio_encoder_task *encode_task; struct pcm2file_enc_hdl { struct audio_encoder encoder; s16 output_frame[1152 / 2]; //align 4Bytes int pcm_frame[64]; //align 4Bytes u8 file_head_frame[128]; u8 file_head_len; /* u8 pcm_buf[PCM_ENC2FILE_PCM_LEN]; */ u8 *pcm_buf; cbuffer_t pcm_cbuf; int out_file_frame[512 / 4]; /* u8 out_file_buf[PCM_ENC2FILE_FILE_LEN]; */ u8 *out_file_buf; cbuffer_t out_file_cbuf; void *whdl; OS_SEM sem_wfile; OS_MUTEX mutex; volatile u32 status : 2; volatile u32 enc_err : 1; volatile u32 encoding : 1; volatile u32 write_head_busy : 1; volatile u32 input_busy : 1; u32 lost; #if PCM2FILE_ENC_BUF_COUNT u16 pcm_buf_max; u16 out_file_max; #endif u32 head_update_tick; }; static volatile u8 pcm2file_used_overlay = 0; #if (RECORDER_MIX_EN) struct pcm2file_enc_hdl pcm2file_enc_overlay_handle sec(.enc_file_mem); u8 pcm_buf_overlay[PCM_ENC2FILE_PCM_LEN_OVERLAY] sec(.enc_file_mem); u8 out_file_buf_overlay[PCM_ENC2FILE_FILE_LEN_OVERLAY] sec(.enc_file_mem); #endif/*RECORDER_MIX_EN*/ static void pcm2file_enc_suspend(struct pcm2file_enc_hdl *enc) { audio_encoder_suspend(&enc->encoder, 0); } static void pcm2file_enc_resume(struct pcm2file_enc_hdl *enc) { audio_encoder_resume(&enc->encoder); } static void pcm2file_wfile_resume(struct pcm2file_enc_hdl *enc) { os_sem_set(&enc->sem_wfile, 0); os_sem_post(&enc->sem_wfile); enc_write_file_resume(enc->whdl); } void enc_change_status(void *hdl) { struct pcm2file_enc_hdl *pcm2file = hdl; if (pcm2file->status == 1) { pcm2file->status = 2; } else if (pcm2file->status == 2) { pcm2file->status = 1; } } // 写pcm数据 int pcm2file_enc_write_pcm(void *priv, s16 *data, int len) { struct pcm2file_enc_hdl *enc = (struct pcm2file_enc_hdl *)priv; if (!enc || enc->enc_err || enc->status == 0) { return 0; } u16 wlen = 0; enc->input_busy = 1; if (enc->status == 1) { wlen = cbuf_write(&enc->pcm_cbuf, data, len); if (!wlen) { enc->lost++; putchar('~'); } else { /* putchar('G');//__G__ */ } #if PCM2FILE_ENC_BUF_COUNT if (enc->pcm_buf_max < enc->pcm_cbuf.data_len) { enc->pcm_buf_max = enc->pcm_cbuf.data_len; } #endif /* printf("wl:%d ", wlen); */ // 激活录音编码器 if (cbuf_get_data_size(&enc->pcm_cbuf) >= 128) { pcm2file_enc_resume(enc); } } else if (enc->status == 2) { // 挂起录音编码器 pcm2file_enc_suspend(enc); } enc->input_busy = 0; return wlen; } // 编码器获取数据 static int pcm2file_enc_pcm_get(struct audio_encoder *encoder, s16 **frame, u16 frame_len) { int rlen = 0; int dlen = 0; if (encoder == NULL) { r_printf("encoder NULL"); } struct pcm2file_enc_hdl *enc = container_of(encoder, struct pcm2file_enc_hdl, encoder); if (enc == NULL) { r_printf("enc NULL"); } /* printf("l:%d", frame_len); */ if (!enc->status) { return 0; } if (enc->enc_err) { return 0; } dlen = cbuf_get_data_len(&enc->pcm_cbuf); if (dlen < frame_len) { /* putchar('T');//__T__ */ return 0; } rlen = cbuf_read(&enc->pcm_cbuf, enc->pcm_frame, frame_len); *frame = enc->pcm_frame; return rlen; } static void pcm2file_enc_pcm_put(struct audio_encoder *encoder, s16 *frame) { } static const struct audio_enc_input pcm2file_enc_input = { .fget = pcm2file_enc_pcm_get, .fput = pcm2file_enc_pcm_put, }; static int pcm2file_enc_probe_handler(struct audio_encoder *encoder) { return 0; } // 编码器输出 static int pcm2file_enc_output_handler(struct audio_encoder *encoder, u8 *frame, int len) { struct pcm2file_enc_hdl *enc = container_of(encoder, struct pcm2file_enc_hdl, encoder); int wlen = cbuf_write(&enc->out_file_cbuf, frame, len); #if PCM2FILE_ENC_BUF_COUNT if (enc->out_file_max < enc->out_file_cbuf.data_len) { enc->out_file_max = enc->out_file_cbuf.data_len; } #endif if (cbuf_get_data_len(&enc->out_file_cbuf) >= (512 * 2)) { pcm2file_wfile_resume(enc); } /* if (wlen != len) { */ /* printf("X"); */ /* } */ /* if (!enc->status) { */ /* return 0; */ /* } */ if (enc->enc_err) { return 0; } return wlen; } static void pcm2file_enc_get_head_info(struct audio_encoder *encoder) { struct pcm2file_enc_hdl *pcm2file = container_of(encoder, struct pcm2file_enc_hdl, encoder); u16 len = 0; u8 *ptr = (u8 *)audio_encoder_ioctrl(&pcm2file->encoder, 2, AUDIO_ENCODER_IOCTRL_CMD_GET_HEAD_INFO, &len); /* printf("%s, ptr = %x, len = %d\n", __FUNCTION__, ptr, len); */ if (ptr) { if (len > sizeof(pcm2file->file_head_frame)) { printf("file_head_frame buf not enough\n"); return; } memcpy(pcm2file->file_head_frame, ptr, len); /* put_buf(pcm2file->file_head_frame, len); */ pcm2file->file_head_len = len; } } static int pcm2file_enc_close_handler(struct audio_encoder *encoder) { //做一些编码关闭前的操作, 例如:adpcm写头操作 pcm2file_enc_get_head_info(encoder);//写编码头部信息 return 0; } const static struct audio_enc_handler pcm2file_enc_handler = { .enc_probe = pcm2file_enc_probe_handler, .enc_output = pcm2file_enc_output_handler, .enc_close = pcm2file_enc_close_handler, }; static int enc_wfile_set_head(void *hdl, char **head) { struct pcm2file_enc_hdl *enc = hdl; /* struct enc_write_test *tst = hdl; */ *head = enc->file_head_frame; return enc->file_head_len; } static void updata_wav_head_info(struct audio_encoder *encoder, void *priv) { int len; char *head; int cur_write_pos; struct audio_fmt *enc_fmt; struct pcm2file_enc_hdl *enc = (struct pcm2file_enc_hdl *)priv; /* extern int audio_encoder_get_fmt(struct audio_encoder * enc, struct audio_fmt **fmt); */ audio_encoder_get_fmt(encoder, &enc_fmt); if ((enc_fmt->coding_type != AUDIO_CODING_WAV) && (enc_fmt->coding_type != AUDIO_CODING_G726) ) { return; } cur_write_pos = fpos(get_wfil_file(enc->whdl)); pcm2file_enc_get_head_info(encoder); len = enc_wfile_set_head(get_wfil_head_hdl(enc->whdl), &head); if (len) { fseek(get_wfil_file(enc->whdl), 0, SEEK_SET); fwrite(get_wfil_file(enc->whdl), head, len); } fseek(get_wfil_file(enc->whdl), cur_write_pos, SEEK_SET); //printf("update head!!\n"); } static void pcm2file_enc_w_evt(void *hdl, int evt, int parm) { struct pcm2file_enc_hdl *enc = hdl; printf("evt: %d ", evt); if (evt == ENC_WRITE_FILE_EVT_WRITE_ERR) { enc->enc_err = 1; pcm2file_wfile_resume(enc); pcm2file_enc_resume(enc); audio_encoder_stop(&enc->encoder); } else if (evt == ENC_WRITE_FILE_EVT_FILE_CLOSE) { printf("sclust: %d ", parm); } } static int pcm2file_enc_w_get(void *hdl, s16 **frame, u16 frame_len) { int rlen; struct pcm2file_enc_hdl *enc = hdl; os_sem_set(&enc->sem_wfile, 0); /* printf("r:%d", frame_len); */ do { rlen = cbuf_read(&enc->out_file_cbuf, enc->out_file_frame, frame_len); if (rlen == frame_len) { break; } if (!enc->status) { rlen = cbuf_get_data_len(&enc->out_file_cbuf); rlen = cbuf_read(&enc->out_file_cbuf, enc->out_file_frame, rlen); break; } if (enc->enc_err) { return 0; } if (cbuf_get_data_size(&enc->pcm_cbuf) >= 128) { pcm2file_enc_resume(enc); } os_sem_pend(&enc->sem_wfile, 2); } while (1); *frame = enc->out_file_frame; return rlen; } static void pcm2file_enc_w_put(void *hdl, s16 *frame) { #if TCFG_NOR_FS_ENABLE || FLASH_INSIDE_REC_ENABLE return ; #endif struct pcm2file_enc_hdl *enc = (struct pcm2file_enc_hdl *)hdl; u32 cur_sys_time = timer_get_ms(); os_mutex_pend(&enc->mutex, 0); if (enc->status == 0) { os_mutex_post(&enc->mutex); return ; } if (cur_sys_time - enc->head_update_tick >= UPDATA_WAV_HEAD_TIME) { updata_wav_head_info(&(enc->encoder), enc); enc->head_update_tick = cur_sys_time; } os_mutex_post(&enc->mutex); } const struct audio_enc_write_input pcm2file_enc_w_input = { .get = pcm2file_enc_w_get, .put = pcm2file_enc_w_put, }; void pcm2file_enc_write_file_set_limit(void *hdl, u32 cut_size, u32 limit_size) { struct pcm2file_enc_hdl *pcm2file = hdl; enc_write_file_set_limit(pcm2file->whdl, cut_size, limit_size); } void pcm2file_enc_set_evt_handler(void *hdl, void (*handler)(struct audio_encoder *, int, int *), u32 maigc) { struct pcm2file_enc_hdl *pcm2file = hdl; audio_encoder_set_event_handler(&pcm2file->encoder, handler, maigc); } void pcm2file_enc_start(void *hdl) { struct pcm2file_enc_hdl *pcm2file = hdl; pcm2file->status = 1; audio_encoder_start(&pcm2file->encoder); enc_write_file_start(pcm2file->whdl); //记录录音启动时的tick, 后面定时更新头部信息用到 pcm2file->head_update_tick = timer_get_ms(); } int pcm2file_enc_get_time(void *hdl) { struct pcm2file_enc_hdl *pcm2file = hdl; if (!pcm2file) { return 0; } os_mutex_pend(&pcm2file->mutex, 0); if (pcm2file->status == 0) { os_mutex_post(&pcm2file->mutex); return 0; } int ret = audio_encoder_ioctrl(&pcm2file->encoder, 1, AUDIO_ENCODER_IOCTRL_CMD_GET_TIME); os_mutex_post(&pcm2file->mutex); return ret; } void *pcm2file_enc_open(struct audio_fmt *pfmt, char *logo, char *folder, char *filename) { int err; struct pcm2file_enc_hdl *pcm2file = NULL; char *temp_filename = NULL; u32 out_file_buf_size = 0; u32 pcm_buf_size = 0; if (pfmt->coding_type != AUDIO_CODING_MP3 && pfmt->coding_type != AUDIO_CODING_WAV && pfmt->coding_type != AUDIO_CODING_G726) { return NULL; } ///创建录音编码线程 audio_encoder_task_open(); #if (RECORDER_MIX_EN) if (BT_CALL_HANGUP != get_call_status()) { printf("[%s], used overlay!!\n", __FUNCTION__); pcm2file_used_overlay = 1; pcm2file = &pcm2file_enc_overlay_handle; memset(&pcm2file_enc_overlay_handle, 0, sizeof(struct pcm2file_enc_hdl)); pcm2file->pcm_buf = pcm_buf_overlay; pcm2file->out_file_buf = out_file_buf_overlay; pcm_buf_size = PCM_ENC2FILE_PCM_LEN_OVERLAY; out_file_buf_size = PCM_ENC2FILE_FILE_LEN_OVERLAY; memset(pcm2file->pcm_buf, 0, PCM_ENC2FILE_PCM_LEN_OVERLAY); memset(pcm2file->out_file_buf, 0, PCM_ENC2FILE_FILE_LEN_OVERLAY); } else #endif/*RECORDER_MIX_EN*/ { printf("[%s], used malloc!!\n", __FUNCTION__); pcm2file_used_overlay = 0; pcm2file = zalloc(sizeof(struct pcm2file_enc_hdl)); if (!pcm2file) { goto __out; } pcm_buf_size = PCM_ENC2FILE_PCM_LEN; out_file_buf_size = PCM_ENC2FILE_FILE_LEN; pcm2file->pcm_buf = zalloc(pcm_buf_size); if (pcm2file->pcm_buf == NULL) { goto __out; } pcm2file->out_file_buf = zalloc(out_file_buf_size); if (pcm2file->out_file_buf == NULL) { goto __out; } } os_sem_create(&pcm2file->sem_wfile, 0); os_mutex_create(&pcm2file->mutex); cbuf_init(&pcm2file->out_file_cbuf, pcm2file->out_file_buf, out_file_buf_size); temp_filename = zalloc(strlen(filename) + 5); if (temp_filename == NULL) { goto __out; } if (pfmt->coding_type == AUDIO_CODING_MP3) { strcat(temp_filename, filename); strcat(temp_filename, ".mp3"); } else if (pfmt->coding_type == AUDIO_CODING_WAV || pfmt->coding_type == AUDIO_CODING_G726) { strcat(temp_filename, filename); strcat(temp_filename, ".wav"); } pcm2file->whdl = enc_write_file_open(logo, folder, temp_filename); free(temp_filename); if (!pcm2file->whdl) { goto __out; } enc_write_file_set_evt_handler(pcm2file->whdl, pcm2file_enc_w_evt, pcm2file); enc_write_file_set_input(pcm2file->whdl, &pcm2file_enc_w_input, pcm2file, sizeof(pcm2file->out_file_frame)); if ((pfmt->coding_type == AUDIO_CODING_WAV) || (pfmt->coding_type == AUDIO_CODING_G726)) { pcm2file->file_head_len = WAV_FILE_HEAD_LEN; enc_write_file_set_head_handler(pcm2file->whdl, enc_wfile_set_head, pcm2file); } if (pfmt->coding_type == AUDIO_CODING_MP3) { if ((pfmt->sample_rate < 16000) && (pfmt->bit_rate > 64)) { pfmt->bit_rate = 64; } } cbuf_init(&pcm2file->pcm_cbuf, pcm2file->pcm_buf, pcm_buf_size); audio_encoder_open(&pcm2file->encoder, &pcm2file_enc_input, encode_task); audio_encoder_set_handler(&pcm2file->encoder, &pcm2file_enc_handler); audio_encoder_set_fmt(&pcm2file->encoder, pfmt); audio_encoder_set_output_buffs(&pcm2file->encoder, pcm2file->output_frame, sizeof(pcm2file->output_frame), 1); pcm2file->input_busy = 0; return pcm2file; __out: if (pcm2file_used_overlay == 0) { if (pcm2file->pcm_buf) { free(pcm2file->pcm_buf); } if (pcm2file->out_file_buf) { free(pcm2file->out_file_buf); } if (pcm2file) { free(pcm2file); } } return NULL; } void pcm2file_enc_close(void **hdl) { struct pcm2file_enc_hdl *pcm2file = *hdl; if (!pcm2file) { return; } os_mutex_pend(&pcm2file->mutex, 0); pcm2file->status = 0; os_mutex_post(&pcm2file->mutex); while (pcm2file->input_busy) { os_time_dly(1); } audio_encoder_close(&pcm2file->encoder); enc_write_file_stop(pcm2file->whdl, 1000); enc_write_file_close(pcm2file->whdl); printf("pcm2file_enc_close, lost:%d ", pcm2file->lost); if (pcm2file_used_overlay == 0) { #if PCM2FILE_ENC_BUF_COUNT printf("pcm_buf_max:%d,%d/100; out_file_max:%d,%d/100 ", pcm2file->pcm_buf_max, pcm2file->pcm_buf_max * 100 / PCM_ENC2FILE_PCM_LEN, pcm2file->out_file_max, pcm2file->out_file_max * 100 / PCM_ENC2FILE_FILE_LEN ); #endif printf("[%s], used malloc, need free!!\n", __FUNCTION__); if (pcm2file->pcm_buf) { free(pcm2file->pcm_buf); } if (pcm2file->out_file_buf) { free(pcm2file->out_file_buf); } OS_ENTER_CRITICAL(); free(pcm2file); *hdl = NULL; OS_EXIT_CRITICAL(); } else { #if PCM2FILE_ENC_BUF_COUNT printf("pcm_buf_max:%d,%d/100; out_file_max:%d,%d/100 ", pcm2file->pcm_buf_max, pcm2file->pcm_buf_max * 100 / PCM_ENC2FILE_PCM_LEN_OVERLAY, pcm2file->out_file_max, pcm2file->out_file_max * 100 / PCM_ENC2FILE_FILE_LEN_OVERLAY ); #endif printf("[%s], used overlay, noneed free!!\n", __FUNCTION__); } audio_encoder_task_close(); /* if (encode_task) { */ /* audio_encoder_task_del(encode_task); */ /* free(encode_task); */ /* encode_task = NULL; */ /* } */ } int pcm2file_enc_is_work(void *hdl) { struct pcm2file_enc_hdl *enc = hdl; if (!enc || !enc->status || enc->enc_err) { return false; } return true; } int get_pcm2file_enc_file_len(void *hdl) { struct pcm2file_enc_hdl *pcm2file = hdl; return get_enc_file_len(pcm2file->whdl); } struct audio_encoder *get_pcm2file_encoder_hdl(void *hdl) { struct pcm2file_enc_hdl *enc = hdl; return &(enc->encoder); } #endif