KT25-0812_82A-UART/cpu/br25/audio_enc/audio_sbc_codec.c
2025-08-12 18:09:23 +08:00

555 lines
15 KiB
C
Raw Permalink 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 "aec_user.h"
#include "asm/audio_src.h"
#include "audio_enc.h"
#include "app_main.h"
#include "btstack/avctp_user.h"
#include "audio_digital_vol.h"
#include "audio_sbc_codec.h"
#include "clock_cfg.h"
extern struct audio_encoder_task *encode_task;
//static struct audio_encoder_task *encode_task = NULL;
#define SBC_ENC_WRITING BIT(1)
#define SBC_ENC_START BIT(2)
#define SBC_ENC_WAKEUP_SEND BIT(3) /*减少唤醒问题*/
#define SBC_ENC_PCM_MUTE_DATA BIT(4) /*发一包静音数据*/
static u8 sbc_buf_flag = 0;
#define ESCO_ADC_BUF_NUM 2
#define ESCO_ADC_IRQ_POINTS 256
#define ESCO_ADC_BUFS_SIZE (ESCO_ADC_BUF_NUM * ESCO_ADC_IRQ_POINTS)
#define SBC_USE_MIC_CHANNEL 0
#define SBC_ENC_PACK_ENABLE 0 /*sbc数据包封装*/
#define SBC_ENC_IN_SIZE 512
#define SBC_ENC_OUT_SIZE 256
#define SBC_ENC_IN_CBUF_SIZE (SBC_ENC_IN_SIZE * 8)
#define SBC_ENC_OUT_CBUF_SIZE (SBC_ENC_OUT_SIZE * 8)
struct sbc_enc_hdl {
struct audio_encoder encoder;
OS_SEM pcm_frame_sem;
u8 output_frame[SBC_ENC_OUT_SIZE];
u8 pcm_frame[SBC_ENC_IN_SIZE];
u8 frame_size;
u8 backup_digital_vol;
cbuffer_t output_cbuf;
u8 out_cbuf_buf[SBC_ENC_OUT_CBUF_SIZE];
cbuffer_t pcm_in_cbuf;/*要注意要跟DAC的buf大小一致*/
u8 in_cbuf_buf[SBC_ENC_IN_CBUF_SIZE];
#if SBC_ENC_PACK_ENABLE
u16 cp_type;
u16 packet_head_sn;
#endif
int mute_data_send_timer;
#if SBC_USE_MIC_CHANNEL
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
s16 adc_buf[ESCO_ADC_BUFS_SIZE]; //align 4Bytes
#endif
/* dvol_handle *dvol; */
};
static struct sbc_enc_hdl *sbc_enc = NULL;
__attribute__((weak))
void audio_sbc_enc_inbuf_resume(void)
{
;
}
__attribute__((weak))
void audio_sbc_enc_open_exit(void)
{
;
}
__attribute__((weak))
void audio_sbc_enc_close_enter(void)
{
;
}
static void sbc_send_mute_data()
{
sbc_buf_flag |= SBC_ENC_PCM_MUTE_DATA;
audio_encoder_resume(&sbc_enc->encoder);
}
static int sbc_enc_pcm_get(struct audio_encoder *encoder, s16 **frame, u16 frame_len)
{
u8 read_flag = 1;
int pcm_len = 0;
if (encoder == NULL) {
r_printf("encoder NULL");
}
struct sbc_enc_hdl *enc = container_of(encoder, struct sbc_enc_hdl, encoder);
if (enc == NULL) {
r_printf("enc NULL");
}
if (cbuf_get_data_size(&enc->pcm_in_cbuf) < SBC_ENC_IN_SIZE) {
if (!(sbc_buf_flag & SBC_ENC_PCM_MUTE_DATA)) {
return 0;
} else {
read_flag = 0;
}
}
if (read_flag) {
pcm_len = cbuf_read(&enc->pcm_in_cbuf, enc->pcm_frame, SBC_ENC_IN_SIZE);
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)
audio_stream_resume(&sbc_emitter.entry);
#endif
} else {
putchar('h');
memset(enc->pcm_frame, 0, SBC_ENC_IN_SIZE);
pcm_len = SBC_ENC_IN_SIZE;
}
if (pcm_len != SBC_ENC_IN_SIZE) {
putchar('L');
}
*frame = enc->pcm_frame;
return pcm_len;
}
static void sbc_enc_pcm_put(struct audio_encoder *encoder, s16 *frame)
{
}
static const struct audio_enc_input sbc_enc_input = {
.fget = sbc_enc_pcm_get,
.fput = sbc_enc_pcm_put,
};
static int sbc_enc_probe_handler(struct audio_encoder *encoder)
{
return 0;
}
#if SBC_ENC_PACK_ENABLE
/*
struct Media_Playload_Header {
u8 Version: 2;
u8 Padding: 1;
u8 Extension: 1;
u8 CSRC_Count: 4;
u8 Marker: 1;
u8 PayloadType: 7;
u16 SequenceNumber;
u32 TimeStamp;
u32 SSRC;
};
SBC_FRAME_SUM defined within sbc_packet_head_buf used for Media Playload parameter:Number of Frames
*/
#define SBC_PACKET_HEADER_LEN (14) /*包头Max Length*/
#define SBC_FRAME_SUM (4) /*一包多少帧*/
static unsigned char sbc_packet_head_buf[SBC_PACKET_HEADER_LEN] = {
0x80, 0x60, //Version:2 Playload Type:0x60
0x00, 0x64, //Sequencenumber
0x00, 0x00, 0x03, 0x20, //Timestamp
0x00, 0x00, 0x00, 0x00 //Synchronization Source
//SBC_FRAME_SUM //defined for Media Payload
};
void sbc_enc_packet_pack(struct sbc_enc_hdl *hdl)
{
unsigned int TS; /*TimeStamp*/
/*SequenceNumber*/
hdl->packet_head_sn++;
/*Timestamp*/
TS = hdl->packet_head_sn * (128 * SBC_FRAME_SUM);
sbc_packet_head_buf[2] = hdl->packet_head_sn >> 8;
sbc_packet_head_buf[3] = hdl->packet_head_sn & 0xff;
sbc_packet_head_buf[4] = TS >> 24;
sbc_packet_head_buf[5] = (TS >> 16) & 0xff;
sbc_packet_head_buf[6] = (TS >> 8) & 0xff;
sbc_packet_head_buf[7] = (TS) & 0xff;
if (hdl->cp_type == 0x0002) {
/*
*Content Protection Header
*L-bit :bit0
*Cp-bit:bit1
*RFA :bit2 to bit7
*/
sbc_packet_head_buf[12] = 0;
sbc_packet_head_buf[13] = SBC_FRAME_SUM;
} else {
sbc_packet_head_buf[12] = SBC_FRAME_SUM;
}
}
#endif/*SBC_ENC_PACK_ENABLE*/
static int sbc_enc_output_handler(struct audio_encoder *encoder, u8 *frame, int len)
{
if (encoder == NULL) {
r_printf("encoder NULL");
}
struct sbc_enc_hdl *enc = container_of(encoder, struct sbc_enc_hdl, encoder);
enc->frame_size = len;
u16 wlen = cbuf_write(&enc->output_cbuf, frame, len);
if (wlen != len) {
putchar('F');
return len;
}
//printf("sbc_enc out,frame:%x,out:%d[0x%x]\n", frame, len, enc->frame_size);
if (cbuf_get_data_size(&sbc_enc->output_cbuf) >= enc->frame_size * 5) {
//达到基本的数据量,唤醒蓝牙发数
user_send_cmd_prepare(USER_CTRL_CMD_RESUME_STACK, 0, NULL);
}
return len;
}
const static struct audio_enc_handler sbc_enc_handler = {
.enc_probe = sbc_enc_probe_handler,
.enc_output = sbc_enc_output_handler,
};
int a2dp_sbc_encoder_get_data(u8 *packet, u16 buf_len, int *frame_size)
{
if (sbc_enc == NULL) {
return 0;
}
if (cbuf_get_data_size(&sbc_enc->output_cbuf) < buf_len) {
return 0;
}
int debug_frame_size = sbc_enc->frame_size;
int number = buf_len / debug_frame_size; /*取整数包*/
*frame_size = debug_frame_size;
u16 rlen = cbuf_read(&sbc_enc->output_cbuf, packet, *frame_size * number);
if (rlen == 0) {
putchar('N');
}
return rlen;
}
static void sbc_enc_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
printf("sbc_enc_event_handler:0x%x,%d\n", argv[0], argv[0]);
switch (argv[0]) {
case AUDIO_ENC_EVENT_END:
puts("AUDIO_ENC_EVENT_END\n");
break;
}
}
#include "sbc_enc.h"
sbc_t sbc_param = {
.frequency = SBC_FREQ_44100,
.blocks = SBC_BLK_16,
.subbands = SBC_SB_8,
.mode = SBC_MODE_STEREO,
.allocation = 0,
.endian = SBC_LE,
.bitpool = 53,
};
int audio_sbc_enc_config(void *cfg)
{
sbc_t *p = cfg;
if (p) {
printf("sbc_enc_param update:\n");
printf("frequency:%d\n", p->frequency);
printf("blocks:%d\n", p->blocks);
printf("subbands:%d\n", p->subbands);
printf("mode:%d\n", p->mode);
printf("allocation:%d\n", p->allocation);
printf("endian:%d\n", p->endian);
printf("bitpool:%d\n", p->bitpool);
}
return 0;
}
int audio_sbc_enc_check_empty_len(void)
{
if (!(sbc_buf_flag & SBC_ENC_START)) {
return 0;
}
if (!sbc_enc) {
return 0;
}
return sbc_enc->pcm_in_cbuf.total_len - sbc_enc->pcm_in_cbuf.data_len;
}
int audio_sbc_enc_write(s16 *data, int len)
{
if (!(sbc_buf_flag & SBC_ENC_START)) {
return 0;
}
if (!sbc_enc) {
return 0;
}
sbc_buf_flag |= SBC_ENC_WRITING;
#if 0
u16 wlen = cbuf_write(&sbc_enc->pcm_in_cbuf, data, len);
if (wlen != len) {
putchar('@');
}
#else
int wlen = 0;
int remain_len = len;
while (remain_len) {
wlen = 0;
void *obuf = cbuf_write_alloc(&sbc_enc->pcm_in_cbuf, &wlen);
if (!wlen) {
break;
}
if (wlen > remain_len) {
wlen = remain_len;
}
memcpy(obuf, data, wlen);
/* audio_digital_vol_run(sbc_enc->dvol, obuf, wlen); */
cbuf_write_updata(&sbc_enc->pcm_in_cbuf, wlen);
remain_len -= wlen;
data += wlen / 2;
};
wlen = len - remain_len;
#endif
if (cbuf_get_data_size(&sbc_enc->pcm_in_cbuf) >= SBC_ENC_IN_SIZE) {
audio_encoder_resume(&sbc_enc->encoder);
}
sbc_buf_flag &= ~SBC_ENC_WRITING;
return wlen;
}
#if SBC_USE_MIC_CHANNEL
s16 temp_data[ESCO_ADC_IRQ_POINTS * 2];
extern struct audio_adc_hdl adc_hdl;
static void adc_mic_output_handler(void *priv, s16 *data, int len)
{
u16 points = len >> 1;
if (!(sbc_buf_flag & SBC_ENC_START)) {
return 0;
}
if (sbc_enc) {
//单变双
for (int i = 0; i < points ; i++) {
temp_data[i * 2] = data[i];
temp_data[i * 2 + 1] = data[i];
}
//app_audio_output_write(temp_data, len*2);
//memset(temp_data, 0 , sizeof(temp_data));
audio_sbc_enc_write(temp_data, len * 2);
}
}
#endif
int audio_sbc_enc_open()
{
int err;
struct audio_fmt fmt;
u16 frame_len = 512;
if (encode_task) {
return -1;
}
printf("sbc_enc_open,frame_len:%d\n", frame_len);
sbc_buf_flag &= ~SBC_ENC_START;
fmt.channel = 1;
fmt.frame_len = frame_len;
fmt.coding_type = AUDIO_CODING_SBC;
fmt.priv = &sbc_param;
audio_encoder_task_open();
if (!sbc_enc) {
sbc_enc = zalloc(sizeof(*sbc_enc));
}
printf("init vol:%d \n", app_var.music_volume);
/* sbc_enc->dvol = audio_digital_vol_open(app_var.music_volume, 30, 7); */
cbuf_init(&sbc_enc->output_cbuf, sbc_enc->out_cbuf_buf, SBC_ENC_OUT_CBUF_SIZE);
cbuf_init(&sbc_enc->pcm_in_cbuf, sbc_enc->in_cbuf_buf, SBC_ENC_IN_CBUF_SIZE);
os_sem_create(&sbc_enc->pcm_frame_sem, 0);
audio_encoder_open(&sbc_enc->encoder, &sbc_enc_input, encode_task);
audio_encoder_set_handler(&sbc_enc->encoder, &sbc_enc_handler);
audio_encoder_set_fmt(&sbc_enc->encoder, &fmt);
audio_encoder_set_event_handler(&sbc_enc->encoder, sbc_enc_event_handler, 0);
audio_encoder_set_output_buffs(&sbc_enc->encoder, sbc_enc->output_frame,
sizeof(sbc_enc->output_frame), 1);
int start_err = audio_encoder_start(&sbc_enc->encoder);
printf("sbc_enc_open ok %d\n", start_err);
#if SBC_USE_MIC_CHANNEL
fmt.sample_rate = 44100;
audio_adc_mic_open(&sbc_enc->mic_ch, AUDIO_ADC_MIC_CH, &adc_hdl);
audio_adc_mic_set_sample_rate(&sbc_enc->mic_ch, fmt.sample_rate);
audio_adc_mic_set_gain(&sbc_enc->mic_ch, app_var.aec_mic_gain);
audio_adc_mic_set_buffs(&sbc_enc->mic_ch, sbc_enc->adc_buf,
ESCO_ADC_IRQ_POINTS * 2, ESCO_ADC_BUF_NUM);
sbc_enc->adc_output.handler = adc_mic_output_handler;
audio_adc_add_output_handler(&adc_hdl, &sbc_enc->adc_output);
//app_audio_output_samplerate_set(44100);
//app_audio_output_start();
audio_adc_mic_start(&sbc_enc->mic_ch);
#endif
clock_add(ENC_SBC_CLK);
clock_set_cur();
sbc_buf_flag |= SBC_ENC_START;
audio_sbc_enc_open_exit();
return 0;
}
int audio_sbc_enc_reset_buf(u8 flag)
{
if (!sbc_enc) {
return -1;
}
r_printf("audio_sbc_enc_reset_buf %d\n", flag);
if (flag) {
//有些情况提示音没有足够的参数去fade out使得下次fade in受影响。
//所以默认每次都reset一下
/* audio_digital_vol_reset_fade(sbc_enc->dvol); */
/* audio_digital_vol_set(sbc_enc->dvol, sbc_enc->backup_digital_vol); */
if (sbc_enc->mute_data_send_timer) {
sys_hi_timer_del(sbc_enc->mute_data_send_timer);
sbc_enc->mute_data_send_timer = 0;
sbc_buf_flag &= ~SBC_ENC_PCM_MUTE_DATA;
}
} else {
/* audio_digital_vol_set(sbc_enc->dvol, 0); */
if (sbc_enc->mute_data_send_timer == 0) {
//sbc_enc->mute_data_send_timer= sys_hi_timer_add((void *)0, sbc_send_mute_data, 12);
}
}
return 0;
}
int audio_sbc_enc_close()
{
if (!sbc_enc) {
return -1;
}
printf("audio_sbc_enc_close\n");
audio_sbc_enc_close_enter();
sbc_buf_flag &= ~SBC_ENC_START;
while (sbc_buf_flag & SBC_ENC_WRITING) {
os_time_dly(1);
}
/* audio_digital_vol_close(sbc_enc->dvol); */
#if SBC_USE_MIC_CHANNEL
audio_adc_mic_close(&sbc_enc->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &sbc_enc->adc_output);
#endif
audio_encoder_close(&sbc_enc->encoder);
free(sbc_enc);
sbc_enc = NULL;
audio_encoder_task_close();
clock_remove(ENC_SBC_CLK);
clock_set_cur();
printf("audio_sbc_enc_close end\n");
return 0;
}
void audio_sbc_enc_init(void)
{
/* audio_digital_vol_open(0, 30, 4); */
//printf("init vol:%d \n", app_var.music_volume);
//audio_digital_vol_open(app_var.music_volume, 30, 7);
}
int audio_sbc_enc_is_work(void)
{
if ((sbc_buf_flag & SBC_ENC_START) && sbc_enc) {
return true;
}
return false;
}
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)
#include "application/audio_dig_vol.h"
extern void *bt_digvol_last;
#endif
void bt_emitter_set_vol(u8 vol)
{
if (!(sbc_buf_flag & SBC_ENC_START)) {
return ;
}
if (!sbc_enc) {
return ;
}
sbc_enc->backup_digital_vol = vol;
r_printf("=======set vol %d\n", vol);
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)
if (bt_digvol_last) {
audio_dig_vol_set(bt_digvol_last, AUDIO_DIG_VOL_ALL_CH, vol);
}
#endif
}
int audio_sbc_enc_get_rate(void)
{
int sr = 44100;
switch (sbc_param.frequency) {
case SBC_FREQ_16000:
sr = 16000;
break;
case SBC_FREQ_32000:
sr = 32000;
break;
case SBC_FREQ_44100:
sr = 44100;
break;
case SBC_FREQ_48000:
sr = 48000;
break;
}
return sr;
}
int audio_sbc_enc_get_channel_num(void)
{
return sbc_param.mode == SBC_MODE_MONO ? 1 : 2;
}
int a2dp_sbc_encoder_init(void *sbc_struct)
{
if (sbc_struct) {
//更新连接过程中的a2dp source参数
//audio_sbc_enc_config(&sbc_param);
memcpy(&sbc_param, sbc_struct, sizeof(sbc_t));
//audio_sbc_enc_config(&sbc_param);
audio_sbc_enc_open();
} else {
audio_sbc_enc_close();
}
return 0;
}
#if (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)
struct sbc_emitter_hdl sbc_emitter = {0};
static int audio_stream_sbc_emitter_data_handler(struct audio_stream_entry *entry, struct audio_data_frame *in,
struct audio_data_frame *out)
{
if (in->data_len == 0) {
return 0;
}
if (false == audio_sbc_enc_is_work()) {
return in->data_len;
}
return audio_sbc_enc_write(in->data, in->data_len);
}
void audio_sbc_emitter_init(void)
{
sbc_emitter.entry.data_handler = audio_stream_sbc_emitter_data_handler;
}
#endif