KT24-1110_65E-HA-651B/cpu/br25/audio_enc/audio_enc_file.c
2024-11-10 18:44:17 +08:00

589 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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