doubao_chat/apps/demo/demo_edr/bt_decode.c

995 lines
26 KiB
C

#include "server/audio_server.h"
#include "server/server_core.h"
#include "btstack/avctp_user.h"
#include "app_config.h"
#include "asm/sbc.h"
#include "asm/clock.h"
#include "btstack/a2dp_media_codec.h"
#include "system/timer.h"
#ifdef CONFIG_BT_ENABLE
#define log_info log_i
#define BT_MUSIC_DECODE
#define BT_PHONE_DECODE
#if TCFG_USER_EMITTER_ENABLE
#define BT_EMITTER_ENABLE
#endif
extern void earphone_a2dp_audio_codec_close(void);
extern void phone_call_end(void);
extern int a2dp_media_get_total_buffer_size(void);
#ifdef BT_MUSIC_DECODE
#define A2DP_CODEC_SBC 0x00
#define A2DP_CODEC_MPEG12 0x01
#define A2DP_CODEC_MPEG24 0x02
#define BT_AUDIO_FORMAT_SBC 1
#define BT_AUDIO_FORMAT_AAC 2
#define BT_AUDIO_FORMAT_APTX 3
#define BT_AUDIO_FORMAT_LADC 4
#define BT_AUDIO_FORMAT_CVSD 5
#define BT_AUDIO_FORMAT_MSBC 6
#define BT_DEC_RATE_MAX_STEP 100
#define BT_DEC_RATE_INC_STEP 2
#define BT_DEC_RATE_DEC_STEP 2
struct bt_media_vfs_handle {
u8 format;
u8 not_mute_cnt;
u8 a2dp_open;
u8 ready;
u16 seqn;
s16 adjust_step;
void *p_addr;
int p_len;
int p_pos;
void *audio_dec;
u32 begin_size;
u32 top_size;
u32 bottom_size;
};
static struct bt_media_vfs_handle bt_media_vfs_handle;
#define mfs (&bt_media_vfs_handle)
static void sbc_dec_event_handler(void *priv, int argc, int *argv)
{
union audio_req req = {0};
switch (argv[0]) {
case AUDIO_SERVER_EVENT_END:
earphone_a2dp_audio_codec_close();
break;
default:
break;
}
}
#define RB16(b) (u16)(((u8 *)b)[0] << 8 | (((u8 *)b))[1])
static int get_rtp_header_len(u8 *buf, int len)
{
int ext, csrc;
int byte_len;
int header_len = 0;
u8 *data = buf;
if (RB16(buf + 2) != (u16)(mfs->seqn + 1) && mfs->seqn) {
putchar('K');
}
mfs->seqn = RB16(buf + 2);
csrc = buf[0] & 0x0f;
ext = buf[0] & 0x10;
byte_len = 12 + 4 * csrc;
buf += byte_len;
if (ext) {
ext = (RB16(buf + 2) + 1) << 2;
}
header_len = byte_len + ext + 1;
if (mfs->format == BT_AUDIO_FORMAT_SBC) {
/*sbc兼容性处理*/
while (data[header_len] != 0x9c) {
if (++header_len > len) {
log_w("sbc warn\n");
return len;
}
}
}
if (header_len != byte_len + ext + 1) {
/* log_w("sbc warn!!!\n"); */
/* put_buf(data, len); */
}
return header_len;
}
static void media_stream_free(void)
{
if (mfs->p_addr) {
a2dp_media_free_packet(mfs->p_addr);
mfs->p_addr = NULL;
mfs->p_pos = 0;
mfs->p_len = 0;
}
}
static int bt_sbc_file_read(void *priv, void *buf, u32 len)
{
u32 r_len = 0;
u32 offset = 0;
do {
if (!mfs->p_addr) {
mfs->p_len = a2dp_media_get_packet((u8 **)&mfs->p_addr);
if (!mfs->p_addr) {
if (!mfs->a2dp_open) {
return 0;
}
if (mfs->p_len == -EINVAL) {
return -1;
}
continue;
}
mfs->p_pos = get_rtp_header_len(mfs->p_addr, mfs->p_len);
}
if (len == (u32) - 1) { //第一包
if (0x800 > mfs->p_len && mfs->format == BT_AUDIO_FORMAT_SBC) {
memcpy(buf, (u8 *)mfs->p_addr, mfs->p_len);
offset = mfs->p_len;
media_stream_free();
break;
} else {
if (mfs->format == BT_AUDIO_FORMAT_SBC) {
memcpy(buf, (u8 *)mfs->p_addr, 0x20);
} else {
memcpy(buf, (u8 *)mfs->p_addr + mfs->p_pos, 0x20);
}
offset = 0x20;
media_stream_free();
break;
}
}
if (!mfs->ready) {
//等待存够50ms才开始解码
while (a2dp_media_get_remain_play_time(0) < 50) {
if (!mfs->a2dp_open) {
return 0;
}
os_time_dly(1);
}
mfs->ready = 1;
}
r_len = mfs->p_len - mfs->p_pos;
if (r_len > (len - offset)) {
r_len = len - offset;
}
memcpy((u8 *)buf + offset, (u8 *)mfs->p_addr + mfs->p_pos, r_len);
mfs->p_pos += r_len;
offset += r_len;
if (mfs->p_pos >= mfs->p_len) {
media_stream_free();
if (mfs->format == BT_AUDIO_FORMAT_SBC) {
break;
}
}
} while (offset < len);
return offset;
}
static int bt_sbc_file_seek(void *priv, u32 offset, int orig)
{
return 0;
}
static const struct audio_vfs_ops bt_sbc_audio_dec_vfs_ops = {
.fread = bt_sbc_file_read,
.fseek = bt_sbc_file_seek,
};
static int bt_sync(void *priv, u32 data_size, u16 *in_rate, u16 *out_rate)
{
data_size = a2dp_media_get_total_data_len();
if (data_size < mfs->bottom_size) {
/* putchar('<'); */
mfs->adjust_step += BT_DEC_RATE_INC_STEP;
if (mfs->adjust_step < 0) {
mfs->adjust_step += BT_DEC_RATE_INC_STEP * 2;
}
} else if (data_size > mfs->top_size) {
/* putchar('>'); */
mfs->adjust_step -= BT_DEC_RATE_DEC_STEP;
if (mfs->adjust_step > 0) {
mfs->adjust_step -= BT_DEC_RATE_DEC_STEP * 2;
}
} else {
/* putchar('='); */
if (mfs->adjust_step > 0) {
mfs->adjust_step -= (mfs->adjust_step * BT_DEC_RATE_INC_STEP) / BT_DEC_RATE_MAX_STEP;
if (mfs->adjust_step > 0) {
mfs->adjust_step--;
}
} else if (mfs->adjust_step < 0) {
mfs->adjust_step += ((0 - mfs->adjust_step) * BT_DEC_RATE_DEC_STEP) / BT_DEC_RATE_MAX_STEP;
if (mfs->adjust_step < 0) {
mfs->adjust_step++;
}
}
}
if (mfs->adjust_step < -BT_DEC_RATE_MAX_STEP) {
mfs->adjust_step = -BT_DEC_RATE_MAX_STEP;
/* putchar('{'); */
} else if (mfs->adjust_step > BT_DEC_RATE_MAX_STEP) {
mfs->adjust_step = BT_DEC_RATE_MAX_STEP;
/* putchar('}'); */
}
*out_rate += mfs->adjust_step;
return 0;
}
void *earphone_a2dp_audio_codec_open(int media_type, u8 volume)
{
union audio_req req = {0};
int err = 0;
mfs->audio_dec = server_open("audio_server", "dec");
if (!mfs->audio_dec) {
return NULL;
}
/*播放事件注册(这个可以先不用加,根据需要添加)*/
server_register_event_handler(mfs->audio_dec, mfs, sbc_dec_event_handler);
switch (media_type) {
case A2DP_CODEC_SBC:
req.dec.dec_type = "sbc";
mfs->format = BT_AUDIO_FORMAT_SBC;
break;
case A2DP_CODEC_MPEG24:
req.dec.dec_type = "aac";
mfs->format = BT_AUDIO_FORMAT_AAC;
break;
}
req.dec.cmd = AUDIO_DEC_OPEN;
req.dec.volume = volume;
req.dec.output_buf = NULL;
req.dec.output_buf_len = 2 * 1024;
req.dec.channel = 0;
req.dec.sample_rate = 0;
req.dec.vfs_ops = &bt_sbc_audio_dec_vfs_ops;
req.dec.sample_source = "dac";
#if defined CONFIG_AUDIO_MIX_ENABLE
req.dec.attr = AUDIO_ATTR_REAL_TIME;
req.dec.dec_sync = bt_sync;
#endif
if (media_type == A2DP_CODEC_MPEG24) {
req.dec.attr |= AUDIO_ATTR_BT_AAC_EN;
}
mfs->a2dp_open = 1;
err = server_request(mfs->audio_dec, AUDIO_REQ_DEC, &req);
if (err) {
mfs->a2dp_open = 0;
server_close(mfs->audio_dec);
mfs->audio_dec = NULL;
return NULL;
}
mfs->seqn = 0;
mfs->adjust_step = 0;
int a2dp_total_size = a2dp_media_get_total_buffer_size();
mfs->begin_size = a2dp_total_size * 6 / 10;
mfs->top_size = a2dp_total_size / 2;
mfs->bottom_size = a2dp_total_size * 3 / 10;
req.dec.cmd = AUDIO_DEC_START;
server_request(mfs->audio_dec, AUDIO_REQ_DEC, &req);
return mfs->audio_dec;
}
void earphone_a2dp_audio_codec_close(void)
{
union audio_req req = {0};
mfs->a2dp_open = 0;
if (!mfs->audio_dec) {
return;
}
log_info("audio decode server close\n");
req.dec.cmd = AUDIO_DEC_STOP;
server_request(mfs->audio_dec, AUDIO_REQ_DEC, &req);
server_close(mfs->audio_dec);
media_stream_free();
mfs->audio_dec = NULL;
mfs->ready = 0;
}
#endif
#ifdef BT_PHONE_DECODE
extern void lmp_private_free_esco_packet(void *packet);
extern void *lmp_private_get_esco_packet(int *len, u32 *hash);
extern int lmp_private_send_esco_packet(void *priv, u8 *packet, int len);
extern u32 lmp_private_get_tx_remain_buffer(void);
struct bt_phone_vfs_handle {
u8 state;
u8 format;
u8 mute;
u8 lmp_open;
void *p_addr;
int p_len;
int p_pos;
int frame_offset;
int err_cnt;
int frame_len;
void *audio_dec;
void *audio_enc;
};
static struct bt_phone_vfs_handle bt_phone_vfs_handle;
#define pfs (&bt_phone_vfs_handle)
static u8 headcheck(u8 *buf)
{
int sync_word = buf[0] | ((buf[1] & 0x0f) << 8);
return (sync_word == 0x801) && (buf[2] == 0xAD);
}
static const u8 msbc_mute_data[] = {
0xAD, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76,
0xDB, 0x6D, 0xDD, 0xB6, 0xDB, 0x77, 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76, 0xDB, 0x6D, 0xDD,
0xB6, 0xDB, 0x77, 0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76, 0xDB, 0x6D, 0xDD, 0xB6, 0xDB, 0x77,
0x6D, 0xB6, 0xDD, 0xDB, 0x6D, 0xB7, 0x76, 0xDB, 0x6C, 0x00,
};
static const u8 msbc_err_data[] = {
0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
};
static void phone_stream_free(void)
{
if (pfs->p_addr) {
lmp_private_free_esco_packet(pfs->p_addr);
pfs->p_addr = NULL;
pfs->p_pos = 0;
pfs->p_len = 0;
}
}
static int bt_phone_file_read(void *priv, void *buf, u32 len)
{
u32 r_len = 0;
u32 offset = 0;
u32 hash = 0;
do {
if (!pfs->p_addr) {
if (pfs->mute) {
pfs->p_addr = (void *)msbc_mute_data;
pfs->p_len = sizeof(msbc_mute_data);
} else {
pfs->p_addr = (u8 *)lmp_private_get_esco_packet(&pfs->p_len, &hash);
if (pfs->p_addr) {
/* put_buf(pfs->p_addr,pfs->p_len); */
u8 test_check[4];
memset(test_check, 0, 4);
memcpy(test_check, pfs->p_addr, 4);
if (test_check[0] == 0x55 && test_check[1] == 0x55 && test_check[2] == 0xAA && test_check[3] == 0xAA) { //丢/错包标记0xAAAA5555
memcpy(buf, msbc_err_data, len);
phone_stream_free();
return len;
break;
}
}
}
if (!pfs->p_addr) {
pfs->p_len = 0;
if (!pfs->lmp_open) {
printf("lmp file close \r\n");
return 0;
} else {
#if 0
os_time_dly(1);
continue;
#else
return -1;
#endif
}
}
pfs->p_pos = 0;
}
if (pfs->frame_offset == 0) {
if (pfs->format == BT_AUDIO_FORMAT_MSBC) {
u32 head_offset = 0;
u8 *ptr = (u8 *)pfs->p_addr + pfs->p_pos;
int check_len = pfs->p_len - pfs->p_pos;
while (head_offset < check_len) {
if (ptr[head_offset] == 0xAD) {
if (head_offset >= 2) {
if (!headcheck(ptr + head_offset - 2)) {
/* put_buf(pfs->p_addr, pfs->p_len); */
pfs->err_cnt++;
head_offset++;
continue;
}
}
break;
}
pfs->err_cnt++;
head_offset++;
}
if (pfs->err_cnt >= pfs->frame_len + 2) {
phone_stream_free();
pfs->mute = 1;
pfs->err_cnt = 0;
continue;
}
if (pfs->p_pos >= pfs->p_len) {
phone_stream_free();
continue;
}
pfs->p_pos += head_offset;
pfs->err_cnt = 0;
} else if (pfs->format == BT_AUDIO_FORMAT_CVSD) {
pfs->frame_len = pfs->p_len;
}
}
r_len = pfs->frame_len - pfs->frame_offset;
if (r_len > (len - offset)) {
r_len = len - offset;
}
if (r_len > (pfs->p_len - pfs->p_pos)) {
r_len = pfs->p_len - pfs->p_pos;
}
memcpy((u8 *)buf + offset, (u8 *)pfs->p_addr + pfs->p_pos, r_len);
offset += r_len;
pfs->p_pos += r_len;
pfs->frame_offset += r_len;
if (pfs->frame_offset >= pfs->frame_len) {
pfs->frame_offset = 0;
}
if (pfs->p_pos >= pfs->p_len) {
if (pfs->mute) {
pfs->p_addr = NULL;
pfs->p_len = 0;
pfs->p_pos = 0;
pfs->mute = 0;
} else {
phone_stream_free();
break;
}
}
} while (offset < len);
if (offset < len) {
putchar('K');
return -1; //华为语音助手唤醒时偶尔会发两个不规范的包
}
return offset;
}
static int bt_phone_file_write(void *priv, void *buf, u32 len)
{
if (!pfs->lmp_open) {
return 0;
}
if (lmp_private_get_tx_remain_buffer() >= len + 28) {
lmp_private_send_esco_packet(NULL, buf, len);
}
return len;
}
static int bt_phone_file_seek(void *priv, u32 offset, int orig)
{
return 0;
}
static int bt_phone_file_len(void *priv)
{
return -1;
}
static const struct audio_vfs_ops bt_phone_audio_dec_vfs_ops = {
.fread = bt_phone_file_read,
.fwrite = bt_phone_file_write,
.fseek = bt_phone_file_seek,
.flen = bt_phone_file_len,
};
static void phone_call_dec_event_handler(void *priv, int argc, int *argv)
{
switch (argv[0]) {
/* case AUDIO_SERVER_EVENT_ERR: */
case AUDIO_SERVER_EVENT_END:
phone_call_end();
break;
default:
break;
}
}
static void *phone_decode_start(int format, u8 volume)
{
union audio_req req = {0};
pfs->audio_dec = server_open("audio_server", "dec");
if (!pfs->audio_dec) {
log_info("audio decode server open error\n");
return NULL;
}
server_register_event_handler(pfs->audio_dec, NULL, phone_call_dec_event_handler);
pfs->format = format;
pfs->frame_offset = 0;
pfs->err_cnt = 0;
if (format == BT_AUDIO_FORMAT_MSBC) {
req.dec.dec_type = "msbc";
req.dec.sample_rate = 16000;
pfs->frame_len = 58;
pfs->mute = 0;
} else if (format == BT_AUDIO_FORMAT_CVSD) {
req.dec.dec_type = "cvsd";
req.dec.sample_rate = 8000;
}
req.dec.cmd = AUDIO_DEC_OPEN;
req.dec.volume = volume;
req.dec.output_buf = NULL;
req.dec.output_buf_len = 1024 * 4;
req.dec.channel = 2;
req.dec.priority = 1;
req.dec.vfs_ops = &bt_phone_audio_dec_vfs_ops;
req.dec.sample_source = "dac";
server_request(pfs->audio_dec, AUDIO_REQ_DEC, &req);
req.dec.cmd = AUDIO_DEC_START;
req.dec.attr = AUDIO_ATTR_NO_WAIT_READY;
server_request(pfs->audio_dec, AUDIO_REQ_DEC, &req);
return pfs->audio_dec;
}
static void phone_decode_close(void)
{
union audio_req req = {0};
if (!pfs->audio_dec) {
return;
}
req.dec.cmd = AUDIO_DEC_STOP;
server_request(pfs->audio_dec, AUDIO_REQ_DEC, &req);
server_close(pfs->audio_dec);
phone_stream_free();
pfs->audio_dec = NULL;
}
static int phone_speak_start(int format, int packet_len)
{
int err = 0;
union audio_req req = {0};
pfs->audio_enc = server_open("audio_server", "enc");
if (!pfs->audio_enc) {
log_info("audio enc server open error\n");
return -1;
}
req.enc.cmd = AUDIO_ENC_OPEN;
req.enc.channel = 1;
req.enc.volume = 100;
req.enc.output_buf = NULL;
req.enc.sample_source = "mic";
req.enc.vfs_ops = &bt_phone_audio_dec_vfs_ops;
#ifdef CONFIG_ALL_ADC_CHANNEL_OPEN_ENABLE
req.enc.channel_bit_map = BIT(CONFIG_PHONE_CALL_ADC_CHANNEL);
#endif
if (format == BT_AUDIO_FORMAT_MSBC) {
req.enc.format = "msbc";
req.enc.sample_rate = 16000;
req.enc.output_buf_len = 512;
} else if (format == BT_AUDIO_FORMAT_CVSD) {
req.enc.format = "cvsd";
req.enc.sample_rate = 8000;
req.enc.frame_size = packet_len * 2;
req.enc.output_buf_len = packet_len * 2 * 10;
}
#if defined CONFIG_AEC_ENC_ENABLE && !defined CONFIG_FPGA_ENABLE
#define AEC_EN BIT(0)
#define NLP_EN BIT(1)
#define ANS_EN BIT(2)
/*aec module enable bit define*/
#define AEC_MODE_ADVANCE (AEC_EN | NLP_EN | ANS_EN)
#define AEC_MODE_REDUCE (NLP_EN | ANS_EN)
#define AEC_MODE_SIMPLEX (ANS_EN)
struct aec_s_attr aec_param = {0};
aec_param.EnableBit = AEC_MODE_ADVANCE;
/* aec_param.agc_en = 1; */
aec_param.output_way = 1; //1:使用硬件回采 0:使用软件回采
req.enc.aec_attr = &aec_param;
req.enc.aec_enable = 1;
extern void get_cfg_file_aec_config(struct aec_s_attr * aec_param);
get_cfg_file_aec_config(&aec_param);
#if 0
aec_param.ANS_NoiseLevel = 2.2e3f; //初始噪声水平,用来加速降噪收敛,跟 mic 信号的信噪比有关。 Mic 信号信噪比高, 该值可以小一点, 反之则需要稍微大一点。default: 2.2e3f(0 ~ 32767)
#endif
if (aec_param.EnableBit == 0) {
req.enc.aec_enable = 0;
req.enc.aec_attr = NULL;
}
if (aec_param.EnableBit != AEC_MODE_ADVANCE) {
aec_param.output_way = 0;
}
if (aec_param.output_way) {
#ifdef CONFIG_ALL_ADC_CHANNEL_OPEN_ENABLE
req.enc.channel_bit_map |= BIT(CONFIG_AEC_ADC_CHANNEL); //配置回采硬件通道
if (CONFIG_AEC_ADC_CHANNEL < CONFIG_PHONE_CALL_ADC_CHANNEL) {
req.enc.ch_data_exchange = 1; //如果回采通道使用的硬件channel比MIC通道使用的硬件channel靠前的话处理数据时需要交换一下顺序
}
#endif
}
aec_param.AGC_echo_look_ahead = 100;
aec_param.AGC_echo_hold = 400;
aec_param.ES_Unconverge_OverDrive = aec_param.ES_MinSuppress;
if (req.enc.sample_rate == 16000) {
aec_param.wideband = 1;
aec_param.hw_delay_offset = 50;
} else {
aec_param.wideband = 0;
aec_param.hw_delay_offset = 75;
}
#if CONFIG_AEC_SIMPLEX_ENABLE
#define AEC_SIMPLEX_TAIL 15 /*单工连续清0的帧数*/
/*远端数据大于CONST_AEC_SIMPLEX_THR,即清零近端数据越小,回音限制得越好,同时也就越容易卡*/
#define AEC_SIMPLEX_THR 100000 /*default:260000*/
aec_param.wn_en = 1;
aec_param.simplex = 1;
aec_param.dly_est = 1;
aec_param.wn_gain = 331;
aec_param.dst_delay = 50;
aec_param.EnableBit = AEC_MODE_SIMPLEX;
aec_param.SimplexTail = req.enc.sample_rate == 8000 ? AEC_SIMPLEX_TAIL / 2 : AEC_SIMPLEX_TAIL;
aec_param.SimplexThr = AEC_SIMPLEX_THR;
#endif/*TCFG_AEC_SIMPLEX*/
#endif
err = server_request(pfs->audio_enc, AUDIO_REQ_ENC, &req);
#if defined CONFIG_AEC_ENC_ENABLE && !defined CONFIG_FPGA_ENABLE
if (aec_param.output_way) {
#ifdef CONFIG_ALL_ADC_CHANNEL_OPEN_ENABLE
extern void adc_multiplex_set_gain(const char *source, u8 channel_bit_map, u8 gain);
adc_multiplex_set_gain("mic", BIT(CONFIG_AEC_ADC_CHANNEL), CONFIG_AEC_AUDIO_ADC_GAIN);
#endif
}
#endif
return err;
}
static int phone_speak_close(void)
{
union audio_req req = {0};
if (pfs->audio_enc) {
req.enc.cmd = AUDIO_ENC_STOP;
server_request(pfs->audio_enc, AUDIO_REQ_ENC, &req);
server_close(pfs->audio_enc);
pfs->audio_enc = NULL;
}
return 0;
}
void *phone_call_begin(void *priv, u8 volume)
{
int err = 0;
u32 esco_param = *(u32 *)priv;
int esco_len = esco_param >> 16;
int codec_type = esco_param & 0x000000ff;
if (codec_type == 3) {
log_info(">>sco_format:msbc\n");
codec_type = BT_AUDIO_FORMAT_MSBC;
} else if (codec_type == 2) {
log_info(">>sco_format:cvsd\n");
codec_type = BT_AUDIO_FORMAT_CVSD;
} else {
log_info("sco_format:error->please check %d\n", codec_type);
return NULL;
}
pfs->lmp_open = 1;
err = phone_speak_start(codec_type, esco_len);
if (err) {
goto __err;
}
return phone_decode_start(codec_type, volume);
__err:
phone_call_end();
return NULL;
}
void phone_call_end(void)
{
pfs->lmp_open = 0;
phone_speak_close();
phone_decode_close();
}
#endif
#ifdef BT_EMITTER_ENABLE
#define BT_EMITTER_CBUF_SIZE (512 * 6)
typedef struct sbc_param_str {
unsigned int flags;
u8 frequency;
u8 blocks;
u8 subbands;
u8 mode;
u8 allocation;
u8 bitpool;
u8 endian;
void *priv;
void *priv_alloc_base;
} sbc_t;
struct bt_emitter_vfs_handle {
u8 open;
u8 gain;
u8 suspend;
u16 frame_size;
void *audio_enc;
cbuffer_t cbuf;
void *buf;
};
static struct bt_emitter_vfs_handle bt_emitter_vfs_handle = {.gain = 100};
#define efs (&bt_emitter_vfs_handle)
static int bt_emitter_vfs_fwrite(void *file, void *data, u32 len)
{
cbuffer_t *cbuf = (cbuffer_t *)file;
efs->frame_size = len;
if (cbuf_write(cbuf, data, len) != len) {
putchar('N');
cbuf_clear(cbuf);
} else if (efs->suspend) {
efs->suspend = 0;
extern void stack_run_loop_resume();
stack_run_loop_resume();
}
return len;
}
static int bt_emitter_vfs_fclose(void *file)
{
return 0;
}
static const struct audio_vfs_ops bt_emitter_vfs_ops = {
.fwrite = bt_emitter_vfs_fwrite,
.fclose = bt_emitter_vfs_fclose,
};
int a2dp_sbc_encoder_init(void *sbc_struct)
{
int ret = 0;
union audio_req req = {0};
sbc_t *sbc = (sbc_t *)sbc_struct;
if (sbc) {
log_info("audio emitter server open \n");
efs->buf = malloc(BT_EMITTER_CBUF_SIZE);
if (!efs->buf) {
return -1;
}
efs->audio_enc = server_open("audio_server", "enc");
if (!efs->audio_enc) {
free(efs->buf);
efs->buf = NULL;
return -1;
}
cbuf_init(&efs->cbuf, efs->buf, BT_EMITTER_CBUF_SIZE);
req.enc.cmd = AUDIO_ENC_OPEN;
req.enc.channel = sbc->mode > 0 ? 2 : 1;
req.enc.volume = efs->gain;
req.enc.frame_size = (sbc->subbands ? 8 : 4) * (4 + (sbc->blocks * 4)) * req.enc.channel * 2;
req.enc.output_buf_len = 4 * req.enc.frame_size;
req.enc.format = "sbc";
req.enc.sample_source = "mic";
req.enc.vfs_ops = &bt_emitter_vfs_ops;
req.enc.file = (FILE *)&efs->cbuf;
req.enc.bitrate = ((3 - sbc->blocks) << 28) & sbc->bitpool;
if (sbc->endian) {
req.enc.bitrate |= BIT(31);
}
if (!sbc->subbands) {
req.enc.bitrate |= BIT(30);
}
if (sbc->frequency == SBC_FREQ_48000) {
req.enc.sample_rate = 48000;
} else if (sbc->frequency == SBC_FREQ_44100) {
req.enc.sample_rate = 44100;
} else if (sbc->frequency == SBC_FREQ_32000) {
req.enc.sample_rate = 32000;
} else {
req.enc.sample_rate = 16000;
}
if (req.enc.channel == 2) {
req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L) | BIT(CONFIG_AUDIO_ADC_CHANNEL_R);
} else {
req.enc.channel_bit_map = BIT(CONFIG_AUDIO_ADC_CHANNEL_L);
}
ret = server_request(efs->audio_enc, AUDIO_REQ_ENC, &req);
if (!ret) {
efs->open = 1;
}
return ret;
} else {
log_info("audio emitter server close \n");
efs->open = 0;
if (efs->audio_enc) {
req.enc.cmd = AUDIO_ENC_CLOSE;
server_request(efs->audio_enc, AUDIO_REQ_ENC, &req);
server_close(efs->audio_enc);
efs->audio_enc = NULL;
}
if (efs->buf) {
cbuf_clear(&efs->cbuf);
free(efs->buf);
efs->buf = NULL;
}
efs->frame_size = 0;
efs->suspend = 0;
return 0;
}
}
int a2dp_sbc_encoder_get_data(u8 *packet, u16 buf_len, int *frame_size)
{
int number = 0;
u32 data_size = 0;
while (efs->open) {
data_size = cbuf_get_data_size(&efs->cbuf);
if (!data_size) {
efs->suspend = 1;
return 0;
}
if (buf_len < data_size) {
data_size = buf_len;
}
number = data_size / efs->frame_size; /*取整数包*/
*frame_size = efs->frame_size;
data_size = cbuf_read(&efs->cbuf, packet, *frame_size * number);
if (data_size > 0) {
return data_size;
}
}
return 0;
}
u8 bt_emitter_stu_get(void)
{
return efs->open;
}
int bt_emitter_enc_gain_set(int step)
{
if (efs->audio_enc) {
union audio_req req = {0};
int gain = efs->gain + step;
if (gain < 0) {
gain = 0;
} else if (gain > 100) {
gain = 100;
}
if (gain == efs->gain) {
return -1;
}
efs->gain = gain;
log_d("set_enc_gain: %d\n", gain);
req.enc.cmd = AUDIO_ENC_SET_VOLUME;
req.enc.volume = gain;
return server_request(efs->audio_enc, AUDIO_REQ_ENC, &req);
}
return -1;
}
#endif
#endif