doubao_chat/include_lib/server/audio_server.h

388 lines
20 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.

#ifndef AUDIO_SERVER_H
#define AUDIO_SERVER_H
#include "fs/fs.h"
#include "server/audio_dev.h"
/**
* @brief enum AUDIO_SERVER事件回调
*/
enum {
AUDIO_SERVER_EVENT_CURR_TIME = 0x20, /*!< AUDIO_SERVER编/解码当前时间 */
AUDIO_SERVER_EVENT_END, /*!< AUDIO_SERVER编/解码结束 */
AUDIO_SERVER_EVENT_ERR, /*!< AUDIO_SERVER编/解码错误 */
AUDIO_SERVER_EVENT_SPEAK_START, /*!< VAD检测到开始说话 */
AUDIO_SERVER_EVENT_SPEAK_STOP, /*!< VAD检测到停止说话 */
};
/**
* @brief 解码附加属性
*/
enum {
AUDIO_ATTR_REAL_TIME = BIT(0), /*!< 保证解码的实时性,解码读数不能堵塞,仅限于蓝牙播歌时时钟同步使用 */
AUDIO_ATTR_LR_SUB = BIT(1), /*!< 伴奏功能,只支持双声道 */
AUDIO_ATTR_PS_EN = BIT(2), /*!< 变速变声功能开关 */
AUDIO_ATTR_LR_ADD = BIT(3), /*!< 解码器左右通道数据叠加 */
AUDIO_ATTR_DECRYPT_DEC = BIT(4), /*!< 文件解密播放,需要配合对应的加密工具 */
AUDIO_ATTR_FADE_INOUT = BIT(5), /*!< 模拟音量淡入淡出,解码开始和暂停时使用 */
AUDIO_ATTR_EQ_EN = BIT(6), /*!< EQ功能开关*/
AUDIO_ATTR_DRC_EN = BIT(7), /*!< DRC功能开关,使能时需要打开EQ功能 */
AUDIO_ATTR_EQ32BIT_EN = BIT(8), /*!< EQ 32bit输出 */
AUDIO_ATTR_BT_AAC_EN = BIT(9), /*!< 蓝牙AAC解码 */
AUDIO_ATTR_DEC_MUTE_EN = BIT(10), /*!< 当前解码输出mute使能 */
AUDIO_ATTR_UNLIMITED_REPEAT = BIT(11), /*!< 当前解码无限循环播放使能 */
AUDIO_ATTR_DEC_SOLO = BIT(12), /*!< 当前解码强制不走叠音流程 */
AUDIO_ATTR_DIGITAL_FADE_INOUT = BIT(13), /*!< 数字音量淡入淡出,解码开始时使用 */
AUDIO_ATTR_SDRAM_PROMPT = BIT(14), /*!< 播放存储在sdram的提示音 */
AUDIO_ATTR_NO_WAIT_READY = BIT(15), /*!< 当前解码开始时不需等待解码数据缓存 */
};
/**
* @brief 音效附加属性
*/
enum {
AUDIO_EFFECT_SPECTRUM_FFT = BIT(0), /*!< 对音频解码数据进行频谱运算 */
AUDIO_EFFECT_DIGITAL_VOL = BIT(1), /*!< 对音频解码数据进行数字音量调整 */
AUDIO_EFFECT_VIRTUAL_BASS = BIT(2), /*!< 对音频解码数据进行虚拟低音 */
};
/**
* \name 音频编解码请求操作类型
* \{
*/
#define AUDIO_REQ_DEC 0 /*!< 解码请求 */
#define AUDIO_REQ_ENC 1 /*!< 编码请求 */
#define AUDIO_REQ_IOCTL 2 /*!< 命令控制 */
#define AUDIO_DEC_OPEN 0 /*!< 打开解码 */
#define AUDIO_DEC_START 1 /*!< 开始解码 */
#define AUDIO_DEC_PAUSE 2 /*!< 暂停解码 */
#define AUDIO_DEC_STOP 3 /*!< 停止解码 */
#define AUDIO_DEC_FF 4 /*!< 快进 */
#define AUDIO_DEC_FR 5 /*!< 快退 */
#define AUDIO_DEC_GET_BREAKPOINT 6 /*!< 获取断点数据 */
#define AUDIO_DEC_PP 7 /*!< 暂停/播放 */
#define AUDIO_DEC_SET_VOLUME 8 /*!< 设置解码音量 */
#define AUDIO_DEC_DIGITAL_MUTE_SET 9 /*!< 设置当前解码的MUTE状态 */
#define AUDIO_DEC_PS_PARM_SET 10 /*!< 设置变速变调的参数 */
#define AUDIO_DEC_GET_STATUS 11 /*!< 获取当前解码器状态 */
#define AUDIO_DEC_AB_REPEAT_SET 12 /*!< 设置AB点复读播放 */
#define AUDIO_DEC_AB_REPEAT_CLOSE 13 /*!< 关闭AB点复读播放 */
#define AUDIO_DEC_GET_EFFECT_HANDLE 14 /*!< 获取对应音效算法的句柄 */
#define AUDIO_DEC_REPEAT_SET 15 /*!< 设置循环播放 */
#define AUDIO_ENC_OPEN 4 /*!< 打开编码 */
#define AUDIO_ENC_START 5 /*!< 开始编码 */
#define AUDIO_ENC_PAUSE 6 /*!< 暂停编码 */
#define AUDIO_ENC_STOP 7 /*!< 停止编码 */
#define AUDIO_ENC_CLOSE 8 /*!< 关闭解码 */
#define AUDIO_ENC_SET_VOLUME 9 /*!< 设置编码模拟增益 */
#define AUDIO_ENC_GET_STATUS 10 /*!< 获取当前编码器状态 */
#define AUDIO_ENC_PP 11 /*!< 暂停/编码 */
/* \} name */
/**
* @brief 解码虚拟输出时的cbuf读写参数结构体
*/
struct audio_cbuf_t {
void *cbuf; /*!< cbuf句柄 */
void *wr_sem; /*!< 写信号量指针 */
void *rd_sem; /*!< 读信号量指针 */
volatile u16 end; /*!< 读写结束 */
volatile u8 state;/*!< 是否正在解码状态 */
};
/// \cond DO_NOT_DOCUMENT
/**
* @brief 数据流解码信息
*/
struct stream_codec_info {
int time; /*!< 时间 */
int frame_num; /*!< 帧数 */
u32 frame_len; /*!< 帧长度 */
int frame_points; /*!< 帧采样点 */
int sequence_number; /*!< 序列号 */
u32 sample_rate; /*!< 采样率 */
u8 channel; /*!< 通道 */
};
/// \endcond
/**
* @brief 解码断点播放信息结构体
*/
struct audio_dec_breakpoint {
int len; /*!< buf长度 */
u32 fptr; /*!< 断点位置偏移量 */
u8 *data; /*!< 断点数据指针 ape格式断点最大2036字节 */
};
/**
* @brief 获取audio解码器信息
*/
struct audio_finfo {
u8 channel; /*!< 通道 */
u8 name_code; /*!< 名称编码 0:ansi, 1:unicode_le, 2:unicode_be */
int sample_rate; /*!< 采样率 */
int bit_rate; /*!< 比特率 */
int total_time; /*!< 总时间 */
};
/**
* @brief audio命令控制
*/
struct audio_ioctl {
u32 cmd; /*!< 请求操作类型 */
void *priv; /*!< 传入指针 */
};
/**
* @brief 指定位置播放参数
*/
struct audio_dest_time_play_param {
u32 start_time; /*!< 要跳转过去播放的起始时间。单位:ms。设置后跳到start_time开始播放 */
u32 dest_time; /*!< 要跳转过去播放的目标时间。单位:ms。播放到dest_time后如果callback_func存在,则调用callback_func */
u32(*callback_func)(void *priv); /*!< 到达目标时间后回调 */
void *callback_priv; /*!< 回调参数,可以在callback_func回调中实现对应需要的动作 */
};
/**
* @brief 音频虚拟文件操作句柄
*/
struct audio_vfs_ops {
void *(*fopen)(const char *path, const char *mode); /*!< 打开创建路径文件 */
int (*fread)(void *file, void *buf, u32 len); /*!< 读文件 */
int (*fwrite)(void *file, void *buf, u32 len); /*!< 写文件 */
int (*fseek)(void *file, u32 offset, int seek_mode); /*!< 寻址文件 */
int (*ftell)(void *file); /*!< 返回给定流stream的当前文件位置 */
int (*flen)(void *file); /*!< 获取文件长度 */
int (*fclose)(void *file); /*!< 关闭文件 */
};
/// \cond DO_NOT_DOCUMENT
/**
* @brief 解码输出句柄
*/
struct audio_dec_output_ops {
void *(*get_buf)(void *priv, u32 *len); /*!< 获取buf空间 */
void (*put_buf)(void *priv, void *buf, u32 len); /*!< 推送buf空间 */
const struct audio_vfs_ops *vfs_ops; /*!< 音频虚拟文件操作句柄指针 */
};
/**
* @brief audio解码句柄
*/
struct audio_decoder_ops {
const char *name;/*!< 解码文件名称 */
void *(*open)(FILE *file, void *priv,
const struct audio_dec_output_ops *ops, struct audio_dec_breakpoint *); /*!< 打开文件 */
void *(*try_open)(FILE *file, void *priv,
const struct audio_dec_output_ops *ops, struct audio_dec_breakpoint *); /*!< 再次尝试打开 */
int (*get_audio_info)(void *, struct audio_finfo *info); /*!< 获取音频信息 */
int (*get_play_time)(void *); /*!< 获取播放时间 */
int (*fast_forward)(void *, int step_s); /*!< 快进 */
int (*fast_rewind)(void *, int step_s); /*!< 快退 */
int (*get_breakpoint)(void *, struct audio_dec_breakpoint *); /*!< 获取断点 */
int (*start)(void *); /*!< 解码开始 */
int (*close)(void *); /*!< 解码结束 */
int (*channel_switch)(void *, u8); /*!< 通道选择 */
int (*stream_info_scan)(void *, struct stream_codec_info *info, void *data, int len); /*!< 扫描数据流信息 */
int (*stop)(void *); /*!< 解码停止 */
int (*ioctl)(void *, u32 cmd, void *parm); /*!< 解码命令控制 */
};
/// \endcond
/**
* @brief AB点复读设置状态
*/
enum {
AB_REPEAT_STA_NON = 0x00, /*!< 未设置AB点 */
AB_REPEAT_STA_ASTA, /*!< 已设置A点 */
AB_REPEAT_STA_BSTA, /*!< 已设置B点 */
};
/**
* @brief AB点复读模式
*/
enum {
AB_REPEAT_MODE_BP_A = 0x01, /*!< 设置A点参数 */
AB_REPEAT_MODE_BP_B, /*!< 设置B点参数 */
AB_REPEAT_MODE_CUR, /*!< 设置取消AB点参数 */
};
/*
* @brief 循环播放fifo
*/
struct fixphase_repair_obj {
short fifo_buf[18 + 12][32][2]; /*!< 相位修复buf */
};
/*
* @brief 循环播放结构体
*
* @param 每次播放会根据headcut_frame和tailcut_frame来砍掉一些不需要的帧
* @param 在repeat_callback()回调中可以自主控制播放次数,返回非0即结束循环
*/
struct audio_repeat_mode_param {
int flag; /*!< 置1使能 */
int headcut_frame; /*!< 砍掉前面几帧,仅mp3格式有效 */
int tailcut_frame; /*!< 砍掉后面几帧,仅mp3格式有效 */
int (*repeat_callback)(void *); /*!< 循环播放回调,返回0-正常循环;返回非0-结束循环 */
void *callback_priv; /*!< 回调参数指针 */
struct fixphase_repair_obj *repair_buf; /*!< 相位修复buf指针 */
};
/**
* @brief 解码器控制命令
*/
enum {
AUDIO_IOCTRL_CMD_SET_BREAKPOINT_A = 0x08, /*!< 设置复读A点 */
AUDIO_IOCTRL_CMD_SET_BREAKPOINT_B, /*!< 设置复读B点 */
AUDIO_IOCTRL_CMD_SET_BREAKPOINT_MODE, /*!< 设置AB点取消复读模式 */
AUDIO_IOCTRL_CMD_REPEAT_PLAY = 0x90, /*!< 设置循环播放 */
AUDIO_IOCTRL_CMD_SET_DEC_SR = 0x91, /*!< 设置采样率或者码率 */
AUDIO_IOCTRL_CMD_SET_DEST_PLAYPOS = 0x93, /*!< 设置指定位置播放 */
AUDIO_IOCTRL_CMD_GET_PLAYPOS = 0x94, /*!< 获取毫秒级时间 */
};
/**
* @brief 解码请求参数
*/
struct audio_dec_req {
u8 cmd; /*!< 请求操作类型 */
u8 status; /*!< 请求后返回的解码状态 */
u8 channel; /*!< 解码通道数 */
u8 volume; /*!< 模拟音量(0-100) */
u8 digital_volume; /*!< 数字音量初始值(0-100) */
u8 priority; /*!< 解码优先级,暂时没用到 */
u8 speedV; /*!< >80是变快,<80是变慢,建议范围:30到130 */
u16 repeat_num; /*!< 循环播放次数 */
u16 pitchV; /*!< >32768是音调变高,<32768音调变低,建议范围20000到50000 */
u16 attr; /*!< 解码附加属性 */
u16 effect; /*!< 音效附加属性 */
u32 output_buf_len; /*!< 解码buffer大小 */
u32 orig_sr; /*!< 强制变采样前的原始采样率,当混响使能强制变采样时才使用 */
u32 force_sr; /*!< 强制变采样的目标采样率 */
u32 sample_rate; /*!< 实际的解码采样率 */
u32 ff_fr_step; /*!< 快进快退级数 */
u32 total_time; /*!< 解码的总共时长 */
u32 play_time; /*!< 断点恢复时的当前播放时间 */
void *output_buf; /*!< 解码缓存buffer,默认填NULL,由解码器自己实现分配和释放 */
FILE *file; /*!< 需要解码的文件句柄 */
const char *dec_type; /*!< 解码格式 */
const char *sample_source; /*!< 播放源,支持"dac","iis0","iis1" */
struct audio_dec_breakpoint *bp; /*!< 断点播放信息句柄 */
const struct audio_vfs_ops *vfs_ops; /*!< 虚拟文件操作句柄 */
void *eq_attr; /*!< eq属性设置 */
void *eq_hdl; /*!< 预先申请好的的eq句柄 */
struct audio_cbuf_t *virtual_audio; /*!< 虚拟解码句柄,供外部读写使用 */
int (*dec_callback)(u8 *buf, u32 len, u32 sample_rate, u8 ch_num); /*!< 解码后的PCM数据回调 */
int (*dec_sync)(void *priv, u32 data_size, u16 *in_rate, u16 *out_rate); /*!< 解码对端采样率同步,常用于蓝牙解码 */
void *get_hdl; /*!< 获取私有句柄 */
void *sync_priv; /*!< 解码对端采样率同步私有指针 */
};
/**
* @brief 编码请求参数
*/
struct audio_enc_req {
u8 cmd; /*!< 请求操作类型 */
u8 status; /*!< 编码器状态 */
u8 channel; /*!< 同时编码的通道数 */
u8 channel_bit_map; /*!< ADC通道选择 */
u8 volume; /*!< ADC增益(0-100),编码过程中可以通过AUDIO_ENC_SET_VOLUME动态调整增益 */
u8 priority; /*!< 编码优先级,暂时没用到 */
u8 use_vad : 2; /*!< 0:关闭vad功能 1:使用旧vad算法 2:使用JL新vad算法 */
u8 vad_auto_refresh : 1; /*!< 是否自动刷新VAD状态,赋值1表示SPEAK_START->SPEAK_STOP- >SPEAK_START->SPEAK_STOP->....循环 */
u8 direct2dac : 1; /*!< AUDIO_AD直通DAC功能 */
u8 high_gain : 1; /*!< 直通DAC时是否打开模拟增益调整 */
u8 amr_src : 1; /*!< amr编码时的强制16k变采样为8kpcm数据,因为amr编码器暂时只支持8k编码 */
u8 aec_enable : 1; /*!< AEC回声消除功能开关,常用于蓝牙通话 */
u8 ch_data_exchange : 1; /*!< 用于AEC差分回采时和MIC的通道数据交换 */
u8 no_header : 1; /*!< 用于opus编码时是否需要添加头部格式 */
u8 vir_data_wait : 1; /*!< 虚拟编码时是否允许丢失数据 */
u8 no_auto_start : 1; /*!< 请求AUDIO_ENC_OPEN时不自动运行编码器,需要主动调用AUDIO_ENC_START */
u8 sample_depth : 3; /*!< 采样深度16bit或者24bit */
u8 dns_enable : 1; /*!< dns降噪算法 0:不使用 1:使用 */
u8 wait_sem : 1; /*!< 编码器数据输出时如果缓存已满即等待信号量 */
u16 vad_start_threshold; /*!< VAD连续检测到声音的阈值,表示开始说话,回调AUDIO_SERVER_EVENT_SPEAK_START,单位ms,填0使用库内默认值 */
u16 vad_stop_threshold; /*!< VAD连续检测到静音的阈值, 表示停止说话,回调AUDIO_SERVER_EVENT_SPEAK_STOP,单位ms,填0使用库内默认值 */
u16 frame_size; /*!< 编码器输出的每一帧帧长大小,只有pcm格式编码时才有效 */
u16 frame_head_reserve_len; /*!< 编码输出的帧预留头部的大小 */
u32 bitrate; /*!< 编码码率大小 */
u32 delay_ms; /*!< 当编码器读写不到数据后的延时等待 */
u32 output_buf_len; /*!< 编码buffer大小 */
u32 sample_rate; /*!< 编码采样率 */
u32 msec; /*!< 编码时长,填0表示一直编码,单位ms,编码结束会回调AUDIO_SERVER_EVENT_END消息 */
FILE *file; /*!< 编码输出文件句柄 */
u8 *output_buf; /*!< 编码buffer,默认填NULL,由编码器自动分配和释放资源 */
const char *format; /*!< 编码格式 */
const char *sample_source; /*!< 采样源,支持"mic","linein","plnk0","plnk1","virtual","iis0","iis1","spdif" */
const struct audio_vfs_ops *vfs_ops; /*!< 虚拟文件操作句柄 */
int(*read_input)(u8 *buf, u32 len); /*!< 用于虚拟采样源"virtual"编码时的数据读取操作读输入buf及其长度,返回负值自动停止编码并回调编码结束的事件 */
void *aec_attr; /*!< AEC回声消除算法配置参数 */
};
/**
* @brief audio服务请求参数
*/
union audio_req {
struct audio_dec_req dec; /*!< 解码请求 */
struct audio_enc_req enc; /*!< 编码请求 */
struct audio_ioctl ioctl; /*!< 命令控制 */
struct audio_finfo info; /*!< 音频信息 */
};
/// \cond DO_NOT_DOCUMENT
struct audio_package_ops {
const char *name; /*!< 文件名称 */
const char *data_fmt; /*!< 数据格式 */
void *(*open)(void *file, const struct audio_vfs_ops *, struct audio_enc_req *); /*!< 打开文件编码 */
int (*start)(void *file, const struct audio_vfs_ops *vfs_ops); /*!< 开始数据包处理 */
int (*input)(void *file, u8 *data, int len, const struct audio_vfs_ops *vfs_ops); /*!< 输入数据 */
int (*close)(void *file, const struct audio_vfs_ops *vfs_ops); /*!< 关闭数据处理 */
};
struct audio_effect_ops {
u16 effect;
u8 pretreatment;
void *(*open)(void *priv, void *param);
int (*run)(void *priv, s16 *data, int len, int sample_rate);
int (*close)(void *priv);
};
#define REGISTER_AUDIO_EFFECT(ops) \
const struct audio_effect_ops ops SEC_USED(.audio_effect)
extern const struct audio_effect_ops audio_effect_begin[];
extern const struct audio_effect_ops audio_effect_end[];
#define list_for_each_audio_effect(p) \
for (p = audio_effect_begin; p < audio_effect_end; p++)
#define REGISTER_AUDIO_DECODER(ops) \
const struct audio_decoder_ops ops SEC_USED(.audio_decoder)
extern const struct audio_decoder_ops audio_decoder_begin[];
extern const struct audio_decoder_ops audio_decoder_end[];
#define list_for_each_audio_decoder(p) \
for (p = audio_decoder_begin; p < audio_decoder_end; p++)
#define REGISTER_AUDIO_PACKAGE(ops) \
const struct audio_package_ops ops SEC_USED(.audio_package)
extern const struct audio_package_ops audio_package_begin[];
extern const struct audio_package_ops audio_package_end[];
#define list_for_each_audio_package(p) \
for (p = audio_package_begin; p < audio_package_end; p++)
/// \endcond
#endif