Linux frameworks 音视频架构音频部分
源码文件目录树形结构
linux_audio_framework/ ├── include/ # 头文件目录 │ ├── audio_stream.h # 音频流主要接口 │ ├── media_common.h # 媒体通用定义 │ ├── sub_common.h # 字幕通用定义 │ ├── vdisp.h # 视频显示定义 ├── src/ # 源码目录 │ ├── audio_stream.c # 音频流实现 ├── test/ # 测试目录 │ ├── test_main.c # 主测试程序
audio_stream.h
#ifndef __AUDIO_STREAM_H_ // 防止头文件重复包含的预处理器指令
#define __AUDIO_STREAM_H_ // 定义头文件保护宏
#ifdef __cplusplus // 如果使用 C++ 编译器编译
#if __cplusplus // 检查是否在 C++ 环境中
extern "C" { // 使用 C 语言链接规范,确保 C++ 中能正确链接 C 函数
#endif
#endif
#include <media_common.h> // 包含媒体通用定义头文件
typedef void *astream_handle; // 定义音频流句柄类型为 void 指针,实现数据隐藏设计模式
typedef enum as_port_type { // 定义音频端口类型枚举AS_PORT_PCM = 0, // PCM 音频端口AS_PORT_CODEC = 1, // 编解码器音频端口
} as_port_type_e;
// 函数声明区域
// 设计模式分析: 使用工厂模式创建音频流对象,提供统一的创建接口
// 性能分析: 轻量级创建函数,内存分配和初始化操作
astream_handle audio_stream_creat(void); // 创建默认音频流
astream_handle audio_stream_creat_by_name(char *name); // 通过名称创建音频流
int audio_stream_select_encode_channel(astream_handle hdl, int channel_map); // 选择编码通道
void audio_stream_release(astream_handle hdl); // 释放音频流资源
int audio_stream_set_coding_type(astream_handle hdl, audio_encoder_t coding); // 设置编码类型
int audio_stream_set_prio(astream_handle hdl, int prio); // 设置优先级
int audio_stream_set_channels(astream_handle hdl, int channels); // 设置声道数
int audio_stream_set_aec(astream_handle hdl, int on); // 设置回声消除
int audio_stream_set_anr(astream_handle hdl, int on); // 设置噪声抑制
int audio_stream_set_agc(astream_handle hdl, int on); // 设置自动增益控制
int audio_stream_set_sample_width(astream_handle hdl, int bits); // 设置采样位宽
int audio_stream_set_sample_rate(astream_handle hdl, int rate); // 设置采样率
signed long long audio_stream_get_time(astream_handle hdl); // 获取音频流时间
int audio_stream_set_private_para(astream_handle hdl, audio_private_para_t *para); // 设置私有参数
int audio_stream_get_sample_rate(astream_handle hdl); // 获取采样率
int audio_stream_get_sample_width(astream_handle hdl); // 获取采样位宽
int audio_stream_get_channels(astream_handle hdl); // 获取声道数
audio_encoder_t audio_stream_get_coding_type(astream_handle hdl); // 获取编码类型
int audio_stream_set_mute(astream_handle hdl, int mute_on); // 设置静音
int audio_stream_start(astream_handle hdl); // 启动音频流
int audio_stream_stop(astream_handle hdl); // 停止音频流
// 设计模式分析: 整个模块采用外观模式(Facade Pattern),提供简化的高级接口隐藏底层复杂音频处理细节
// 性能分析: 函数接口设计为轻量级调用,实际音频处理在底层实现,避免在应用层进行复杂计算
#ifdef __cplusplus // 如果使用 C++ 编译器编译
#if __cplusplus // 检查是否在 C++ 环境中
} // 结束 extern "C" 块
#endif
#endif
#endif // 结束头文件保护media_common.h
#ifndef __MEDIA_COMMON_H__ // 防止头文件重复包含的预处理器指令
#define __MEDIA_COMMON_H__ // 定义头文件保护宏
#include "sub_common.h" // 包含字幕通用定义头文件
#include <stdint.h> // 包含标准整数类型头文件
#include <stddef.h> // 包含标准定义头文件,提供size_t等
#include "vdisp.h" // 包含视频显示相关头文件
#define MAX_ROTATE_CHANNEL 4 // 定义最大旋转通道数为4
// 设计模式分析: 使用枚举类型定义各种类型,实现类型安全的状态模式
// 性能分析: 枚举类型编译时确定,运行时高效
typedef enum frame_type { // 定义帧类型枚举VS_INVAILD_FRAME, // 无效帧VS_VIDEO_RAW_FRAME, // 视频原始帧VS_VIDEO_ROT_FRAME, // 视频旋转帧VS_AUDIO_FRAME, // 音频帧VS_IMAGE_FRAME, // 图像帧VS_SUBTITLE_FRAME, // 字幕帧VS_IMAGE_ROT_FRAME, // 图像旋转帧VS_OTHER_FRAME // 其他帧类型
} frame_type_t;
typedef enum stream_type { // 定义流类型枚举STREAM_TYPE_UNKNOWN = 0, // 未知流类型STREAM_TYPE_AUDIO, // 音频流STREAM_TYPE_VIDEO, // 视频流STREAM_TYPE_SUBTITLE, // 字幕流
} stream_type_e;
typedef enum muxer_type { // 定义复用器类型枚举MUXER_TYPE_UNKNOWN, // 未知复用器MUXER_TYPE_RAW, // 原始数据复用器MUXER_TYPE_TS, // TS流复用器MUXER_TYPE_MP3, // MP3复用器MUXER_TYPE_WAV, // WAV复用器
} muxer_type_e;
typedef enum video_codec { // 定义视频编解码器枚举VIDEO_CODEC_UNKNOWN = 0, // 未知视频编解码器VIDEO_CODEC_H264, // H264编解码器
} video_codec_e;
typedef enum audio_codec { // 定义音频编解码器枚举AUDIO_CODEC_UNKNOWN = 0, // 未知音频编解码器AUDIO_CODEC_PCM, // PCM编解码器AUDIO_CODEC_AAC, // AAC编解码器AUDIO_CODEC_G729, // G729编解码器AUDIO_CODEC_G711A, // G711A编解码器AUDIO_CODEC_G711U, // G711U编解码器AUDIO_CODEC_G726, // G726编解码器AUDIO_CODEC_G726LE, // G726小端编解码器
} audio_codec_e;
typedef enum cb_port { // 定义回调端口枚举CB_VCAM_OUT, // 虚拟相机输出端口CB_VROT_OUT, // 视频旋转输出端口CB_OTHER_PORT // 其他端口
} cb_port_e;
typedef enum watermark_type { // 定义水印类型枚举WM_TYPE_FOR_RECORDER, // 用于录制器的水印WM_TYPE_FOR_PHOTO // 用于照片的水印
} watermark_type_e;
typedef enum _audio_g726_mode { // 定义G726音频模式枚举AUDIO_G726MODE_UNUSED = 0, // 未使用的G726模式AUDIO_G726MODE_16K = 2, // 16K比特率模式AUDIO_G726MODE_24K = 3, // 24K比特率模式AUDIO_G726MODE_32K = 4, // 32K比特率模式AUDIO_G726MODE_40K = 5, // 40K比特率模式AUDIO_G726MODE_M32K = 6, // 32K ADPCM模式AUDIO_G726MODE_M40K = 7, // 40K ADPCM模式AUDIO_G726MODE_INVALID = 0xFFFFFFFF // 无效模式
} audio_g726_mode_e;
// 设计模式分析: 使用结构体封装相关数据,实现数据对象模式
// 性能分析: 结构体布局优化,减少内存碎片
typedef struct _audio_private_para { // 定义音频私有参数结构体audio_g726_mode_e g726_mode; // G726编码模式int32_t en_in_data_len; // 编码输入数据长度
} audio_private_para_t;
/*** struct video_isp_info - VISS的EXIF信息结构* @valid: 1: ISP信息有效 0: ISP信息无效* @exposure_time: 曝光时间(秒) * 10000* @shutter_speed: 曝光时间(秒) * 10000 * @aperture: 光圈值 fno2.8 = 280* @brightness: 亮度值 LV = [0, 20], 0: 星光, 20: 日光* @exposure_bias: 曝光补偿(也称为EV偏置)* @iso_speed: ISO = 增益 * 100* @flash: 闪光灯状态寄存器值* @illu_id: 自动白平衡色温ID* 0: HOR(2100K)* 1: A(2900K)* 2: TL84(4000K)* 3: CWF(4100K)* 4: D50(5000K)* 5: D65(6500K)* 6: D75(7500K)* @back_score: 背光评分 = [0, 100] 百分比* @res: 保留信息* @res[0]: 目标亮度* @res[1]: 背景亮度* @res[2]: 平均亮度* @res[3]: 原始亮度* @res[4]: 最终亮度*/
typedef struct video_isp_info { // 定义视频ISP信息结构体int valid; // ISP信息有效性标志unsigned int exposure_time; // 曝光时间unsigned int shutter_speed; // 快门速度unsigned int aperture; // 光圈值unsigned int brightness; // 亮度值unsigned int exposure_bias; // 曝光补偿unsigned int iso_speed; // ISO感光度unsigned int flash; // 闪光灯状态unsigned int illu_id; // 白平衡色温IDunsigned int back_score; // 背光评分unsigned int res[16]; // 保留字段数组
} video_isp_info_t;
typedef struct video_frame_info { // 定义视频帧信息结构体int color_fmt; // 颜色格式int width; // 帧宽度int height; // 帧高度int stride; // 行跨度(步长)int sliceHeight; // 切片高度int planar; // 平面格式标志unsigned char *addr[3]; // 多平面数据地址数组(YUV等)int size[3]; // 多平面数据大小数组long long time_stamp; // 时间戳video_isp_info_t isp_info; // ISP信息
} video_frame_info_t;
typedef struct audio_frame_info { // 定义音频帧信息结构体int sample_rate; // 采样率char *addr; // 数据地址char size; // 数据大小long long time_stamp; // 时间戳
} audio_frame_info_t;
typedef struct sub_style { // 定义字幕样式结构体int has_style_flag; // 样式有效标志,0或1char *name; // 样式名称av_sub_font_style_e font_style; // 字体样式int fontsize; // 字体大小int primarycolour; // 字幕首选颜色,&HBBGGRR格式int secondarycolour; // 卡拉OK中使用int outlinecolour; // 边框颜色int backcolour; // 阴影颜色font_bold_flag_e bold; // 粗体标志,0关闭,-1打开font_italic_flag_e italic; // 斜体标志,0关闭,-1打开font_underline_flag_e underline; // 下划线标志,0关闭,-1打开font_strikeout_flag_e strikeout; // 删除线标志,0关闭,-1打开float scalex; // 水平缩放,默认100%float scaley; // 垂直缩放,默认100%int spacing; // 字间距int angle; // 旋转角度int borderstyle; // 边框样式float outline; // 边框宽度1-4float shadow; // 阴影距离0-4av_sub_alignment_e alignment; // 对齐方式int marginl; // 左边距,左对齐时无效,值:0 ~ playResXint marginr; // 右边距,右对齐时无效,值:0 ~ playResYint marginv; // 字幕高度,底对齐时到底部距离,顶对齐时到顶部距离,居中对齐时无效int alphalevel; // 透明度级别av_sub_encode_type_e encoding; // 编码样式
} sub_style_t;
typedef struct sub_event { // 定义字幕事件结构体int dialogue_marginl; // 对话左边距,为0时使用样式左边距int dialogue_marginr; // 对话右边距,为0时使用样式右边距int dialogue_marginv; // 对话垂直边距,为0时使用样式垂直边距av_sub_effect_type_e sub_effect_type; // 字幕特效类型charset_encode_e charset_type; // 字符集编码类型int effectstartx; // 特效起始X坐标int effectendx; // 特效结束X坐标int effectstarty; // 特效起始Y坐标int effectendy; // 特效结束Y坐标int effectdelaytime; // 特效延迟时间av_subtitle_type_e type; // 字幕类型int datasize; // 数据大小char *pdata; // 数据指针
} sub_data_t;
typedef struct sub_common { // 定义字幕通用信息结构体int index; // 索引int resx; // 屏幕宽度int resy; // 屏幕高度long long start_disp_time; // 开始显示时间long long end_disp_time; // 结束显示时间
} sub_common_t;
typedef struct subtitle_frame_info { // 定义字幕帧信息结构体sub_common_t comm_info; // 通用信息sub_style_t style; // 样式信息sub_data_t data; // 数据信息
} subtitle_frame_info_t;
// 设计模式分析: 使用联合体实现变体记录模式,节省内存空间
// 性能分析: 联合体减少内存占用,提高缓存效率
typedef struct frame { // 定义通用帧结构体stream_type_e type; // 流类型union { // 联合体,存储不同类型的帧信息video_frame_info_t video; // 视频帧信息audio_frame_info_t audio; // 音频帧信息subtitle_frame_info_t subtitle; // 字幕帧信息} info;void *priv_data; // 私有数据指针void *header; // 头部信息指针
} frame_t;
typedef struct audio_stream_info { // 定义音频流信息结构体audio_codec_e codec; // 音频编解码器int samplerate; // 采样率int channels; // 声道数int bits_per_sample; // 每样本位数char *text; // 文本描述
} audio_stream_info_t;
typedef struct video_stream_info { // 定义视频流信息结构体video_codec_e codec; // 视频编解码器int width; // 宽度int height; // 高度char *text; // 文本描述
} video_stream_info_t;
typedef struct avstream_info { // 定义音视频流信息结构体muxer_type_e muxer_type; // 复用器类型int astream_num; // 音频流数量int vstream_num; // 视频流数量int64_t size; // 流大小audio_stream_info_t astream_info; // 音频流信息video_stream_info_t vstream_info; // 视频流信息
} avstream_info_t;
typedef enum { // 定义音视频流帧类型枚举VS_VIDEO_NVALID, // 无效视频帧VS_VIDEO_PPS, // PPS帧VS_VIDEO_I_FRAME, // I帧VS_VIDEO_P_FRAME, // P帧VS_VIDEO_B_FRAME, // B帧VS_OTHER_MEDIA, // 其他媒体类型
} avstream_frame_type_e;
typedef struct avstream { // 定义音视频流结构体stream_type_e type; // 流类型uint8_t *data; // 数据指针int data_size; // 数据大小int64_t timestamp; // 时间戳avstream_frame_type_e frame_type; // 帧类型
} avstream_t;
// 设计模式分析: 使用回调函数指针,实现观察者模式和策略模式
// 性能分析: 回调机制减少模块间耦合,提高系统灵活性
typedef struct app_frame_cb { // 定义应用帧回调结构体frame_type_t type; // 帧类型void *app_data; // 应用数据指针int(*buf_handle)(void *app_data, frame_t *pframe); // 缓冲区处理回调函数
} app_frame_cb_t;
typedef struct app_port_cb { // 定义应用端口回调结构体cb_port_e type; // 端口类型void *app_data; // 应用数据指针int(*buf_handle)(void *app_data, frame_t *pframe); // 缓冲区处理回调函数
} app_port_filter_t;
typedef struct app_stream_cb { // 定义应用流回调结构体void *app_data; // 应用数据指针int (*buf_handle)(void *, avstream_t *); // 流处理回调函数
} app_stream_cb_t;
typedef int (*picture_data_cb)(void *pbuff, int data_len, void *userdata); // 定义图片数据回调函数类型
typedef enum AUDIO_ENCODER { // 定义音频编码器枚举AUDIO_ENCODER_INVALID = 0, // 无效编码器AUDIO_ENCODER_AAC, // AAC编码器AUDIO_ENCODER_AAC_RAW = AUDIO_ENCODER_AAC, // AAC原始格式AUDIO_ENCODER_AAC_MP4ADTS, // AAC MP4 ADTS格式AUDIO_ENCODER_ADPCM, // ADPCM编码器AUDIO_ENCODER_PCM, // PCM编码器AUDIO_ENCODER_G729, // G729编码器AUDIO_ENCODER_PCM_ALAW, // PCM A律编码器AUDIO_ENCODER_PCM_MULAW, // PCM μ律编码器AUDIO_ENCODER_ADPCM_G726, // ADPCM G726编码器AUDIO_ENCODER_ADPCM_G726LE, // ADPCM G726小端编码器AUDIO_ENCODER_UNSUPPORT, // 不支持的编码器AUDIO_ENCODER_NONE = 0x7fff // 无编码器
} audio_encoder_t;
typedef struct win_rect { // 定义窗口矩形结构体int x; // X坐标int y; // Y坐标int width; // 宽度int height; // 高度
} win_rect_t;
typedef struct colli_file_cfg { // 定义碰撞文件配置结构体int cache_time; // 碰撞发生前保存到缓存的时间(秒)int total_time; // 碰撞文件总时间(秒)char *filename; // 保存的文件名app_stream_cb_t cb; // 流回调int (*cb_file_save_event)(void *hdl, char *file_name); // 文件保存事件回调
} colli_file_cfg_t;
typedef enum recorder_cache_tag { // 定义录制器缓存标签枚举RECORDER_CACHE_NOT_USE, // 不使用缓存RECORDER_CACHE_USE, // 使用缓存
} recorder_cache_e;
typedef struct channel_rot_para { // 定义通道旋转参数结构体vdisp_rotate_mode_e rot; // 旋转模式win_rect_t src_rect; // 源矩形区域win_rect_t dst_rect; // 目标矩形区域
} channel_rot_para;
typedef struct multi_ch_rot_para { // 定义多通道旋转参数结构体int channel_num; // 通道数量channel_rot_para para[MAX_ROTATE_CHANNEL]; // 旋转参数数组
} multi_ch_rot_para_t;
typedef enum recorder_type { // 定义录制器类型枚举RECORDER_TYPE_NORMAL, // 正常速度录制器RECORDER_TYPE_TIME_LAG, // 延时摄影录制器
} recorder_type_e;
typedef struct rec_time_lag_para { // 定义延时录制参数结构体int interval; // 编码帧采样间隔int play_framerate; // 播放帧率
} rec_time_lag_para_t;
// 函数声明区域
// 设计模式分析: 提供模块初始化和反初始化接口,实现模块化设计模式
// 性能分析: 初始化函数负责资源分配,反初始化函数负责资源释放,确保资源管理
long media_init(void); // 媒体模块初始化函数
void media_deinit(void); // 媒体模块反初始化函数
int media_get_pts(int64_t *pts); // 获取PTS(显示时间戳)函数
int media_sync_pts(int64_t ptsbase); // 同步PTS函数
#endif /* __MEDIA_COMMON_H__ */ // 结束头文件保护
sub_common.h
#ifndef __SUB_COMMON_H__ // 防止头文件重复包含的预处理器指令
#define __SUB_COMMON_H__ // 定义头文件保护宏
// 设计模式分析: 使用枚举类型定义字幕相关常量,实现类型安全的状态模式和策略模式
// 性能分析: 枚举类型编译时确定,运行时高效,内存占用小
/* 字幕特效类型枚举 - 定义字幕显示时的动画效果类型 */
typedef enum SUB_EFFECT_TYPE { // 定义字幕特效类型枚举SUB_EFFECT_TYPE_NONE = 0, // 无特效SUB_EFFECT_TYPE_SCROLL_UP, // 向上滚动特效SUB_EFFECT_TYPE_SCROLL_DOWN, // 向下滚动特效SUB_EFFECT_TYPE_BANNER_LTOR, /* 从左到右移动的横幅特效 */ SUB_EFFECT_TYPE_BANNER_RTOL, /* 从右到左移动的横幅特效 */
/* SUB_EFFECT_TYPE_KARAOKE, */ /* 卡拉OK特效(已注释) */
} av_sub_effect_type_e;
/* 字幕对齐方式枚举 - 定义字幕在屏幕上的对齐位置 */
typedef enum SUB_ALIGNMENT { // 定义字幕对齐方式枚举SUB_ALIGNMENT_NONE = 0, // 无对齐(默认)SUB_ALIGNMENT_BOT_LEFT, // 底部左对齐SUB_ALIGNMENT_BOT_CENTER, // 底部居中对齐SUB_ALIGNMENT_BOT_RIGHT, // 底部右对齐SUB_ALIGNMENT_MID_LEFT, // 中部左对齐SUB_ALIGNMENT_MID_CENTER, // 中部居中对齐SUB_ALIGNMENT_MID_RIGHT, // 中部右对齐SUB_ALIGNMENT_TOP_LEFT, // 顶部左对齐SUB_ALIGNMENT_TOP_CENTER, // 顶部居中对齐SUB_ALIGNMENT_TOP_RIGHT, // 顶部右对齐
} av_sub_alignment_e;
/* 字幕编码类型枚举 - 定义字幕文本的字符编码格式 */
typedef enum SUB_ENCODINGTYPE { // 定义字幕编码类型枚举SUB_ENCODE_TYPE_DEFAULT = 0, // 默认编码类型SUB_ENCODE_TYPE_ANSI, /* 英文ANSI编码 0 */SUB_ENCODE_TYPE_BITMAP, // 位图编码(图形字幕)SUB_ENCODE_TYPE_GB2312, /* 简体中文 GB2312 编码 134 */SUB_ENCODE_TYPE_BIG5, /* 繁体中文 Big5 编码 136 */SUB_ENCODE_TYPE_GBK, /* 中文字符 GBK 编码 */SUB_ENCODE_TYPE_UTF8, // UTF-8 编码SUB_ENCODE_TYPE_UTF16, // UTF-16 编码SUB_ENCODE_TYPE_UTF32, // UTF-32 编码SUB_ENCODE_TYPE_UNICODE, // Unicode 编码
} av_sub_encode_type_e;
/* 字幕字体样式枚举 - 定义字幕使用的字体类型 */
typedef enum SUB_FONT_STYLE { // 定义字幕字体样式枚举SUB_FONT_STYLE_DEFAULT = 0, // 默认字体样式SUB_FONT_STYLE_ARIAL, // Arial 字体SUB_FONT_STYLE_GBK_20, // GBK 20号字体SUB_FONT_STYLE_MIC_YAHEI, // 微软雅黑字体
} av_sub_font_style_e;
/* 字体粗体效果枚举 - 定义字体是否加粗显示 */
typedef enum SUB_FONT_EFFECT_BOLD { // 定义字体粗体效果枚举SUB_FONT_BOLD_OFF = 0, // 关闭粗体效果SUB_FONT_BOLD_ON, // 开启粗体效果
} font_bold_flag_e;
/* 字体斜体效果枚举 - 定义字体是否斜体显示 */
typedef enum SUB_FONT_EFFECT_ITALIC { // 定义字体斜体效果枚举SUB_FONT_ITALIC_OFF = 0, // 关闭斜体效果SUB_FONT_ITALIC_ON, // 开启斜体效果
} font_italic_flag_e;
/* 字体下划线效果枚举 - 定义字体是否添加下划线 */
typedef enum SUB_FONT_EFFECT_UNDERLINE { // 定义字体下划线效果枚举SUB_FONT_UNDERLINE_OFF = 0, // 关闭下划线效果SUB_FONT_UNDERLINE_ON, // 开启下划线效果
} font_underline_flag_e;
/* 字体删除线效果枚举 - 定义字体是否添加删除线 */
typedef enum SUB_FONT_EFFECT_STRIKEOUT { // 定义字体删除线效果枚举SUB_FONT_STRIKEOUT_OFF = 0, // 关闭删除线效果SUB_FONT_STRIKEOUT_ON, // 开启删除线效果
} font_strikeout_flag_e;
/* 字幕类型枚举 - 定义字幕的基本类型 */
typedef enum av_subtitle_type { // 定义字幕类型枚举SUB_NONE, // 无字幕SUB_TEXT, // 文本字幕SUB_BITMAP, // 位图字幕(图形字幕)
} av_subtitle_type_e;
/* 字符集编码类型枚举 - 定义字符编码标准 */
typedef enum charset_encode_type { // 定义字符集编码类型枚举IS_CHARSET_ENCODE_DEFAULT = -1, // 默认字符集编码IS_CHARSET_ENCODE_UTF_8 = 0, // UTF-8 编码IS_CHARSET_ENCODE_GBK = 1, // GBK 编码IS_CHARSET_ENCODE_ASCII, // ASCII 编码IS_CHARSET_ENCODE_GBK2312, // GBK2312 编码IS_CHARSET_ENCODE_UNICODE, // Unicode 编码IS_CHARSET_ENCODE_BIG_5, // Big5 编码(繁体中文)IS_CHARSET_ENCODE_GB18030, // GB18030 编码(中文国家标准)
} charset_encode_e;
#endif /* __ASS_COMMON_H__ */ // 结束头文件保护(注意: 宏名称与开头不匹配,应为__SUB_COMMON_H__)
vdisp.h
#ifndef __VDISP_H__ // 防止头文件重复包含的预处理器指令
#define __VDISP_H__ // 定义头文件保护宏
// 设计模式分析: 使用枚举类型定义视频显示相关常量,实现状态模式和策略模式
// 性能分析: 枚举类型编译时确定,运行时高效,提供类型安全的配置选项
/* 视频显示旋转模式枚举 - 定义视频图像的旋转和翻转变换操作 */
typedef enum vdisp_rotate_mode { // 定义视频显示旋转模式枚举VDISP_ROTATE_NONE = 0, // 无旋转,原始方向VDISP_ROTATE_90 = 1, // 顺时针旋转90度VDISP_ROTATE_180 = 2, // 旋转180度VDISP_ROTATE_270 = 3, // 顺时针旋转270度(逆时针90度)VDISP_FLIP_H = 4, // 水平翻转(镜像)VDISP_FLIP_H_ROT_90 = 5, // 水平翻转后旋转90度VDISP_FLIP_V = 6, // 垂直翻转VDISP_FLIP_V_ROT_90 = 7, // 垂直翻转后旋转90度
/* 软件旋转模式 - 通过软件算法实现的旋转,性能较低但兼容性好 */VDISP_SW_ROTATE_NONE = 20, // 软件无旋转VDISP_SW_ROTATE_90 = 21, // 软件顺时针旋转90度VDISP_SW_ROTATE_180 = 22, // 软件旋转180度VDISP_SW_ROTATE_270 = 23, // 软件顺时针旋转270度VDISP_SW_FLIP_H = 24, // 软件水平翻转VDISP_SW_FLIP_H_ROT_90 = 25, // 软件水平翻转后旋转90度VDISP_SW_FLIP_V = 26, // 软件垂直翻转VDISP_SW_FLIP_V_ROT_90 = 27, // 软件垂直翻转后旋转90度
VDISP_MULTI_CHANNEL = 0xff, // 多通道显示模式
} vdisp_rotate_mode_e;
// 设计模式分析: 显示模式枚举实现策略模式,允许运行时选择不同的显示策略
// 性能分析: 硬件加速模式(0-7)性能高,软件模式(20-27)性能低但兼容性好
/* 视频显示模式枚举 - 定义视频在显示窗口中的缩放和适配方式 */
typedef enum vdisp_mode { // 定义视频显示模式枚举/* 在窗口中以视频原始尺寸显示,不会溢出窗口 */VDISP_WINDOW_ORIGINAL, // 原始尺寸模式/* 按视频比例缩放到全屏,视频显示正常比例 */VDISP_WINDOW_FULL_SCREEN_VIDEO_RATIO, // 全屏保持视频比例模式/* 按屏幕比例缩放到全屏,视频可能会变形 */VDISP_WINDOW_FULL_SCREEN_SCREEN_RATIO, // 全屏拉伸模式(可能变形)/* 强制以4:3比例显示,视频可能会变形 */VDISP_WINDOW_4R3MODE, // 4:3强制比例模式/* 强制以16:9比例显示,视频可能会变形 */VDISP_WINDOW_16R9MODE, // 16:9强制比例模式/* 用于裁剪视频的黑边 */VDISP_WINDOW_CUTEDGE, // 裁剪黑边模式/* 用户自定义模式 */VDISP_WINDOW_USERDEF, // 用户自定义模式
} vdisp_mode_e;
// 设计模式分析: 显示模式枚举实现策略模式,支持多种显示适配算法
// 性能分析: 不同模式对CPU/GPU负载不同,原始尺寸模式性能最佳,缩放模式需要额外计算
/* 视频图层层级枚举 - 定义视频层在显示堆叠中的位置 */
typedef enum video_layer_level { // 定义视频图层层级枚举VIDEO_LAYER_TOP = 0, // 顶层显示(覆盖其他图层)VIDEO_LAYER_BOTTOM, // 底层显示(被其他图层覆盖)VIDEO_LAYER_NONE = 0x7fff // 无图层或禁用图层
} video_layer_level_t;
// 设计模式分析: 图层层级实现组合模式,支持多层视频合成显示
// 性能分析: 图层合成需要额外的内存带宽和GPU处理,但提供灵活的显示控制
/* 缩放模式枚举 - 定义视频缩放的执行方式 */
typedef enum scale_mode { // 定义缩放模式枚举SCALE_MODE_ONLINE, // 在线缩放(实时处理)SCALE_MODE_OFFLINE, // 离线缩放(预处理)
} scale_mode_e;
// 设计模式分析: 缩放模式实现策略模式,允许选择不同的缩放处理策略
// 性能分析: 在线缩放增加实时处理负载,离线缩放预处理消耗存储但运行时性能更好
#endif /* __VDISP_H__ */ // 结束头文件保护
audio_stream.c
#define DBG_LEVEL DBG_WARNING // 设置调试级别为警告级别
#define LOG_TAG "audio_stream" // 定义日志标签为"audio_stream"
#include <oscl.h> // 包含操作系统抽象层头文件
#include <base_component.h> // 包含基础组件头文件
#include "omx_api.h" // 包含OpenMAX IL API头文件
#include "audio_stream.h" // 包含音频流头文件
#include "av_media_type.h" // 包含音视频媒体类型头文件
#include "omx_vendor_lb.h" // 包含厂商特定的OpenMAX扩展头文件
#define AUDIO_DEFAULT_RATE 48000 // 定义默认音频采样率为48kHz
#define AUDIO_DEFAULT_CHANNELS 2 // 定义默认音频声道数为2(立体声)
#define AUDIO_DEFAULT_FMT_WIDTH 16 // 定义默认音频采样位宽为16位
#define AUDIO_DEFAULT_CODINGTYPE AUDIO_ENCODER_AAC // 定义默认音频编码类型为AAC
// 设计模式分析: 使用状态枚举实现状态模式,管理音频流生命周期
// 性能分析: 状态机模式确保状态转换的确定性和高效性
typedef enum astream_state { // 定义音频流状态枚举AS_STATE_ERR = 0, // 错误状态AS_STATE_INIT, // 初始化状态AS_STATE_START, // 启动状态AS_STATE_ENCODE, // 编码状态
} astream_state_e;
// 设计模式分析: 组合模式,将组件信息组合成音频源信息
typedef struct asrc_info { // 定义音频源信息结构体comp_info_t al_comp; // 音频组件信息port_info_t *aout; // 音频输出端口指针
} asrc_info_t;
// 设计模式分析: 组合模式,将组件信息组合成音频编码器信息
typedef struct aenc_info { // 定义音频编码器信息结构体comp_info_t al_comp; // 音频组件信息port_info_t *ain; // 音频输入端口指针port_info_t *aout; // 音频输出端口指针
} aenc_info_t;
// 设计模式分析: 组合模式,管理音频分流器组件和端口映射
typedef struct _asplt_info { // 定义音频分流器信息结构体comp_info_t al_comp; // 音频组件信息port_info_t *in; // 输入端口指针int outport_map; // 输出端口映射位图
} audio_splt_t;
#define MAX_DEV_NAME_LEN 32 // 定义最大设备名称长度为32字节
// 设计模式分析: 享元模式,音频源对象被多个编码器共享使用
// 性能分析: 共享音频源减少资源重复分配,提高内存利用率
typedef struct audio_source { // 定义音频源结构体char dev_name[MAX_DEV_NAME_LEN]; // 设备名称OMX_U32 channels; /* 声道数 (例如 2 表示立体声) */OMX_U32 bit_per_sample; /* 每个采样的位数 */OMX_U32 sample_rate; /* 源数据的采样率。对于可变或未知采样率使用0 */int mute_on; // 静音开关OMX_U32 aqe_funcs; // 音频质量增强功能int prio; // 优先级asrc_info_t asrc_info; // 音频源信息audio_splt_t asrc_splt; // 音频源分流器int ref; // 引用计数int started_cnt; // 启动计数int index; // 索引
} audio_source_t;
// 设计模式分析: 策略模式,支持多种音频编码算法
// 性能分析: 编码器参数预配置,减少运行时计算开销
typedef struct audio_enc { // 定义音频编码器结构体int prio; // 优先级int n_channel; // 声道数int channel_map; // 声道映射audio_encoder_t coding_type; // 编码类型
audio_source_t *asrc; // 关联的音频源指针port_info_t *aenc_srcport; // 编码器源端口aenc_info_t aenc_info; // 编码器信息audio_splt_t aenc_splt; // 编码器分流器int ref; // 引用计数int started_cnt; // 启动计数int index; // 索引audio_private_para_t private_para; // 私有参数
} audio_enc_t;
// 设计模式分析: 外观模式,提供简化的音频流操作接口
// 性能分析: 句柄封装内部复杂结构,提供轻量级访问接口
typedef struct { // 定义音频流句柄结构体astream_state_e state; // 音频流状态audio_source_t *asrc; // 音频源指针audio_enc_t *aenc; // 音频编码器指针port_info_t *enc_outport; // 编码输出端口int srcport_map; // 源端口映射int encport_map; // 编码端口映射int index; // 索引int ref; // 引用计数
} astream_handle_t;
#define MAX_AUDIO_DEVICE 4 // 定义最大音频设备数为4
#define MAX_AUDIO_STREAM 8 // 定义最大音频流数为8
// 设计模式分析: 单例模式,全局音频流管理器
// 性能分析: 集中管理音频资源,避免资源碎片化
typedef struct audio_stream { // 定义音频流管理器结构体OMX_U32 channels; /* 声道数 (例如 2 表示立体声) */OMX_U32 bit_per_sample; /* 每个采样的位数 */OMX_U32 sample_rate; /* 源数据的采样率。对于可变或未知采样率使用0 */audio_encoder_t coding_type; // 编码类型
astream_state_e state; // 状态asrc_info_t asrc_info; // 音频源信息audio_splt_t asrc_splt; // 音频源分流器port_info_t *aenc_srcport; // 编码器源端口aenc_info_t aenc_info; // 编码器信息audio_splt_t aenc_splt; // 编码器分流器
audio_source_t *audio_source[MAX_AUDIO_DEVICE]; // 音频源数组audio_enc_t *audio_encoder[MAX_AUDIO_STREAM]; // 音频编码器数组astream_handle_t *astream_handle_t[MAX_AUDIO_STREAM]; // 音频流句柄数组pthread_mutex_t lock; // 互斥锁int ref; // 引用计数int init; // 初始化标志int muti_coding_enable; // 多编码使能标志
} audio_stream_t;
// 设计模式分析: 对象池模式,预分配音频资源对象
// 性能分析: 静态分配避免动态内存分配开销,提高实时性
typedef struct audio_stream_sum { // 定义音频流汇总结构体audio_source_t audio_source[MAX_AUDIO_DEVICE]; // 音频源对象池audio_enc_t audio_encoder[MAX_AUDIO_STREAM]; // 音频编码器对象池astream_handle_t astream_handle_t[MAX_AUDIO_STREAM]; // 音频流句柄对象池int init; // 初始化标志int muti_coding_enable; // 多编码使能标志
} audio_stream_sum_t;
// 平台相关的互斥锁初始化
#ifdef __EOS__
static pthread_mutex_t _astream_lock = {.attr = -1}; // EOS平台互斥锁初始化
#else
static pthread_mutex_t _astream_lock = PTHREAD_MUTEX_INITIALIZER; // 标准平台互斥锁初始化
#endif
// 全局音频录制对象,单例模式实例
audio_stream_sum_t g_audio_rec = { // 定义全局音频录制对象.init = 0 // 初始化为未初始化状态
};
// 设计模式分析: 包装器模式,提供线程安全的资源访问
// 性能分析: 细粒度锁保护关键资源,平衡并发性能和数据安全
#define ASTREAM_LOCK() pthread_mutex_lock(&_astream_lock) // 音频流加锁宏
#define ASTREAM_UNLOCK() pthread_mutex_unlock(&_astream_lock) // 音频流解锁宏
#define get_audio_stream(hdl) ((astream_handle_t *)(hdl)) // 获取音频流句柄宏
// 调试日志宏定义
#define log_aenc_state(aenc) \ // 记录音频编码器状态宏OSCL_LOGI("asrc:%p, count:%d; aenc %p count:%d!", \ // 日志格式aenc ? aenc->asrc : NULL,\ // 音频源指针aenc ? (aenc->asrc ? aenc->asrc->started_cnt : 0) : 0, \ // 音频源启动计数aenc, aenc ? aenc->started_cnt : 0) // 编码器指针和启动计数
#define log_astream_state(astream) \ // 记录音频流状态宏OSCL_LOGI("hdl:%p-%p-%p ref:%d-%d-%d, start:%d-%d, map:%x-%x", \ // 日志格式astream, astream ? astream->asrc : NULL, \ // 句柄和音频源指针astream ? astream->aenc : NULL, \ // 编码器指针astream->ref, astream->asrc ? astream->asrc->ref : 0, \ // 引用计数astream->aenc ? astream->aenc->ref : 0, \ // 编码器引用计数astream->asrc ? astream->asrc->started_cnt : 0, \ // 音频源启动计数astream->aenc ? astream->aenc->started_cnt : 0, \ // 编码器启动计数astream->asrc ? astream->asrc->asrc_splt.outport_map : 0, \ // 源端口映射astream->aenc ? astream->aenc->aenc_splt.outport_map : 0) // 编码端口映射
// 设计模式分析: 工厂方法模式,根据名称获取或创建音频源
// 性能分析: 对象池查找O(n)复杂度,缓存友好但规模受限
static audio_source_t *__get_source_by_name(char *name) // 根据名称获取音频源函数
{int i;audio_stream_sum_t *ainfo = &g_audio_rec; // 获取全局音频信息audio_source_t *asource = NULL; // 音频源指针int unused_index = -1; // 未使用索引
oscl_param_check(name != NULL, NULL, NULL); // 参数检查
for (i = 0; i < MAX_AUDIO_DEVICE; i++) { // 遍历音频设备数组if (unused_index == -1 && // 查找第一个未使用的索引strlen(ainfo->audio_source[i].dev_name) == 0) {unused_index = i;}if (strcmp(name, ainfo->audio_source[i].dev_name) == 0) { // 查找匹配设备名asource = &ainfo->audio_source[i]; // 找到现有音频源break;}}if (asource == NULL && unused_index != -1) { // 未找到且有空闲位置asource = &ainfo->audio_source[unused_index]; // 创建新音频源asource->index = unused_index; // 设置索引strncpy(asource->dev_name, name, MAX_DEV_NAME_LEN - 1); // 复制设备名asource->channels = AUDIO_DEFAULT_CHANNELS; // 设置默认声道数asource->bit_per_sample = AUDIO_DEFAULT_FMT_WIDTH; // 设置默认位宽asource->sample_rate = AUDIO_DEFAULT_RATE; // 设置默认采样率asource->started_cnt = 0; // 初始化启动计数}if (asource) // 如果成功获取音频源asource->ref++; // 增加引用计数elseOSCL_LOGE("create audio stream source failed:%s", name); // 记录错误日志return asource; // 返回音频源指针
}
// 设计模式分析: 引用计数模式,管理音频源生命周期
// 性能分析: 轻量级引用计数,避免频繁的内存分配释放
int __put_source(audio_source_t *asource) // 释放音频源函数
{oscl_param_check(asource != NULL, -1, NULL); // 参数检查oscl_param_check(asource->ref > 0, 0, NULL); // 引用计数检查asource->ref--; // 减少引用计数if (asource->ref == 0) { // 如果引用计数为0if (asource->asrc_info.al_comp.cmp_hdl) { // 检查组件句柄是否释放OSCL_LOGE("ERR! resource not released:%p", // 记录资源未释放错误asource->asrc_info.al_comp.cmp_hdl);}memset(asource, 0, sizeof(audio_source_t)); // 清空音频源内存}return 0; // 返回成功
}
// 设计模式分析: 享元模式,查找正在执行的相同配置编码器
// 性能分析: 避免重复创建相同编码器,节省系统资源
static audio_enc_t *__get_excuting_aenc(audio_enc_t *init_encoder) // 获取执行中编码器函数
{audio_stream_sum_t *ainfo = &g_audio_rec; // 获取全局音频信息int i;audio_enc_t *excuting_encoder = NULL; // 执行中编码器指针audio_enc_t *tmp_enc = NULL; // 临时编码器指针excuting_encoder = NULL;
/* 多编码未启用,所有流使用同一个编码器 */if (ainfo->muti_coding_enable == 0) // 检查多编码是否禁用return NULL;
/* 查找具有相同音频源和设置的执行中编码器 */for (i = 0; i < MAX_AUDIO_STREAM; i++) { // 遍历音频编码器数组tmp_enc = &ainfo->audio_encoder[i]; // 获取临时编码器if (tmp_enc != init_encoder && // 不是初始编码器tmp_enc->asrc == init_encoder->asrc && // 相同音频源tmp_enc->started_cnt > 0 && // 正在执行tmp_enc->channel_map == init_encoder->channel_map && // 相同声道映射tmp_enc->coding_type == init_encoder->coding_type) { // 相同编码类型excuting_encoder = tmp_enc; // 找到匹配编码器excuting_encoder->ref++; // 增加引用计数OSCL_LOGE("find a excuting audio encoder:(%s),%d,%x", // 记录日志tmp_enc->asrc->dev_name, tmp_enc->coding_type,tmp_enc->channel_map);break;}}return excuting_encoder; // 返回执行中编码器
}
// 设计模式分析: 工厂方法模式,根据音频源获取编码器
// 性能分析: 对象池管理,支持单编码和多编码两种模式
static audio_enc_t *__get_aenc_by_src(audio_source_t *asrc) // 根据音频源获取编码器函数
{int i;audio_enc_t *aenc = NULL; // 编码器指针audio_stream_sum_t *ainfo = &g_audio_rec; // 获取全局音频信息
oscl_param_check(asrc != NULL, NULL, NULL); // 参数检查/* 多编码未启用,所有流使用同一个编码器。在数组中查找它 */if (ainfo->muti_coding_enable == 0) { // 单编码模式for (i = 0; i < MAX_AUDIO_STREAM; i++) { // 遍历查找现有编码器if (ainfo->audio_encoder[i].asrc == asrc) { // 找到匹配音频源的编码器aenc = &ainfo->audio_encoder[i]; // 获取编码器break;}}}/* 多编码启用,获取新编码器 */if (ainfo->muti_coding_enable != 0 || aenc == NULL) { // 多编码模式或未找到OSCL_TRACE("==");aenc = NULL;for (i = 0; i < MAX_AUDIO_STREAM; i++) { // 遍历查找空闲编码器OSCL_TRACE("==");if (ainfo->audio_encoder[i].asrc == NULL) { // 找到空闲编码器aenc = &ainfo->audio_encoder[i]; // 获取编码器aenc->asrc = asrc; // 设置音频源aenc->prio = 0; // 初始化优先级aenc->coding_type = AUDIO_DEFAULT_CODINGTYPE; // 设置默认编码类型aenc->index = i; // 设置索引aenc->n_channel = aenc->asrc->channels; // 设置声道数aenc->channel_map = (1<<aenc->n_channel) - 1; // 设置声道映射(全选)break;}}}OSCL_TRACE("==");if (aenc) // 如果成功获取编码器aenc->ref++; // 增加引用计数elseOSCL_LOGE("create audio stream encoder failed:%s", asrc->dev_name); // 记录错误OSCL_TRACE("==");return aenc; // 返回编码器指针
}
// 设计模式分析: 引用计数模式,管理编码器生命周期
// 性能分析: 延迟释放策略,避免频繁创建销毁编码器
int __put_enc(audio_enc_t *aenc) // 释放编码器函数
{oscl_param_check(aenc != NULL, -1, NULL); // 参数检查oscl_param_check(aenc->ref > 0, 0, NULL); // 引用计数检查aenc->ref--; // 减少引用计数if (aenc->ref == 0) { // 如果引用计数为0if (aenc->aenc_srcport || aenc->aenc_info.al_comp.cmp_hdl) { // 检查资源是否释放OSCL_LOGE("ERR! resource not released:%p %p", // 记录资源未释放错误aenc->aenc_srcport, aenc->aenc_info.al_comp.cmp_hdl);}memset(aenc, 0, sizeof(audio_enc_t)); // 清空编码器内存}return 0; // 返回成功
}
/*** _setup_asrc - 为音频接收器组件设置参数** @asrc: 音频源** 成功返回0,否则返回错误码。*/
// 设计模式分析: 模板方法模式,定义音频源设置的固定流程
// 性能分析: 批量设置OpenMAX参数,减少API调用次数
int _setup_asrc(audio_source_t *asrc) // 设置音频源函数
{OMX_AUDIO_PARAM_PCMMODETYPE pcm_type; // PCM参数结构int ret = 0;OMX_PRIORITYMGMTTYPE priority; // 优先级管理结构OMX_AUDIO_CONFIG_MUTETYPE mute; // 静音配置结构
OSCL_TRACE("asrc:%p", asrc); // 跟踪日志oscl_param_check(asrc != NULL, 0, NULL); // 参数检查oscl_param_check(asrc->asrc_info.al_comp.cmp_hdl != NULL, 0, NULL); // 组件句柄检查oscl_param_check(asrc->asrc_info.aout != NULL, 0, NULL); // 输出端口检查
OMX_SetParameter(asrc->asrc_info.al_comp.cmp_hdl, // 设置设备名称参数omx_index_audio_devname,asrc->dev_name);
/* 为音频接收器组件设置参数*/ret = OMX_SetConfig(asrc->asrc_info.al_comp.cmp_hdl, // 设置音频质量增强功能omx_index_audio_aqefunc, &asrc->aqe_funcs);if (ret) {OSCL_LOGE("set audio aqe funcs config error!"); // 记录错误return ret;}
memset(&pcm_type, 0, sizeof(pcm_type)); // 清空PCM参数结构pcm_type.nChannels = asrc->channels; // 设置声道数pcm_type.nBitPerSample = asrc->bit_per_sample; // 设置采样位宽pcm_type.nSamplingRate = asrc->sample_rate; // 设置采样率ret = OMX_SetParameter(asrc->asrc_info.al_comp.cmp_hdl, // 设置PCM参数OMX_IndexParamAudioPcm,&pcm_type);
if (asrc->prio) { // 如果设置了优先级priority.nVersion.nVersion = OMX_VERSION; // 设置版本priority.nGroupPriority = asrc->prio; // 设置组优先级OMX_SetParameter(asrc->asrc_info.al_comp.cmp_hdl, // 设置源组件优先级OMX_IndexParamPriorityMgmt, &priority);OMX_SetParameter(asrc->asrc_splt.al_comp.cmp_hdl, // 设置分流器组件优先级OMX_IndexParamPriorityMgmt, &priority);}
memset(&mute, 0, sizeof(OMX_AUDIO_CONFIG_MUTETYPE)); // 清空静音配置结构if (asrc->mute_on) // 如果启用静音mute.bMute = OMX_TRUE; // 设置静音标志mute.nPortIndex = asrc->asrc_info.aout->index; // 设置端口索引ret = OMX_SetConfig(asrc->asrc_info.al_comp.cmp_hdl, // 设置静音配置OMX_IndexConfigAudioMute, &mute);
OSCL_TRACE("asrc:%p", asrc); // 跟踪日志return ret; // 返回结果
}
/*** _setup_aenc - 为音频编码器组件设置参数** @aenc: audio_enc_t** 成功返回0,否则返回错误码。*/
// 设计模式分析: 策略模式,支持多种音频编码算法的参数配置
// 性能分析: 按编码类型分支处理,避免不必要的参数设置
int _setup_aenc(audio_enc_t *aenc) // 设置音频编码器函数
{OMX_AUDIO_PARAM_ADPCMTYPE adpcm_type; // ADPCM参数结构OMX_AUDIO_PARAM_PCMMODETYPE pcm_type; // PCM参数结构OMX_AUDIO_PARAM_AACPROFILETYPE aac_type; // AAC参数结构OMX_AUDIO_PARAM_G729TYPE g729_type; // G729参数结构OMX_AUDIO_PARAM_G726TYPE g726_type; // G726参数结构OMX_PRIORITYMGMTTYPE priority; // 优先级管理结构int ret = 0;OMX_U32 channels; // 声道数OMX_U32 bit_per_sample; // 采样位宽OMX_U32 sample_rate; // 采样率OMX_U32 port_index; // 端口索引OMX_AUDIO_PARAM_CHANNEL_MAP channel_map_para; // 声道映射参数
oscl_param_check(aenc != NULL, 0, NULL); // 参数检查oscl_param_check(aenc->asrc != NULL, 0, NULL); // 音频源检查oscl_param_check(aenc->aenc_info.aout != NULL, 0, NULL); // 输出端口检查oscl_param_check(aenc->aenc_info.al_comp.cmp_hdl != NULL, 0, NULL); // 组件句柄检查channels = aenc->n_channel; // 获取声道数bit_per_sample = aenc->asrc->bit_per_sample; // 获取采样位宽sample_rate = aenc->asrc->sample_rate; // 获取采样率port_index = aenc->aenc_info.aout->index; // 获取端口索引
switch (aenc->coding_type) { // 根据编码类型分支处理case AUDIO_ENCODER_ADPCM: // ADPCM编码memset(&adpcm_type, 0, sizeof(OMX_AUDIO_PARAM_ADPCMTYPE)); // 清空结构adpcm_type.nChannels = channels; // 设置声道数adpcm_type.nBitsPerSample = bit_per_sample; // 设置采样位宽adpcm_type.nSampleRate = sample_rate; // 设置采样率adpcm_type.nPortIndex = port_index; // 设置端口索引ret = OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置ADPCM参数OMX_IndexParamAudioAdpcm,&adpcm_type);break;
case AUDIO_ENCODER_AAC: // AAC编码memset(&aac_type, 0, sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE)); // 清空结构aac_type.nChannels = channels; // 设置声道数aac_type.nSampleRate = sample_rate; // 设置采样率aac_type.nBitRate = 128000; // 设置比特率128kbpsaac_type.eAACStreamFormat = OMX_AUDIO_AACStreamFormatRAW; // 设置流格式为RAWaac_type.nPortIndex = port_index; // 设置端口索引OSCL_LOGI("aac setting: channels %d, samplerate:%d, bitrate:%d", // 记录配置aac_type.nChannels, aac_type.nSampleRate, aac_type.nBitRate);ret = OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置AAC参数OMX_IndexParamAudioAac,&aac_type);break;case AUDIO_ENCODER_AAC_MP4ADTS: // AAC MP4 ADTS格式memset(&aac_type, 0, sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE)); // 清空结构aac_type.nChannels = channels; // 设置声道数aac_type.nSampleRate = sample_rate; // 设置采样率aac_type.nBitRate = 128000; // 设置比特率128kbpsaac_type.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS; // 设置流格式为MP4 ADTSaac_type.nPortIndex = port_index; // 设置端口索引OSCL_LOGI("aac setting: channels %d, samplerate:%d, bitrate:%d", // 记录配置aac_type.nChannels, aac_type.nSampleRate, aac_type.nBitRate);ret = OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置AAC参数OMX_IndexParamAudioAac,&aac_type);break;case AUDIO_ENCODER_G729: // G729编码memset(&g729_type, 0, sizeof(OMX_AUDIO_PARAM_G729TYPE)); // 清空结构g729_type.nChannels = channels; // 设置声道数g729_type.nPortIndex = port_index; // 设置端口索引ret = OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置G729参数OMX_IndexParamAudioG729,&g729_type);break;case AUDIO_ENCODER_ADPCM_G726: // G726 ADPCM编码memset(&g726_type, 0, sizeof(OMX_AUDIO_PARAM_G726TYPE)); // 清空结构g726_type.nChannels = channels; // 设置声道数g726_type.nPortIndex = port_index; // 设置端口索引switch (aenc->private_para.g726_mode) { // 根据G726模式分支case AUDIO_G726MODE_16K: // 16k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode16;break;case AUDIO_G726MODE_24K: // 24k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode24;break;case AUDIO_G726MODE_M32K: // 32k ADPCM模式case AUDIO_G726MODE_32K: // 32k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode32;break;case AUDIO_G726MODE_M40K: // 40k ADPCM模式case AUDIO_G726MODE_40K: // 40k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode40;break;default: // 默认32k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode32;break;}ret = OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置G726参数OMX_IndexParamAudioG726,&g726_type);break;case AUDIO_ENCODER_ADPCM_G726LE: // G726小端ADPCM编码memset(&g726_type, 0, sizeof(OMX_AUDIO_PARAM_G726TYPE)); // 清空结构g726_type.nChannels = channels; // 设置声道数g726_type.nPortIndex = port_index; // 设置端口索引switch (aenc->private_para.g726_mode) { // 根据G726模式分支case AUDIO_G726MODE_16K: // 16k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode16;break;case AUDIO_G726MODE_24K: // 24k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode24;break;case AUDIO_G726MODE_M32K: // 32k ADPCM模式case AUDIO_G726MODE_32K: // 32k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode32;break;case AUDIO_G726MODE_M40K: // 40k ADPCM模式case AUDIO_G726MODE_40K: // 40k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode40;break;default: // 默认32k模式g726_type.eG726Mode = OMX_AUDIO_G726Mode32;break;}ret = OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置G726小端参数OMX_IndexParamAudioG726le,&g726_type);break;
case AUDIO_ENCODER_PCM: // PCM编码case AUDIO_ENCODER_PCM_ALAW: // PCM A律编码case AUDIO_ENCODER_PCM_MULAW: // PCM μ律编码default: // 默认编码memset(&pcm_type, 0, sizeof(pcm_type)); // 清空PCM参数结构pcm_type.nChannels = channels; // 设置声道数pcm_type.nBitPerSample = bit_per_sample; // 设置采样位宽pcm_type.nSamplingRate = sample_rate; // 设置采样率pcm_type.nPortIndex = port_index; // 设置端口索引if (aenc->coding_type == AUDIO_ENCODER_PCM_ALAW) // A律编码pcm_type.ePCMMode = OMX_AUDIO_PCMModeALaw;else if (aenc->coding_type == AUDIO_ENCODER_PCM_MULAW) // μ律编码pcm_type.ePCMMode = OMX_AUDIO_PCMModeMULaw;ret = OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置PCM参数OMX_IndexParamAudioPcm,&pcm_type);break;}
if (aenc->prio) { // 如果设置了优先级priority.nVersion.nVersion = OMX_VERSION; // 设置版本priority.nGroupPriority = aenc->prio; // 设置组优先级OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置编码器组件优先级OMX_IndexParamPriorityMgmt, &priority);OMX_SetParameter(aenc->aenc_splt.al_comp.cmp_hdl, // 设置编码器分流器优先级OMX_IndexParamPriorityMgmt, &priority);}if (aenc->private_para.en_in_data_len) { // 如果设置了输入数据长度OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置输入数据长度参数omx_index_audio_set_en_in_datalen,&aenc->private_para.en_in_data_len);}
channel_map_para.channel_map = aenc->channel_map; // 设置声道映射channel_map_para.src_channel_num = aenc->asrc->channels; // 设置源声道数OMX_SetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 设置声道选择参数omx_index_audio_select_channels, &channel_map_para);
OSCL_TRACE("aenc:%p, %x", aenc, channel_map_para.channel_map); // 跟踪日志return ret; // 返回结果
}
// 设计模式分析: 模板方法模式,定义端口准备的固定流程
// 性能分析: 批量配置端口参数,优化OpenMAX API调用
static int _asplt_prepare(audio_splt_t *splt_info, OMX_PARAM_PORTDEFINITIONTYPE *port) // 准备音频分流器函数
{int i = 0;int ret = 0;port_info_t *al_port; // 端口信息指针
OSCL_TRACE("==");for (i = 0; i < splt_info->al_comp.num_port; i++) { // 遍历所有端口al_port = &splt_info->al_comp.port_info[i]; // 获取端口信息al_port->domain = port->eDomain; // 设置端口域OSCL_LOGI("nbuffer(%d) edir(%d) domain(%d) size(%d)!", // 记录端口信息al_port->nbuffer,al_port->edir,al_port->domain,al_port->buf_size);if (al_port->edir == OMX_DirInput) { // 如果是输入端口port->eDir = OMX_DirInput; // 设置方向为输入port->nPortIndex = i; // 设置端口索引ret = OMX_SetParameter(splt_info->al_comp.cmp_hdl, // 设置端口定义OMX_IndexParamPortDefinition, port);OSCL_LOGI("%d buf:%d", i, port->nBufferCountActual); // 记录缓冲区数量break;}}for (i = 0; i < splt_info->al_comp.num_port; i++) { // 再次遍历所有端口al_port = &splt_info->al_comp.port_info[i]; // 获取端口信息al_port->domain = port->eDomain; // 设置端口域port->nPortIndex = i; // 设置端口索引ret = OMX_GetParameter(splt_info->al_comp.cmp_hdl, // 获取端口定义OMX_IndexParamPortDefinition, port);al_port->nbuffer = port->nBufferCountActual; // 设置缓冲区数量al_port->buf_size = port->nBufferSize; // 设置缓冲区大小if (al_port->edir == OMX_DirOutput) // 如果是输出端口al_port->is_shared_buffer = 1; // 标记为共享缓冲区}OSCL_TRACE("==");return ret; // 返回结果
}
// 设计模式分析: 工厂方法模式,从分流器获取可用输出端口
// 性能分析: 位图管理端口分配,O(n)查找但n很小
static port_info_t *_splt_get_outport(audio_splt_t *vsplt_info) // 获取分流器输出端口函数
{port_info_t *port = NULL; // 端口指针port_info_t *splt_port = NULL; // 分流器端口指针int nports; // 端口数量int index; // 索引
OSCL_TRACE("==");oscl_param_check(vsplt_info != NULL, NULL, NULL); // 参数检查splt_port = vsplt_info->al_comp.port_info; // 获取端口信息数组nports = vsplt_info->al_comp.num_port; // 获取端口数量for (index = 0; index < nports; index++) { // 遍历所有端口if (splt_port[index].edir == OMX_DirInput) // 跳过输入端口continue;if ((vsplt_info->outport_map & (1 << index)) == 0) { // 查找未使用的输出端口vsplt_info->outport_map |= (1 << index); // 标记端口为已使用port = &splt_port[index]; // 获取端口指针break;}}OSCL_TRACE("=index:%d, port:%p=", index, port); // 跟踪日志return port; // 返回端口指针
}
// 设计模式分析: 资源管理模式,释放分流器输出端口
// 性能分析: 位图操作O(1)复杂度,高效端口管理
static int _splt_put_outport(audio_splt_t *vsplt_info, port_info_t *port) // 释放分流器输出端口函数
{port_info_t *splt_port = NULL; // 分流器端口指针int ret = -1; // 返回值
OSCL_TRACE("==port:%p", port); // 跟踪日志oscl_param_check(vsplt_info != NULL, -1, NULL); // 参数检查oscl_param_check(vsplt_info->al_comp.port_info != NULL, -1, NULL); // 端口信息检查oscl_param_check(port != NULL, -1, NULL); // 端口指针检查
splt_port = vsplt_info->al_comp.port_info; // 获取端口信息数组if (port == &splt_port[port->index]) { // 验证端口有效性if ((vsplt_info->outport_map & (1 << port->index)) == 0) // 检查端口是否已释放OSCL_LOGE("free a port already freed"); // 记录错误else {vsplt_info->outport_map &= ~(1 << port->index); // 清除端口使用标记ret = 0; // 设置成功返回值}}OSCL_TRACE("==");return ret; // 返回结果
}
// 设计模式分析: 命令模式,封装端口启用操作为独立命令
// 性能分析: 直接调用OpenMAX命令,轻量级操作
int _splt_enable_port(audio_splt_t *vsplt_info, port_info_t *port) // 启用分流器端口函数
{int ret; // 返回值
OSCL_TRACE("=="); // 跟踪日志oscl_param_check(vsplt_info != NULL, -1, NULL); // 参数检查:分流器信息oscl_param_check(vsplt_info->al_comp.cmp_hdl != NULL, -1, NULL); // 参数检查:组件句柄oscl_param_check(port != NULL, -1, NULL); // 参数检查:端口信息oscl_param_check(port == &vsplt_info->al_comp.port_info[port->index], -1, NULL); // 参数检查:端口有效性
ret = component_sendcom(&vsplt_info->al_comp, OMX_CommandPortEnable, // 发送端口启用命令port->index, NULL);OSCL_TRACE("=="); // 跟踪日志return ret; // 返回操作结果
}
// 设计模式分析: 命令模式,封装端口禁用操作为独立命令
// 性能分析: 直接调用OpenMAX命令,轻量级操作
int _splt_disable_port(audio_splt_t *vsplt_info, port_info_t *port) // 禁用分流器端口函数
{int ret; // 返回值
OSCL_TRACE("=="); // 跟踪日志oscl_param_check(vsplt_info != NULL, -1, NULL); // 参数检查:分流器信息oscl_param_check(vsplt_info->al_comp.cmp_hdl != NULL, -1, NULL); // 参数检查:组件句柄oscl_param_check(port != NULL, -1, NULL); // 参数检查:端口信息oscl_param_check(port == &vsplt_info->al_comp.port_info[port->index], -1, NULL); // 参数检查:端口有效性
ret = component_sendcom(&vsplt_info->al_comp, OMX_CommandPortDisable, // 发送端口禁用命令port->index, NULL);OSCL_TRACE("=="); // 跟踪日志return ret; // 返回操作结果
}
// 设计模式分析: 组合模式,批量处理多个端口的禁用操作
// 性能分析: 遍历所有映射端口,适合批量操作场景
int _splt_disable_mapped_ports(audio_splt_t *vsplt_info) // 禁用所有已映射端口函数
{int i; // 循环索引
OSCL_TRACE("=="); // 跟踪日志oscl_param_check(vsplt_info != NULL, -1, NULL); // 参数检查:分流器信息oscl_param_check(vsplt_info->al_comp.cmp_hdl != NULL, -1, NULL); // 参数检查:组件句柄
for (i = 0; i < vsplt_info->al_comp.num_port; i++) { // 遍历所有端口if ((vsplt_info->outport_map & (1<<i)) != 0) { // 检查端口是否已映射component_sendcom(&vsplt_info->al_comp, // 发送端口禁用命令OMX_CommandPortDisable,i, NULL);}}
OSCL_TRACE("=="); // 跟踪日志return 0; // 返回成功
}
// 设计模式分析: 状态模式,检查分流器是否处于忙碌状态
// 性能分析: 简单位图检查,O(1)时间复杂度
static int _is_splt_busy(audio_splt_t *vsplt_info) // 检查分流器是否忙碌函数
{return (vsplt_info->outport_map != 0); // 返回端口映射是否非零(有端口在使用)
}
// 设计模式分析: 工厂方法模式,根据类型获取相应端口
// 性能分析: 状态检查和端口分配,确保操作的正确时序
port_info_t *_audio_stream_getport(astream_handle_t *astream, as_port_type_e type) // 获取音频流端口函数
{port_info_t *port = NULL; // 端口指针
oscl_param_check(astream != NULL, NULL, NULL); // 参数检查:音频流句柄if (type == AS_PORT_CODEC && astream->aenc) { // 请求编码器端口且编码器存在if (astream->state == AS_STATE_ENCODE) // 检查是否处于编码状态port = _splt_get_outport(&astream->aenc->aenc_splt); // 获取编码器输出端口elseOSCL_LOGE("err! get encoded port while encode not start!"); // 记录状态错误if (port) // 如果成功获取端口astream->encport_map |= (1 << port->index); // 更新编码端口映射位图}if (type == AS_PORT_PCM && astream->asrc) { // 请求PCM端口且音频源存在if (astream->state == AS_STATE_ENCODE // 检查是否处于编码状态|| astream->state == AS_STATE_START) // 或启动状态port = _splt_get_outport(&astream->asrc->asrc_splt); // 获取音频源输出端口elseOSCL_LOGE("err! get pcm port while audio src not start!"); // 记录状态错误if (port) // 如果成功获取端口astream->srcport_map |= (1 << port->index); // 更新源端口映射位图}return port; // 返回端口指针
}
// 设计模式分析: 资源管理模式,释放音频流端口资源
// 性能分析: 端口映射位图操作,O(1)时间复杂度
int _audio_stream_putport(astream_handle_t *astream, port_info_t *port) // 释放音频流端口函数
{int ret = -1; // 返回值
oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(port != NULL, -1, NULL); // 参数检查:端口信息
if (astream->aenc && port->comp_info == &astream->aenc->aenc_splt.al_comp) { // 编码器端口OSCL_LOGI("audio stream put port:%p (%d), map:%x %x", // 记录端口释放日志port, port->index, astream->srcport_map, astream->encport_map);ret = _splt_put_outport(&astream->aenc->aenc_splt, port); // 释放编码器输出端口astream->encport_map &= ~(1 << port->index); // 清除编码端口映射位}if (astream->asrc && port->comp_info == &astream->asrc->asrc_splt.al_comp) { // 音频源端口OSCL_LOGI("audio stream put port:%p (%d), map:%x %x", // 记录端口释放日志port, port->index, astream->srcport_map, astream->encport_map);ret = _splt_put_outport(&astream->asrc->asrc_splt, port); // 释放音频源输出端口astream->srcport_map &= ~(1 << port->index); // 清除源端口映射位}
return ret; // 返回操作结果
}
// 设计模式分析: 状态模式,管理音频源停止流程
// 性能分析: 引用计数管理,确保资源正确释放
int _asrc_stop(audio_source_t *asrc) // 停止音频源函数
{int ret = 0; // 返回值
OSCL_LOGI("asrc:%p(%s), count:%d", asrc ? asrc : NULL, // 记录音频源状态日志asrc ? (asrc->dev_name) : "NULL", asrc ? asrc->started_cnt : 0);if (asrc == NULL) { // 检查音频源是否存在OSCL_LOGI("astream asrc is not created!"); // 记录音频源未创建goto EXIT; // 跳转到退出点}asrc->started_cnt--; // 减少启动计数if (asrc->started_cnt > 0) { // 如果还有其他使用者OSCL_LOGI("astream start count:%d!", asrc->started_cnt); // 记录当前计数goto EXIT; // 跳转到退出点}if (asrc->started_cnt < 0) { // 如果启动计数异常(过度停止)OSCL_LOGE("state err! This may caused by err started or err stopped"); // 记录状态错误asrc->started_cnt = 0; // 重置启动计数}
/* 检查音频源分流器是否忙碌 */if (_is_splt_busy(&asrc->asrc_splt)) { // 检查分流器端口使用情况OSCL_LOGE("ERROR: asrc splt is busy: %x!", asrc->asrc_splt.outport_map); // 记录忙碌错误_splt_disable_mapped_ports(&asrc->asrc_splt); // 强制禁用所有映射端口asrc->asrc_splt.outport_map = 0; // 重置端口映射}
component_setstate(&asrc->asrc_splt.al_comp, OMX_StateIdle); // 设置分流器组件为空闲状态component_setstate(&asrc->asrc_info.al_comp, OMX_StateIdle); // 设置音频源组件为空闲状态untunnel_unset_ports(asrc->asrc_info.aout, asrc->asrc_splt.in); // 断开端口连接
component_setstate(&asrc->asrc_info.al_comp, OMX_StateLoaded); // 设置音频源组件为加载状态component_setstate(&asrc->asrc_splt.al_comp, OMX_StateLoaded); // 设置分流器组件为加载状态
component_deinit(&asrc->asrc_info.al_comp); // 反初始化音频源组件component_deinit(&asrc->asrc_splt.al_comp); // 反初始化分流器组件
EXIT:OSCL_LOGI("asrc:%p(%s), count:%d", asrc ? asrc : NULL, // 记录音频源最终状态asrc ? (asrc->dev_name) : "NULL", asrc ? asrc->started_cnt : 0);return ret; // 返回操作结果
}
/*** _asrc_start - 启动音频设备** @audio_stream_t: 音频流信息** 成功返回0,否则返回错误码*/
// 设计模式分析: 模板方法模式,定义音频源启动的标准流程
// 性能分析: 顺序执行组件初始化和状态转换,确保正确启动顺序
int _asrc_start(audio_source_t *asrc) // 启动音频源函数
{OMX_PARAM_PORTDEFINITIONTYPE omx_port; // OpenMAX端口定义参数int ret = 0; // 返回值int index = 0; // 端口索引OSCL_TRACE("hdl:%p", asrc); // 跟踪日志
OSCL_LOGI("asrc:%p(%s), count:%d", asrc ? asrc : NULL, // 记录音频源状态asrc ? (asrc->dev_name) : "NULL", asrc ? asrc->started_cnt : 0);if (asrc->started_cnt > 0) { // 如果音频源已启动OSCL_TRACE("astream already started"); // 记录已启动asrc->started_cnt++; // 增加启动计数goto EXIT; // 跳转到退出点}
asrc->started_cnt = 1; // 设置启动计数为1/* 初始化音频源组件 */ret = component_init(&asrc->asrc_info.al_comp, "OMX.LB.SOURCE.AREC", // 初始化音频源组件&untunnel_common_callbacks);oscl_param_check_exit(ret == 0, ret, NULL); // 参数检查并退出index = component_get_port_index(&asrc->asrc_info.al_comp, OMX_DirOutput, // 获取输出端口索引OMX_PortDomainAudio);oscl_param_check_exit(index >= 0, -1, NULL); // 参数检查并退出asrc->asrc_info.aout = &asrc->asrc_info.al_comp.port_info[index]; // 设置输出端口
/* 初始化音频源分流器组件 */ret = component_init(&asrc->asrc_splt.al_comp, "OMX.LB.SPLITTER.BASE", // 初始化分流器组件&untunnel_common_callbacks);oscl_param_check_exit(ret == 0, ret, NULL); // 参数检查并退出asrc->asrc_splt.in = &asrc->asrc_splt.al_comp.port_info[0]; // 设置输入端口
/* 设置音频组件参数 */ret = _setup_asrc(asrc); // 设置音频源参数oscl_param_check_exit((ret == 0), ret, NULL); // 参数检查并退出
/* 设置分流器端口定义 */omx_port.nPortIndex = asrc->asrc_info.aout->index; // 设置端口索引omx_port.nVersion.nVersion = OMX_VERSION; // 设置版本ret = OMX_GetParameter(asrc->asrc_info.al_comp.cmp_hdl, // 获取端口定义参数OMX_IndexParamPortDefinition, &omx_port);oscl_param_check_exit(ret == OMX_ErrorNone, ret, NULL); // 参数检查并退出_asplt_prepare(&asrc->asrc_splt, &omx_port); // 准备分流器端口
/* 连接音频源和音频源分流器 */ret = untunnel_setup_ports(asrc->asrc_info.aout, // 设置端口连接asrc->asrc_splt.in);oscl_param_check_exit(ret == OMX_ErrorNone, ret, NULL); // 参数检查并退出
/* 将音频组件转换为空闲状态 */component_setstate(&asrc->asrc_splt.al_comp, OMX_StateIdle); // 设置分流器为空闲状态component_setstate(&asrc->asrc_info.al_comp, OMX_StateIdle); // 设置音频源为空闲状态
/* 将录制器组件转换为执行状态 */ret = component_setstate(&asrc->asrc_splt.al_comp, OMX_StateExecuting); // 设置分流器为执行状态oscl_param_check_exit(ret == 0, -1, NULL); // 参数检查并退出ret = component_setstate(&asrc->asrc_info.al_comp, OMX_StateExecuting); // 设置音频源为执行状态oscl_param_check_exit(ret == 0, -1, NULL); // 参数检查并退出
EXIT:if (ret != 0) // 如果启动失败_asrc_stop(asrc); // 停止音频源(清理资源)OSCL_LOGI("asrc:%p(%s), count:%d", asrc ? asrc : NULL, // 记录最终状态asrc ? (asrc->dev_name) : "NULL", asrc ? asrc->started_cnt : 0);OSCL_TRACE("hdl:%p ret:%d", asrc, ret); // 跟踪日志return ret; // 返回操作结果
}
/*** astream_start - 启动音频流** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 外观模式,提供简化的音频流启动接口
// 性能分析: 状态验证和委托调用,确保操作的正确性
int _astream_start(astream_handle_t *astream) // 启动音频流函数
{int ret = 0; // 返回值
OSCL_TRACE("hdl:%p", astream); // 跟踪日志oscl_param_check((astream->state == AS_STATE_INIT), 0, NULL); // 参数检查:必须为初始化状态
ret = _asrc_start(astream->asrc); // 启动音频源if (ret == 0) // 如果启动成功astream->state = AS_STATE_START; // 更新音频流状态为启动状态
OSCL_TRACE("astream:%p ret:%d", astream, ret); // 跟踪日志return ret; // 返回操作结果
}
/*** _astream_stop - 停止音频源** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 外观模式,提供简化的音频流停止接口
// 性能分析: 状态验证和委托调用,确保操作的正确性
int _astream_stop(astream_handle_t *astream) // 停止音频流函数
{int ret = 0; // 返回值
OSCL_TRACE("hdl:%p", astream); // 跟踪日志oscl_param_check((astream->state == AS_STATE_START), -1, NULL); // 参数检查:必须为启动状态ret = _asrc_stop(astream->asrc); // 停止音频源astream->state = AS_STATE_INIT; // 更新音频流状态为初始化状态OSCL_TRACE("hdl:%p asrc:%p, aenc:%p", astream, astream->asrc, astream->aenc); // 跟踪日志return ret; // 返回操作结果
}
/*** _aenc_start - 启动音频编码器** @aenc: 音频编码信息** 成功返回0,否则返回错误码*/
// 设计模式分析: 模板方法模式,定义编码器启动的标准流程
// 性能分析: 顺序执行组件初始化和状态转换,确保正确启动顺序
int _aenc_start(audio_enc_t *aenc) // 启动音频编码器函数
{OMX_PARAM_PORTDEFINITIONTYPE omx_port; // OpenMAX端口定义参数int index; // 端口索引int ret = 0; // 返回值OSCL_TRACE("hdl:%p", aenc); // 跟踪日志
log_aenc_state(aenc); // 记录编码器状态/* 初始化音频编码组件 */ret = component_init(&aenc->aenc_info.al_comp, "OMX.LB.ENCODER.AUDIO", // 初始化编码器组件&untunnel_common_callbacks);oscl_param_check_exit(ret == 0, ret, NULL); // 参数检查并退出index = component_get_port_index(&aenc->aenc_info.al_comp, OMX_DirInput, // 获取输入端口索引OMX_PortDomainAudio);oscl_param_check_exit(index >= 0, -1, NULL); // 参数检查并退出aenc->aenc_info.ain = &aenc->aenc_info.al_comp.port_info[index]; // 设置输入端口index = component_get_port_index(&aenc->aenc_info.al_comp, OMX_DirOutput, // 获取输出端口索引OMX_PortDomainAudio);oscl_param_check_exit(index >= 0, -1, NULL); // 参数检查并退出aenc->aenc_info.aout = &aenc->aenc_info.al_comp.port_info[index]; // 设置输出端口OSCL_LOGE("aenc buffer number:%d", aenc->aenc_info.aout->nbuffer); // 记录缓冲区数量
/* 初始化音频编码器分流器组件 */ret = component_init(&aenc->aenc_splt.al_comp, "OMX.LB.SPLITTER.BASE", // 初始化编码器分流器&untunnel_common_callbacks);oscl_param_check_exit(ret == 0, ret, NULL); // 参数检查并退出aenc->aenc_splt.in = &aenc->aenc_splt.al_comp.port_info[0]; // 设置输入端口
/* 设置音频组件参数 */ret = _setup_aenc(aenc); // 设置编码器参数oscl_param_check_exit((ret == 0), ret, NULL); // 参数检查并退出
/* 设置分流器端口定义 */omx_port.nPortIndex = aenc->aenc_info.aout->index; // 设置端口索引omx_port.nVersion.nVersion = OMX_VERSION; // 设置版本ret = OMX_GetParameter(aenc->aenc_info.al_comp.cmp_hdl, // 获取端口定义参数OMX_IndexParamPortDefinition, &omx_port);oscl_param_check_exit(ret == OMX_ErrorNone, ret, NULL); // 参数检查并退出_asplt_prepare(&aenc->aenc_splt, &omx_port); // 准备分流器端口
/* 连接音频源和音频源分流器 */ret = untunnel_setup_ports(aenc->aenc_srcport, // 连接音频源端口到编码器输入aenc->aenc_info.ain);oscl_param_check_exit(ret == OMX_ErrorNone, ret, NULL); // 参数检查并退出ret = untunnel_setup_ports(aenc->aenc_info.aout, // 连接编码器输出到分流器输入aenc->aenc_splt.in);oscl_param_check_exit(ret == OMX_ErrorNone, ret, NULL); // 参数检查并退出
/* 将音频组件转换为空闲状态 */component_setstate(&aenc->aenc_splt.al_comp, OMX_StateIdle); // 设置分流器为空闲状态component_setstate(&aenc->aenc_info.al_comp, OMX_StateIdle); // 设置编码器为空闲状态
/* 将录制器组件转换为执行状态 */component_setstate(&aenc->aenc_splt.al_comp, OMX_StateExecuting); // 设置分流器为执行状态component_setstate(&aenc->aenc_info.al_comp, OMX_StateExecuting); // 设置编码器为执行状态_splt_enable_port(&aenc->asrc->asrc_splt, aenc->aenc_srcport); // 启用音频源分流器端口
EXIT:log_aenc_state(aenc); // 记录编码器最终状态OSCL_TRACE("hdl:%p ret:%d", aenc, ret); // 跟踪日志return ret; // 返回操作结果
}
// 设计模式分析: 状态模式,管理编码器停止流程
// 性能分析: 引用计数管理,确保资源正确释放
int _aenc_stop(audio_enc_t *aenc) // 停止音频编码器函数
{if (aenc == NULL) { // 检查编码器是否存在OSCL_LOGI("astream aenc is not created!"); // 记录编码器未创建goto EXIT; // 跳转到退出点}log_aenc_state(aenc); // 记录编码器状态if (aenc->started_cnt <= 0) { // 如果编码器未启动或已停止if (aenc->aenc_info.al_comp.cmp_hdl || aenc->aenc_splt.al_comp.cmp_hdl) { // 检查组件句柄OSCL_LOGE("err! aenc stopped but cmphandl not freed:%p:%p!", // 记录资源未释放错误aenc->aenc_info.al_comp.cmp_hdl,aenc->aenc_splt.al_comp.cmp_hdl);} else {OSCL_LOGI("aenc double stopped!"); // 记录重复停止aenc->started_cnt = 0; // 重置启动计数goto EXIT; // 跳转到退出点}}aenc->started_cnt--; // 减少启动计数if (aenc->started_cnt > 0) { // 如果还有其他使用者OSCL_LOGI("_aenc_stop %p count:%x!", aenc, aenc->started_cnt); // 记录当前计数goto EXIT; // 跳转到退出点}/* 检查音频编码器分流器是否忙碌 */if (_is_splt_busy(&aenc->aenc_splt)) { // 检查分流器端口使用情况OSCL_LOGI("ERR,aenc splt is busy: %x!", aenc->aenc_splt.outport_map); // 记录忙碌错误_splt_disable_mapped_ports(&aenc->aenc_splt); // 强制禁用所有映射端口aenc->aenc_splt.outport_map = 0; // 重置端口映射}
/* 1. 禁用源端口* 2. 将编码器组件和编码器分流器组件转换为空闲状态* 3. 断开音频源分流器和音频编码器的连接。断开音频编码器和音频编码器分流器的连接。* 4. 释放编码器源端口。* 5. 将编码器组件和编码器分流器组件转换为加载状态*/if (aenc->asrc) // 如果音频源存在_splt_disable_port(&aenc->asrc->asrc_splt, aenc->aenc_srcport); // 禁用音频源分流器端口
component_setstate(&aenc->aenc_info.al_comp, OMX_StateIdle); // 设置编码器为空闲状态component_setstate(&aenc->aenc_splt.al_comp, OMX_StateIdle); // 设置分流器为空闲状态
untunnel_unset_ports(aenc->aenc_srcport, aenc->aenc_info.ain); // 断开音频源到编码器的连接untunnel_unset_ports(aenc->aenc_info.aout, aenc->aenc_splt.in); // 断开编码器到分流器的连接
if (aenc->asrc) { // 如果音频源存在_splt_put_outport(&aenc->asrc->asrc_splt, aenc->aenc_srcport); // 释放音频源端口aenc->aenc_srcport = NULL; // 清空端口指针}
component_setstate(&aenc->aenc_info.al_comp, OMX_StateLoaded); // 设置编码器为加载状态component_setstate(&aenc->aenc_splt.al_comp, OMX_StateLoaded); // 设置分流器为加载状态
component_deinit(&aenc->aenc_splt.al_comp); // 反初始化分流器组件component_deinit(&aenc->aenc_info.al_comp); // 反初始化编码器组件log_aenc_state(aenc); // 记录编码器最终状态
EXIT:log_aenc_state(aenc); // 记录编码器状态return 0; // 返回成功
}
/*** _astream_stop_enc - 停止音频编码器** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 外观模式,提供简化的编码器停止接口
// 性能分析: 资源清理和状态管理,确保编码器正确停止
int _astream_stop_enc(astream_handle_t *astream) // 停止音频编码器函数
{int ret = 0; // 返回值audio_enc_t *aenc; // 编码器指针
OSCL_TRACE("hdl:%p, %d", astream, astream->state); // 跟踪日志log_astream_state(astream); // 记录音频流状态
aenc = astream->aenc; // 获取编码器指针if (aenc == NULL) { // 检查编码器是否存在OSCL_LOGI("astream aenc is not created(%p %p)!", aenc, astream->asrc); // 记录编码器未创建ret = -1; // 设置错误返回值goto EXIT; // 跳转到退出点}
if (astream->enc_outport) { // 如果编码输出端口未释放OSCL_LOGE("Err, astream->enc_outport not freed!"); // 记录端口未释放错误_splt_disable_port(&astream->aenc->aenc_splt, astream->enc_outport); // 禁用端口_audio_stream_putport(astream, astream->enc_outport); // 释放端口astream->enc_outport = NULL; // 清空端口指针}_aenc_stop(astream->aenc); // 停止编码器if (astream->state == AS_STATE_ENCODE) // 如果当前处于编码状态astream->state = AS_STATE_START; // 更新状态为启动状态if (astream->aenc->ref > 1) { // 如果编码器有多个引用aenc = __get_aenc_by_src(astream->aenc->asrc); // 获取新的编码器if (aenc != NULL) { // 如果成功获取新编码器__put_enc(astream->aenc); // 释放原编码器log_astream_state(astream); // 记录音频流状态astream->aenc = aenc; // 更新编码器指针}}
EXIT:
OSCL_TRACE("hdl:%p state:%d, encmap:%x", // 跟踪日志astream, astream->state, aenc->aenc_splt.outport_map);log_astream_state(astream); // 记录音频流最终状态return ret; // 返回操作结果
}
/*** _astream_start_enc - 启动音频编码** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 享元模式,重用正在执行的编码器实例
// 性能分析: 编码器实例共享,避免重复初始化和资源浪费
int _astream_start_enc(astream_handle_t *astream) // 启动音频编码函数
{int ret = 0; // 返回值audio_enc_t *excuting_encoder; // 执行中编码器指针
OSCL_TRACE("hdl:%p", astream); // 跟踪日志log_astream_state(astream); // 记录音频流状态oscl_param_check((astream->state == AS_STATE_START), -1, NULL); // 参数检查:必须为启动状态if (astream->aenc->started_cnt >= 1) { // 如果编码器已启动OSCL_LOGI("stream %p use a started encoder:%p, %d", // 记录使用已启动编码器astream, astream->aenc, astream->aenc->started_cnt);astream->aenc->started_cnt++; // 增加启动计数goto EXIT; // 跳转到退出点}
excuting_encoder = __get_excuting_aenc(astream->aenc); // 查找正在执行的相同配置编码器if (excuting_encoder) { // 如果找到可重用的编码器__put_enc(astream->aenc); // 释放当前编码器astream->aenc = excuting_encoder; // 使用找到的编码器astream->aenc->started_cnt++; // 增加启动计数goto EXIT; // 跳转到退出点}
astream->aenc->aenc_srcport = _splt_get_outport(&astream->asrc->asrc_splt); // 获取音频源输出端口oscl_param_check_exit(astream->aenc->aenc_srcport, -1, NULL); // 参数检查并退出ret = _aenc_start(astream->aenc); // 启动编码器oscl_param_check_exit(ret == 0, -1, NULL); // 参数检查并退出astream->aenc->started_cnt++; // 增加启动计数
EXIT:if (ret == 0 && astream->state == AS_STATE_START) // 如果启动成功且状态正确astream->state = AS_STATE_ENCODE; // 更新状态为编码状态OSCL_TRACE("hdl:%p astream->state:%d", astream, astream->state); // 跟踪日志if (ret != 0) { // 如果启动失败OSCL_LOGE("start astream failed, try stop!"); // 记录启动失败_astream_stop_enc(astream); // 停止编码器(清理资源)}log_astream_state(astream); // 记录音频流最终状态return ret; // 返回操作结果
}
/*** _astream_reset - 重置音频流** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 外观模式,提供简化的音频流重置接口
// 性能分析: 顺序停止编码器和音频源,确保完全重置
int _astream_reset(astream_handle_t *astream) // 重置音频流函数
{int ret = 0; // 返回值
OSCL_TRACE("hdl:%p", astream); // 跟踪日志log_astream_state(astream); // 记录音频流状态ret = _astream_stop_enc(astream); // 停止编码器if (ret != 0) { // 如果停止编码器失败OSCL_LOGI("_astream_stop_enc fail!"); // 记录失败goto EXIT; // 跳转到退出点}
ret = _astream_stop(astream); // 停止音频源if (ret != 0) { // 如果停止音频源失败OSCL_LOGI("_astream_stop fail!"); // 记录失败goto EXIT; // 跳转到退出点}
EXIT:log_astream_state(astream); // 记录音频流最终状态OSCL_TRACE("hdl:%p", astream); // 跟踪日志return ret; // 返回操作结果
}
// 设计模式分析: 外观模式,提供简化的采样率获取接口
// 性能分析: 线程安全访问,轻量级操作
int audio_stream_get_sample_rate(astream_handle hdl) // 获取音频流采样率函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄int sample_rate = 0; // 采样率oscl_param_check(astream != NULL, 0, NULL); // 参数检查:音频流句柄ASTREAM_LOCK(); // 加锁保护if (astream->asrc) // 如果音频源存在sample_rate = astream->asrc->sample_rate; // 获取采样率ASTREAM_UNLOCK(); // 解锁return sample_rate; // 返回采样率
}
// 设计模式分析: 外观模式,提供简化的参数获取接口
// 性能分析: 线程安全访问,轻量级操作
int audio_stream_get_sample_width(astream_handle hdl) // 获取音频流采样位宽函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄int bit_per_sample = 0; // 采样位宽oscl_param_check(astream != NULL, 0, NULL); // 参数检查:音频流句柄ASTREAM_LOCK(); // 加锁保护if (astream->asrc) // 如果音频源存在bit_per_sample = astream->asrc->sample_rate; // 获取采样率(注意:这里应该是bit_per_sample字段)ASTREAM_UNLOCK(); // 解锁return bit_per_sample; // 返回采样位宽
}
// 设计模式分析: 外观模式,提供简化的声道数获取接口
// 性能分析: 线程安全访问,支持编码器和音频源两种来源
int audio_stream_get_channels(astream_handle hdl) // 获取音频流声道数函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄int channels = 0; // 声道数oscl_param_check(astream != NULL, 0, NULL); // 参数检查:音频流句柄oscl_param_check(astream->asrc != NULL, 0, NULL); // 参数检查:音频源ASTREAM_LOCK(); // 加锁保护if (astream->aenc) // 如果编码器存在,优先使用编码器声道数channels = astream->aenc->n_channel;else // 否则使用音频源声道数channels = astream->asrc->channels;ASTREAM_UNLOCK(); // 解锁return channels; // 返回声道数
}
// 设计模式分析: 外观模式,提供简化的编码类型获取接口
// 性能分析: 线程安全访问,轻量级操作
audio_encoder_t audio_stream_get_coding_type(astream_handle hdl) // 获取音频流编码类型函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄int coding_type = 0; // 编码类型oscl_param_check(astream != NULL, 0, NULL); // 参数检查:音频流句柄ASTREAM_LOCK(); // 加锁保护if (astream->aenc) // 如果编码器存在coding_type = astream->aenc->coding_type; // 获取编码类型ASTREAM_UNLOCK(); // 解锁
OSCL_LOGE("coding_type:%d", coding_type); // 记录编码类型日志return coding_type; // 返回编码类型
}
// 设计模式分析: 策略模式,设置编码器私有参数
// 性能分析: 线程安全访问,参数验证
int audio_stream_set_private_para(astream_handle hdl, audio_private_para_t *para) // 设置音频流私有参数函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄int ret = 0; // 返回值oscl_param_check(astream != NULL, 0, NULL); // 参数检查:音频流句柄oscl_param_check(astream->aenc != NULL, 0, NULL); // 参数检查:编码器ASTREAM_LOCK(); // 加锁保护if (para->g726_mode) // 如果设置了G726模式astream->aenc->private_para.g726_mode = para->g726_mode; // 设置G726模式else // 否则使用默认模式astream->aenc->private_para.g726_mode = AUDIO_G726MODE_32K; // 默认32K模式if (para->en_in_data_len) // 如果设置了输入数据长度astream->aenc->private_para.en_in_data_len = para->en_in_data_len; // 设置输入数据长度ASTREAM_UNLOCK(); // 解锁return ret; // 返回操作结果
}
/*** audio_stream_get_cur_time - 获取音频流时间(音频源)** @hdl: 音频流句柄** 成功返回时间,否则返回0*/
// 设计模式分析: 外观模式,提供简化的时间获取接口
// 性能分析: OpenMAX API调用,需要硬件支持
signed long long audio_stream_get_time(astream_handle hdl) // 获取音频流时间函数
{int ret = 0; // 返回值astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄OMX_TIME_CONFIG_TIMESTAMPTYPE time; // OpenMAX时间戳配置signed long long cur_time = -1; // 当前时间
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(astream->asrc != NULL, -1, NULL); // 参数检查:音频源
ASTREAM_LOCK(); // 加锁保护if (astream->asrc->asrc_info.al_comp.cmp_hdl && astream->asrc->asrc_info.aout) { // 检查组件和端口time.nPortIndex = astream->asrc->asrc_info.aout->index; // 设置端口索引ret = OMX_GetConfig(astream->asrc->asrc_info.al_comp.cmp_hdl, // 获取当前时间配置omx_index_tang_config_cur_time, &time);if (ret == 0) // 如果获取成功cur_time = time.nTimestamp; // 设置当前时间}ASTREAM_UNLOCK(); // 解锁return cur_time; // 返回当前时间
}
/*** audio_stream_set_sample_rate - audio_stream_set_sample_rate** @hdl: 音频流句柄* @rate: 采样率** 成功返回0,否则返回错误码*/
// 设计模式分析: 策略模式,设置音频采样率参数
// 性能分析: 线程安全访问,参数验证
int audio_stream_set_sample_rate(astream_handle hdl, int rate) // 设置音频流采样率函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(astream->asrc != NULL, -1, NULL); // 参数检查:音频源
ASTREAM_LOCK(); // 加锁保护if (rate != 0) // 如果采样率有效astream->asrc->sample_rate = rate; // 设置采样率ASTREAM_UNLOCK(); // 解锁
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return 0; // 返回成功
}
/*** audio_stream_set_sample_width - audio_stream_set_sample_width** @hdl: 音频流句柄* @bits: 每个采样的位数** 成功返回0,否则返回错误码*/
// 设计模式分析: 策略模式,设置音频采样位宽参数
// 性能分析: 线程安全访问,参数验证(只支持8位和16位)
int audio_stream_set_sample_width(astream_handle hdl, int bits) // 设置音频流采样位宽函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(astream->asrc != NULL, -1, NULL); // 参数检查:音频源
ASTREAM_LOCK(); // 加锁保护if (bits == 8 || bits == 16) // 只支持8位或16位采样astream->asrc->bit_per_sample = bits; // 设置采样位宽ASTREAM_UNLOCK(); // 解锁
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return 0; // 返回成功
}
/*** audio_stream_set_channels - audio_stream_set_channels** @hdl: 音频流句柄* @channels: 音频设备的声道数** 成功返回0,否则返回错误码*/
// 设计模式分析: 策略模式,设置音频声道数参数
// 性能分析: 线程安全访问,参数验证和一致性检查
int audio_stream_set_channels(astream_handle hdl, int channels) // 设置音频流声道数函数
{int ret = 0; // 返回值astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄
ASTREAM_LOCK(); // 加锁保护oscl_param_check_exit(astream->asrc != NULL, -1, NULL); // 参数检查:音频源oscl_param_check_exit(channels != 0, -1, NULL); // 参数检查:声道数有效性if (astream->aenc->n_channel != astream->asrc->channels) { // 检查声道数一致性OSCL_LOGE("set channels after set channal map!"); // 记录错误:在设置声道映射后设置声道数ret = -1; // 设置错误返回值goto EXIT; // 跳转到退出点}astream->asrc->channels = channels; // 设置音频源声道数astream->aenc->n_channel = channels; // 设置编码器声道数astream->aenc->channel_map = (1<<astream->asrc->channels) - 1; // 设置声道映射(全选所有声道)
EXIT:ASTREAM_UNLOCK(); // 解锁
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return ret; // 返回操作结果
}
/*** audio_stream_set_channels - audio_stream_set_channels** @hdl: 音频流句柄* @on: 0表示关闭,其他值表示开启** 成功返回0,否则返回错误码*/
// 设计模式分析: 策略模式,设置回声消除功能
// 性能分析: 线程安全访问,位操作设置功能标志
int audio_stream_set_aec(astream_handle hdl, int on) // 设置音频流回声消除函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(astream->asrc != NULL, -1, NULL); // 参数检查:音频源
ASTREAM_LOCK(); // 加锁保护if (on) // 如果启用回声消除astream->asrc->aqe_funcs |= LB_AQE_AEC; // 设置AEC功能标志else // 如果禁用回声消除astream->asrc->aqe_funcs &= (~LB_AQE_AEC); // 清除AEC功能标志ASTREAM_UNLOCK(); // 解锁
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return 0; // 返回成功
}
/*** audio_stream_set_anr - 设置音频流噪声抑制开关* 目前我们只支持单声道、8k或16k的噪声抑制** @hdl: 录制器句柄* @on: 0表示关闭,其他值表示开启*/
// 设计模式分析: 策略模式,设置噪声抑制功能
// 性能分析: 线程安全访问,位操作设置功能标志
int audio_stream_set_anr(astream_handle hdl, int on) // 设置音频流噪声抑制函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志if (astream == NULL) { // 检查音频流句柄OSCL_LOGE("input hdl err!"); // 记录句柄错误return -1; // 返回错误}ASTREAM_LOCK(); // 加锁保护if (on) // 如果启用噪声抑制astream->asrc->aqe_funcs |= LB_AQE_ANR; // 设置ANR功能标志else // 如果禁用噪声抑制astream->asrc->aqe_funcs &= (~LB_AQE_ANR); // 清除ANR功能标志ASTREAM_UNLOCK(); // 解锁OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return 0; // 返回成功
}
/*** audio_stream_set_agc - 设置音频流自动增益控制开关* 目前我们只支持单声道、8k、16k、32k、48k的自动增益控制** @hdl: 录制器句柄* @on: 0表示关闭,其他值表示开启*/
// 设计模式分析: 策略模式,设置自动增益控制功能
// 性能分析: 线程安全访问,位操作设置功能标志
int audio_stream_set_agc(astream_handle hdl, int on) // 设置音频流自动增益控制函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志if (astream == NULL) { // 检查音频流句柄OSCL_LOGE("input hdl err!"); // 记录句柄错误return -1; // 返回错误}ASTREAM_LOCK(); // 加锁保护if (on) // 如果启用自动增益控制astream->asrc->aqe_funcs |= LB_AQE_AGC; // 设置AGC功能标志else // 如果禁用自动增益控制astream->asrc->aqe_funcs &= (~LB_AQE_AGC); // 清除AGC功能标志ASTREAM_UNLOCK(); // 解锁OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return 0; // 返回成功
}
/*** audio_stream_set_prio - audio_stream_set_prio** @hdl: 音频流句柄* @prio: 优先级** 成功返回0,否则返回错误码*/
// 设计模式分析: 策略模式,设置组件优先级
// 性能分析: 批量设置所有相关组件优先级,确保一致性
int audio_stream_set_prio(astream_handle hdl, int prio) // 设置音频流优先级函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄OMX_PRIORITYMGMTTYPE priority; // OpenMAX优先级管理结构
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(astream->asrc != NULL, -1, NULL); // 参数检查:音频源oscl_param_check(astream->aenc != NULL, -1, NULL); // 参数检查:编码器astream->asrc->prio = prio; // 设置音频源优先级astream->aenc->prio = prio; // 设置编码器优先级
priority.nVersion.nVersion = OMX_VERSION; // 设置OpenMAX版本priority.nGroupPriority = prio; // 设置组优先级if (astream->asrc->asrc_info.al_comp.cmp_hdl) // 如果音频源组件句柄存在OMX_SetParameter(astream->asrc->asrc_info.al_comp.cmp_hdl, // 设置音频源组件优先级OMX_IndexParamPriorityMgmt, &priority);
if (astream->asrc->asrc_splt.al_comp.cmp_hdl) // 如果音频源分流器组件句柄存在OMX_SetParameter(astream->asrc->asrc_splt.al_comp.cmp_hdl, // 设置音频源分流器组件优先级OMX_IndexParamPriorityMgmt, &priority);
if (astream->aenc->aenc_info.al_comp.cmp_hdl) // 如果编码器组件句柄存在OMX_SetParameter(astream->aenc->aenc_info.al_comp.cmp_hdl, // 设置编码器组件优先级OMX_IndexParamPriorityMgmt, &priority);
if (astream->aenc->aenc_splt.al_comp.cmp_hdl) // 如果编码器分流器组件句柄存在OMX_SetParameter(astream->aenc->aenc_splt.al_comp.cmp_hdl, // 设置编码器分流器组件优先级OMX_IndexParamPriorityMgmt, &priority);OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return 0; // 返回成功
}
/*** audio_stream_set_coding_type - audio_stream_set_coding_type** @hdl: 音频流句柄* @coding: 编码类型** 成功返回0,否则返回错误码*/
// 设计模式分析: 策略模式,设置音频编码类型
// 性能分析: 线程安全访问,编码类型验证
int audio_stream_set_coding_type(astream_handle hdl, audio_encoder_t coding) // 设置音频流编码类型函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(astream->aenc != NULL, -1, NULL); // 参数检查:编码器
ASTREAM_LOCK(); // 加锁保护if (coding > AUDIO_ENCODER_INVALID && coding < AUDIO_ENCODER_UNSUPPORT) // 验证编码类型有效性astream->aenc->coding_type = coding; // 设置编码类型elseOSCL_LOGE("error coding type:%d", coding); // 记录编码类型错误
ASTREAM_UNLOCK(); // 解锁
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return 0; // 返回成功
}
/*** audio_stream_set_mute - audio_stream_set_mute** @hdl: 音频流句柄* @mute_on: 0:静音关闭,其他值:静音开启** 成功返回0,否则返回错误码*/
// 设计模式分析: 命令模式,封装静音设置操作为独立命令
// 性能分析: OpenMAX API调用,实时生效
int audio_stream_set_mute(astream_handle hdl, int mute_on) // 设置音频流静音函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄OMX_AUDIO_CONFIG_MUTETYPE mute; // OpenMAX静音配置结构int ret = 0; // 返回值
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(astream->asrc != NULL, -1, NULL); // 参数检查:音频源
ASTREAM_LOCK(); // 加锁保护astream->asrc->mute_on = mute_on; // 设置静音状态if (astream->asrc->asrc_info.al_comp.cmp_hdl) { // 如果音频源组件句柄存在memset(&mute, 0, sizeof(OMX_AUDIO_CONFIG_MUTETYPE)); // 清空静音配置结构if (mute_on) // 如果启用静音mute.bMute = OMX_TRUE; // 设置静音标志mute.nPortIndex = astream->asrc->asrc_info.aout->index; // 设置端口索引ret = OMX_SetConfig(astream->asrc->asrc_info.al_comp.cmp_hdl, // 设置静音配置OMX_IndexConfigAudioMute, &mute);}ASTREAM_UNLOCK(); // 解锁OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return ret; // 返回操作结果
}
/*** audio_stream_select_encode_channel - 选择要编码的声道** @hdl: 音频流句柄* @chanal_map: 选择声道,位=1表示选择该声道** 成功返回0,否则返回错误码*/
// 设计模式分析: 策略模式,设置声道选择映射
// 性能分析: 位图操作,高效声道选择
int audio_stream_select_encode_channel(astream_handle hdl, int channel_map) // 选择编码声道函数
{int i; // 循环索引int mask; // 声道掩码astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(astream->asrc != NULL, -1, NULL); // 参数检查:音频源ASTREAM_LOCK(); // 加锁保护OSCL_LOGI("set astream %p, ch map:%x", astream, channel_map); // 记录声道映射设置mask = (1<<astream->asrc->channels) - 1; // 计算声道掩码(所有声道)if (channel_map == 0) // 如果声道映射为0channel_map = mask; // 使用所有声道if (astream->state == AS_STATE_ENCODE) { // 如果正在编码中OSCL_LOGE("ERR: astream is encoding"); // 记录编码中错误} else {astream->aenc->channel_map = channel_map & mask; // 设置声道映射(与掩码相与)astream->aenc->n_channel = 0; // 重置声道计数for (i = 0; i < astream->asrc->channels; i++) { // 遍历所有声道if ((astream->aenc->channel_map & (1<<i)) != 0) // 如果声道被选中astream->aenc->n_channel++; // 增加声道计数}OSCL_LOGI("chanal_map is %x, select %d from %d", // 记录声道选择结果channel_map, astream->aenc->n_channel, astream->asrc->channels);}OSCL_LOGI("set astream %p, ch map:%x", astream, astream->aenc->channel_map); // 记录最终声道映射ASTREAM_UNLOCK(); // 解锁return 0; // 返回成功
}
/*** audio_stream_creat - 通过设备名称获取音频流句柄** @name: 音频设备名称** 成功返回音频流句柄,否则返回0*/
// 设计模式分析: 工厂方法模式,根据设备名称创建音频流
// 性能分析: 对象池管理,线程安全创建
astream_handle audio_stream_creat_by_name(char *name) // 通过名称创建音频流函数
{audio_stream_sum_t *ainfo; // 音频流汇总信息astream_handle_t *astream = NULL; // 音频流句柄int i; // 循环索引int ret = -1; // 返回值
ASTREAM_LOCK(); // 加锁保护ainfo = &g_audio_rec; // 获取全局音频录制对象if (ainfo->init == 0) { // 如果未初始化memset(ainfo, 0, sizeof(audio_stream_sum_t)); // 清空内存ainfo->init = 1; // 设置初始化标志ainfo->muti_coding_enable = 1; // 启用多编码功能}
if (name == NULL) // 如果名称为空name = "default"; // 使用默认设备名
for (i = 0; i < MAX_AUDIO_STREAM; i++) { // 遍历音频流对象池if (ainfo->astream_handle_t[i].ref == 0) { // 找到未使用的音频流astream = &ainfo->astream_handle_t[i]; // 获取音频流astream->ref++; // 增加引用计数astream->index = i; // 设置索引break;}}oscl_param_check_exit(astream != NULL, -1, NULL); // 参数检查:音频流创建成功
astream->asrc = __get_source_by_name(name); // 根据名称获取音频源OSCL_LOGI("name:%s, src:%p", name, astream->asrc); // 记录音频源信息oscl_param_check_exit(astream->asrc != NULL, -1, NULL); // 参数检查:音频源获取成功
astream->aenc = __get_aenc_by_src(astream->asrc); // 根据音频源获取编码器oscl_param_check_exit(astream->aenc != NULL, -1, NULL); // 参数检查:编码器获取成功ret = 0; // 设置成功返回值astream->state = AS_STATE_INIT; // 设置音频流状态为初始化
EXIT:log_astream_state(astream); // 记录音频流状态ASTREAM_UNLOCK(); // 解锁if (ret != 0) { // 如果创建失败OSCL_LOGE("astream creat fail:%x", ret); // 记录创建失败audio_stream_release(astream); // 释放音频流资源astream = NULL; // 清空句柄}OSCL_TRACE("astream:%p", astream); // 跟踪日志return astream; // 返回音频流句柄
}
/*** audio_stream_creat - 获取音频流句柄** 成功返回音频流句柄,否则返回0*/
// 设计模式分析: 工厂方法模式,创建默认音频流
// 性能分析: 委托给具体实现,代码复用
astream_handle audio_stream_creat(void) // 创建音频流函数(默认设备)
{return audio_stream_creat_by_name(NULL); // 使用默认设备名创建音频流
}
/*** audio_stream_release - 释放录制器使用的资源** @hdl: 录制器句柄*/
// 设计模式分析: 资源管理模式,管理音频流生命周期
// 性能分析: 引用计数管理,确保资源正确释放
void audio_stream_release(astream_handle hdl) // 释放音频流函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("astream:%p", hdl); // 跟踪日志if (astream == NULL) // 如果句柄为空return; // 直接返回
ASTREAM_LOCK(); // 加锁保护log_astream_state(astream); // 记录音频流状态/* 只有在所有音频句柄都释放时才反初始化音频流 */if (astream->ref <= 0) { // 如果引用计数异常astream->ref = 0; // 重置引用计数OSCL_LOGE("astream already released!"); // 记录重复释放错误goto EXIT; // 跳转到退出点}if (astream->ref > 1) { // 如果还有其他引用astream->ref--; // 减少引用计数OSCL_TRACE("astream->ref:%d", astream->ref); // 跟踪引用计数goto EXIT; // 跳转到退出点}if (astream->state == AS_STATE_ENCODE) { // 如果处于编码状态OSCL_LOGE("stream %p release in state AS_STATE_ENCODE!", astream); // 记录状态警告_astream_stop_enc(astream); // 停止编码器}if (astream->state == AS_STATE_START) { // 如果处于启动状态OSCL_LOGE("stream %p release in state AS_STATE_START!", astream); // 记录状态警告_astream_stop(astream); // 停止音频源}if (astream->srcport_map || astream->encport_map) { // 如果端口映射未清空OSCL_LOGE("Err, stream release with %x-%x, astream->state:%d!", // 记录端口未释放错误astream->srcport_map, astream->encport_map, astream->state);}__put_enc(astream->aenc); // 释放编码器__put_source(astream->asrc); // 释放音频源log_astream_state(astream); // 记录释放后状态memset(astream, 0, sizeof(astream_handle_t)); // 清空音频流内存astream->state = AS_STATE_ERR; // 设置状态为错误
EXIT:log_astream_state(astream); // 记录最终状态ASTREAM_UNLOCK(); // 解锁OSCL_TRACE("hdl:%p astream->state:%d", hdl, astream->state); // 跟踪日志
}
/*** audio_stream_inc_refcnt - 增加音频流的引用计数** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 引用计数模式,管理音频流生命周期
// 性能分析: 轻量级引用计数操作,线程安全
int audio_stream_inc_refcnt(astream_handle hdl) // 增加音频流引用计数函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄int ret = 0; // 返回值
OSCL_TRACE("start"); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄ASTREAM_LOCK(); // 加锁保护if (astream->state == AS_STATE_ERR) // 如果音频流处于错误状态ret = -1; // 设置错误返回值elseastream->ref++; // 增加引用计数ASTREAM_UNLOCK(); // 解锁
return ret; // 返回操作结果
}
/*** audio_stream_start - 启动音频流** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 状态模式,管理音频流状态转换
// 性能分析: 状态验证确保正确启动顺序,避免重复启动
int audio_stream_start(astream_handle hdl) // 启动音频流函数
{int ret = 0; // 返回值astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄
ASTREAM_LOCK(); // 加锁保护log_astream_state(astream); // 记录音频流状态oscl_param_check_exit(astream->asrc != NULL, -1, NULL); // 参数检查:音频源必须存在oscl_param_check_exit(astream->state != AS_STATE_ERR, -1, NULL); // 参数检查:状态不能为错误if (astream->state == AS_STATE_INIT) // 如果处于初始化状态ret = _astream_start(astream); // 启动音频流elseOSCL_LOGW("stream %p already started(%d)!", astream, astream->state); // 记录警告:音频流已启动
EXIT:log_astream_state(astream); // 记录音频流最终状态ASTREAM_UNLOCK(); // 解锁OSCL_TRACE("hdl:%p", hdl); // 跟踪日志return ret; // 返回操作结果
}
/*** audio_stream_stop - 停止音频流** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 状态模式,管理音频流停止流程
// 性能分析: 按状态顺序停止,确保资源正确释放
int audio_stream_stop(astream_handle hdl) // 停止音频流函数
{int ret = 0; // 返回值astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄
ASTREAM_LOCK(); // 加锁保护log_astream_state(astream); // 记录音频流状态oscl_param_check_exit(astream->asrc != NULL, -1, NULL); // 参数检查:音频源必须存在oscl_param_check_exit(astream->state != AS_STATE_ERR, -1, NULL); // 参数检查:状态不能为错误if (astream->state == AS_STATE_ENCODE) { // 如果处于编码状态OSCL_LOGW("stream %p is in encoding while stopping!", astream); // 记录警告:编码中停止_astream_stop_enc(astream); // 停止编码器}if (astream->state == AS_STATE_START) { // 如果处于启动状态OSCL_LOGI("stream %p is stopping!", astream); // 记录信息:正在停止_astream_stop(astream); // 停止音频源}OSCL_TRACE("hdl:%p astream->state:%d", hdl, astream->state); // 跟踪日志
EXIT:log_astream_state(astream); // 记录音频流最终状态ASTREAM_UNLOCK(); // 解锁return ret; // 返回操作结果
}
/*** audio_stream_start_enc - 启动音频编码** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 工厂方法模式,返回编码端口
// 性能分析: 状态机驱动,确保正确的启动序列
port_info_t *audio_stream_start_enc(astream_handle hdl) // 启动音频编码函数
{int ret = 0; // 返回值astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄port_info_t *port = NULL; // 端口指针
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, NULL, NULL); // 参数检查:音频流句柄
ASTREAM_LOCK(); // 加锁保护oscl_param_check_exit(astream->asrc != NULL, -1, NULL); // 参数检查:音频源必须存在oscl_param_check_exit(astream->aenc != NULL, -1, NULL); // 参数检查:编码器必须存在if (astream->state == AS_STATE_ENCODE) // 如果已处于编码状态OSCL_TRACE("astream already started"); // 跟踪日志:音频流已启动if (astream->state == AS_STATE_INIT) // 如果处于初始化状态ret = _astream_start(astream); // 先启动音频流if (astream->state == AS_STATE_START) // 如果处于启动状态ret = _astream_start_enc(astream); // 启动编码器if (astream->state != AS_STATE_ENCODE) // 如果最终状态不是编码状态ret = -1; // 设置错误返回值if (ret == 0) { // 如果启动成功port = _audio_stream_getport(astream, AS_PORT_CODEC); // 获取编码端口astream->enc_outport = port; // 保存编码输出端口}
EXIT:log_astream_state(astream); // 记录音频流状态ASTREAM_UNLOCK(); // 解锁
OSCL_LOGE("astream:%p-%p astream->state:%d", astream, port, astream->state); // 记录编码启动结果return port; // 返回编码端口
}
/*** audio_stream_stop_enc - 停止音频编码** @hdl: 音频流句柄** 成功返回0,否则返回错误码*/
// 设计模式分析: 资源管理模式,释放编码资源
// 性能分析: 端口验证和资源清理,确保编码器正确停止
int audio_stream_stop_enc(astream_handle hdl, port_info_t *enc_port) // 停止音频编码函数
{int ret = 0; // 返回值astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("hdl:%p", hdl); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄
ASTREAM_LOCK(); // 加锁保护oscl_param_check_exit(astream->state == AS_STATE_ENCODE, -1, NULL); // 参数检查:必须处于编码状态oscl_param_check_exit(astream->asrc != NULL, -1, NULL); // 参数检查:音频源必须存在oscl_param_check_exit(astream->aenc != NULL, -1, NULL); // 参数检查:编码器必须存在if (enc_port) { // 如果提供了编码端口if (astream->enc_outport != enc_port) { // 检查端口一致性OSCL_LOGE("err! astream->enc_outport != port (%p, %p)", // 记录端口不匹配错误astream->enc_outport, enc_port);}_audio_stream_putport(astream, enc_port); // 释放编码端口astream->enc_outport = NULL; // 清空编码输出端口指针}ret = _astream_stop_enc(astream); // 停止编码器
EXIT:ASTREAM_UNLOCK(); // 解锁
return ret; // 返回操作结果
}
/*** audio_stream_getport - 从音频流获取一个空闲端口** @hdl: 音频流句柄** @type: 要获取的PCM端口或编码端口** 成功返回端口句柄,否则返回NULL*/
// 设计模式分析: 工厂方法模式,根据类型创建端口
// 性能分析: 线程安全端口分配,支持PCM和编码两种类型
port_info_t *audio_stream_getport(astream_handle hdl, as_port_type_e type) // 获取音频流端口函数
{port_info_t *port = NULL; // 端口指针astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("=="); // 跟踪日志oscl_param_check(astream != NULL, NULL, NULL); // 参数检查:音频流句柄
ASTREAM_LOCK(); // 加锁保护port = _audio_stream_getport(astream, type); // 根据类型获取端口ASTREAM_UNLOCK(); // 解锁OSCL_LOGI("get port:%p", port); // 记录端口获取结果return port; // 返回端口指针
}
/*** audio_stream_putport - 释放从音频流获取的端口** @hdl: 音频流句柄** @port: 要释放的端口** 成功返回0,否则返回错误码*/
// 设计模式分析: 资源管理模式,释放端口资源
// 性能分析: 线程安全端口释放,资源回收
int audio_stream_putport(astream_handle hdl, port_info_t *port) // 释放音频流端口函数
{astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄int ret = -1; // 返回值
OSCL_TRACE("=="); // 跟踪日志ASTREAM_LOCK(); // 加锁保护ret = _audio_stream_putport(astream, port); // 释放端口ASTREAM_UNLOCK(); // 解锁OSCL_TRACE("==ret:%d", ret); // 跟踪操作结果
return ret; // 返回操作结果
}
/*** audio_stream_enable_port - 启用从音频流获取的端口** @hdl: 音频流句柄** @port: 要启用的端口** 成功返回0,否则返回错误码*/
// 设计模式分析: 命令模式,封装端口启用操作
// 性能分析: 根据端口类型路由到相应的启用函数
int audio_stream_enable_port(void *hdl, port_info_t *port) // 启用音频流端口函数
{int ret = -1; // 返回值astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("=="); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(port != NULL, -1, NULL); // 参数检查:端口
ASTREAM_LOCK(); // 加锁保护oscl_param_check_exit(astream->asrc != NULL, -1, NULL); // 参数检查:音频源必须存在oscl_param_check_exit(astream->aenc != NULL, -1, NULL); // 参数检查:编码器必须存在if (port->comp_info == &astream->aenc->aenc_splt.al_comp) // 如果是编码器分流器端口ret = _splt_enable_port(&astream->aenc->aenc_splt, port); // 启用编码器分流器端口if (port->comp_info == &astream->asrc->asrc_splt.al_comp) // 如果是音频源分流器端口ret = _splt_enable_port(&astream->asrc->asrc_splt, port); // 启用音频源分流器端口EXIT:ASTREAM_UNLOCK(); // 解锁
OSCL_TRACE("=="); // 跟踪日志return ret; // 返回操作结果
}
/*** audio_stream_disable_port - 禁用从音频流获取的端口** @hdl: 音频流句柄** @port: 要禁用的端口** 成功返回0,否则返回错误码*/
// 设计模式分析: 命令模式,封装端口禁用操作
// 性能分析: 根据端口类型路由到相应的禁用函数
int audio_stream_disable_port(void *hdl, port_info_t *port) // 禁用音频流端口函数
{int ret = -1; // 返回值astream_handle_t *astream = get_audio_stream(hdl); // 获取音频流句柄
OSCL_TRACE("=="); // 跟踪日志oscl_param_check(astream != NULL, -1, NULL); // 参数检查:音频流句柄oscl_param_check(port != NULL, -1, NULL); // 参数检查:端口
ASTREAM_LOCK(); // 加锁保护oscl_param_check_exit(astream->asrc != NULL, -1, NULL); // 参数检查:音频源必须存在oscl_param_check_exit(astream->aenc != NULL, -1, NULL); // 参数检查:编码器必须存在if (port->comp_info == &astream->aenc->aenc_splt.al_comp) // 如果是编码器分流器端口ret = _splt_disable_port(&astream->aenc->aenc_splt, port); // 禁用编码器分流器端口if (port->comp_info == &astream->asrc->asrc_splt.al_comp) // 如果是音频源分流器端口ret = _splt_disable_port(&astream->asrc->asrc_splt, port); // 禁用音频源分流器端口
EXIT:ASTREAM_UNLOCK(); // 解锁
OSCL_TRACE("=="); // 跟踪日志return ret; // 返回操作结果
}
#if 0
/*** audio_stream_muti_encoder_onoff - 打开/关闭多音频编码器** @on: 1--打开, 0--关闭** 成功返回0,否则返回错误码*/
// 设计模式分析: 策略模式,配置多编码器功能
// 性能分析: 全局配置开关,影响所有音频流行为
int audio_stream_muti_encoder_onoff(int on) // 多编码器开关函数(已注释)
{audio_stream_sum_t *ainfo; // 音频流汇总信息ainfo = &g_audio_rec; // 获取全局音频录制对象ASTREAM_LOCK(); // 加锁保护if (ainfo->init == 0) { // 如果未初始化memset(ainfo, 0, sizeof(audio_stream_sum_t)); // 清空内存ainfo->init = 1; // 设置初始化标志}ainfo->muti_coding_enable = on; // 设置多编码使能标志ASTREAM_UNLOCK(); // 解锁return 0; // 返回成功
}
#endif
框架架构分析
1. 核心模块交互架构
Application Layer (测试应用)↓ Audio Stream API Layer (audio_stream_xxx)↓ Component Management Layer (组件管理)↓ OpenMAX IL Layer (OMX标准接口)↓ Hardware Abstraction Layer (硬件抽象)↓ Linux Sound Subsystem (ALSA/Kernel)
2. 与Linux内核音频子系统对比
用户空间:Audio Framework ↔ 测试应用↓OpenMAX IL ↔ GStreamer/PulseAudio↓ 内核空间:ALSA API ↔ ALSA驱动↓Sound Core ↔ 音频硬件驱动↓音频硬件 (Codec/DMA/I2S)
逐行注解的测试程序
/*** test_main.c - Linux音频框架测试程序* * 设计模式: 组合模式 + 观察者模式 + 策略模式* 性能分析: 多线程测试 + 状态监控 + 性能统计*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include "audio_stream.h"
#include "media_common.h"
// 设计模式: 单例模式 - 全局测试上下文
typedef struct test_context {int test_case; // 测试用例编号int running; // 运行标志int success_count; // 成功计数int fail_count; // 失败计数pthread_mutex_t lock; // 线程锁astream_handle audio_handles[4]; // 音频句柄数组int handle_count; // 句柄计数
} test_context_t;
static test_context_t g_ctx = {0}; // 全局测试上下文
// 设计模式: 工厂模式 - 创建测试上下文
test_context_t* test_context_create(void)
{test_context_t* ctx = &g_ctx; // 使用全局单例ctx->test_case = 0; // 初始化测试用例ctx->running = 1; // 设置运行标志ctx->success_count = 0; // 初始化成功计数ctx->fail_count = 0; // 初始化失败计数ctx->handle_count = 0; // 初始化句柄计数pthread_mutex_init(&ctx->lock, NULL); // 初始化互斥锁return ctx; // 返回上下文指针
}
// 设计模式: 资源管理模式 - 销毁测试上下文
void test_context_destroy(test_context_t* ctx)
{if (!ctx) return; // 空指针检查pthread_mutex_destroy(&ctx->lock); // 销毁互斥锁memset(ctx, 0, sizeof(test_context_t)); // 清空上下文
}
// 性能分析: 线程安全的结果统计
void test_record_result(test_context_t* ctx, int success)
{pthread_mutex_lock(&ctx->lock); // 加锁保护if (success) { // 如果测试成功ctx->success_count++; // 增加成功计数printf("✅ 测试用例 %d 通过\n", ctx->test_case); // 输出成功信息} else { // 如果测试失败ctx->fail_count++; // 增加失败计数printf("❌ 测试用例 %d 失败\n", ctx->test_case); // 输出失败信息}ctx->test_case++; // 递增测试用例编号pthread_mutex_unlock(&ctx->lock); // 解锁
}
/*** 测试用例1: 音频流创建和释放测试* 设计模式: 模板方法模式 - 定义测试流程* 性能分析: 资源泄漏检测 + 生命周期管理*/
int test_audio_stream_create_release(test_context_t* ctx)
{int result = 0; // 测试结果astream_handle handle; // 音频流句柄printf("\n🎵 测试1: 音频流创建和释放\n"); // 输出测试开始信息printf("================================\n"); // 分隔线// 步骤1: 创建音频流printf("步骤1: 创建音频流...\n"); // 输出步骤信息handle = audio_stream_creat(); // 创建默认音频流if (handle == NULL) { // 检查创建是否成功printf("错误: 音频流创建失败\n"); // 输出错误信息test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}printf("✅ 音频流创建成功, 句柄: %p\n", handle); // 输出成功信息// 步骤2: 验证初始状态printf("步骤2: 验证初始状态...\n"); // 输出步骤信息int channels = audio_stream_get_channels(handle); // 获取声道数int sample_rate = audio_stream_get_sample_rate(handle); // 获取采样率int sample_width = audio_stream_get_sample_width(handle); // 获取采样位宽printf(" 声道数: %d\n", channels); // 输出声道数printf(" 采样率: %d\n", sample_rate); // 输出采样率 printf(" 采样位宽: %d\n", sample_width); // 输出采样位宽// 步骤3: 增加引用计数printf("步骤3: 测试引用计数...\n"); // 输出步骤信息if (audio_stream_inc_refcnt(handle) != 0) { // 增加引用计数printf("错误: 引用计数增加失败\n"); // 输出错误信息audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}printf("✅ 引用计数测试通过\n"); // 输出成功信息// 步骤4: 释放音频流printf("步骤4: 释放音频流...\n"); // 输出步骤信息audio_stream_release(handle); // 第一次释放(减少引用计数)audio_stream_release(handle); // 第二次释放(实际释放资源)printf("✅ 音频流释放成功\n"); // 输出成功信息test_record_result(ctx, 1); // 记录成功结果return 0; // 返回成功
}
/*** 测试用例2: 音频参数配置测试* 设计模式: 策略模式 - 测试不同参数配置* 性能分析: 参数验证 + 配置回读测试*/
int test_audio_parameter_config(test_context_t* ctx)
{astream_handle handle; // 音频流句柄int ret; // 返回值printf("\n🎛️ 测试2: 音频参数配置\n"); // 输出测试开始信息printf("================================\n"); // 分隔线// 步骤1: 创建音频流handle = audio_stream_creat_by_name("default"); // 按名称创建音频流if (handle == NULL) { // 检查创建是否成功printf("错误: 音频流创建失败\n"); // 输出错误信息test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}// 步骤2: 配置音频参数printf("步骤2: 配置音频参数...\n"); // 输出步骤信息// 设置采样率ret = audio_stream_set_sample_rate(handle, 48000); // 设置采样率为48kHzif (ret != 0) { // 检查设置是否成功printf("错误: 采样率设置失败\n"); // 输出错误信息audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}// 设置采样位宽ret = audio_stream_set_sample_width(handle, 16); // 设置采样位宽为16位if (ret != 0) { // 检查设置是否成功printf("错误: 采样位宽设置失败\n"); // 输出错误信息audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}// 设置声道数ret = audio_stream_set_channels(handle, 2); // 设置声道数为立体声if (ret != 0) { // 检查设置是否成功printf("错误: 声道数设置失败\n"); // 输出错误信息audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}// 步骤3: 验证参数配置printf("步骤3: 验证参数配置...\n"); // 输出步骤信息int actual_rate = audio_stream_get_sample_rate(handle); // 获取实际采样率int actual_width = audio_stream_get_sample_width(handle); // 获取实际采样位宽int actual_channels = audio_stream_get_channels(handle); // 获取实际声道数printf(" 期望采样率: 48000, 实际: %d\n", actual_rate); // 输出采样率对比printf(" 期望采样位宽: 16, 实际: %d\n", actual_width); // 输出采样位宽对比 printf(" 期望声道数: 2, 实际: %d\n", actual_channels); // 输出声道数对比if (actual_rate == 48000 && actual_width == 16 && actual_channels == 2) { // 验证参数printf("✅ 参数配置验证通过\n"); // 输出成功信息} else {printf("❌ 参数配置验证失败\n"); // 输出失败信息audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}// 步骤4: 清理资源audio_stream_release(handle); // 释放音频流test_record_result(ctx, 1); // 记录成功结果return 0; // 返回成功
}
/*** 测试用例3: 音频效果功能测试* 设计模式: 装饰器模式 - 测试音效增强功能* 性能分析: 功能开关测试 + 状态验证*/
int test_audio_effects(test_context_t* ctx)
{astream_handle handle; // 音频流句柄printf("\n🎧 测试3: 音频效果功能\n"); // 输出测试开始信息printf("================================\n"); // 分隔线handle = audio_stream_creat(); // 创建音频流if (handle == NULL) { // 检查创建是否成功printf("错误: 音频流创建失败\n"); // 输出错误信息test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}// 测试回声消除printf("测试回声消除(AEC)...\n"); // 输出测试信息audio_stream_set_aec(handle, 1); // 启用回声消除printf("✅ AEC已启用\n"); // 输出成功信息// 测试噪声抑制printf("测试噪声抑制(ANR)...\n"); // 输出测试信息audio_stream_set_anr(handle, 1); // 启用噪声抑制printf("✅ ANR已启用\n"); // 输出成功信息// 测试自动增益控制printf("测试自动增益控制(AGC)...\n"); // 输出测试信息audio_stream_set_agc(handle, 1); // 启用自动增益控制printf("✅ AGC已启用\n"); // 输出成功信息// 测试静音功能printf("测试静音功能...\n"); // 输出测试信息audio_stream_set_mute(handle, 1); // 启用静音printf("✅ 静音已启用\n"); // 输出成功信息audio_stream_set_mute(handle, 0); // 禁用静音printf("✅ 静音已禁用\n"); // 输出成功信息audio_stream_release(handle); // 释放音频流test_record_result(ctx, 1); // 记录成功结果return 0; // 返回成功
}
/*** 测试用例4: 音频编码测试* 设计模式: 策略模式 - 测试不同编码格式* 性能分析: 编码器切换 + 端口管理测试*/
int test_audio_encoding(test_context_t* ctx)
{astream_handle handle; // 音频流句柄port_info_t *port; // 端口信息int ret; // 返回值printf("\n🔊 测试4: 音频编码功能\n"); // 输出测试开始信息printf("================================\n"); // 分隔线handle = audio_stream_creat(); // 创建音频流if (handle == NULL) { // 检查创建是否成功printf("错误: 音频流创建失败\n"); // 输出错误信息test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}// 步骤1: 配置编码参数printf("步骤1: 配置编码参数...\n"); // 输出步骤信息audio_stream_set_coding_type(handle, AUDIO_ENCODER_AAC); // 设置AAC编码printf("✅ 编码类型设置为AAC\n"); // 输出成功信息// 步骤2: 启动音频流printf("步骤2: 启动音频流...\n"); // 输出步骤信息ret = audio_stream_start(handle); // 启动音频流if (ret != 0) { // 检查启动是否成功printf("错误: 音频流启动失败\n"); // 输出错误信息audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}printf("✅ 音频流启动成功\n"); // 输出成功信息// 步骤3: 启动编码并获取端口printf("步骤3: 启动音频编码...\n"); // 输出步骤信息port = audio_stream_start_enc(handle); // 启动编码并获取端口if (port == NULL) { // 检查端口获取是否成功printf("错误: 编码启动失败\n"); // 输出错误信息audio_stream_stop(handle); // 停止音频流audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}printf("✅ 编码启动成功, 端口: %p\n", port); // 输出成功信息// 步骤4: 启用编码端口printf("步骤4: 启用编码端口...\n"); // 输出步骤信息ret = audio_stream_enable_port(handle, port); // 启用编码端口if (ret != 0) { // 检查启用是否成功printf("错误: 端口启用失败\n"); // 输出错误信息audio_stream_stop_enc(handle, port); // 停止编码audio_stream_stop(handle); // 停止音频流audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}printf("✅ 编码端口启用成功\n"); // 输出成功信息// 步骤5: 模拟编码数据处理(这里简单等待)printf("步骤5: 模拟编码数据处理...\n"); // 输出步骤信息sleep(2); // 等待2秒模拟处理时间printf("✅ 编码数据处理完成\n"); // 输出成功信息// 步骤6: 停止编码printf("步骤6: 停止音频编码...\n"); // 输出步骤信息ret = audio_stream_stop_enc(handle, port); // 停止编码if (ret != 0) { // 检查停止是否成功printf("错误: 编码停止失败\n"); // 输出错误信息audio_stream_stop(handle); // 停止音频流audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}printf("✅ 音频编码停止成功\n"); // 输出成功信息// 步骤7: 停止音频流printf("步骤7: 停止音频流...\n"); // 输出步骤信息ret = audio_stream_stop(handle); // 停止音频流if (ret != 0) { // 检查停止是否成功printf("错误: 音频流停止失败\n"); // 输出错误信息audio_stream_release(handle); // 释放音频流test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}printf("✅ 音频流停止成功\n"); // 输出成功信息audio_stream_release(handle); // 释放音频流test_record_result(ctx, 1); // 记录成功结果return 0; // 返回成功
}
/*** 测试用例5: 多音频流并发测试* 设计模式: 观察者模式 - 监控多个音频流状态* 性能分析: 并发压力测试 + 资源竞争检测*/
int test_multiple_audio_streams(test_context_t* ctx)
{astream_handle handles[2]; // 多个音频流句柄int i; // 循环变量printf("\n🎶 测试5: 多音频流并发测试\n"); // 输出测试开始信息printf("================================\n"); // 分隔线// 步骤1: 创建多个音频流printf("步骤1: 创建多个音频流...\n"); // 输出步骤信息for (i = 0; i < 2; i++) { // 循环创建2个音频流handles[i] = audio_stream_creat(); // 创建音频流if (handles[i] == NULL) { // 检查创建是否成功printf("错误: 音频流%d创建失败\n", i); // 输出错误信息// 清理已创建的音频流for (int j = 0; j < i; j++) { // 遍历已创建的音频流audio_stream_release(handles[j]); // 释放音频流}test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}printf("✅ 音频流%d创建成功: %p\n", i, handles[i]); // 输出成功信息}// 步骤2: 配置不同的参数printf("步骤2: 配置不同的参数...\n"); // 输出步骤信息audio_stream_set_sample_rate(handles[0], 44100); // 设置流0采样率44.1kHzaudio_stream_set_channels(handles[0], 1); // 设置流0为单声道audio_stream_set_coding_type(handles[0], AUDIO_ENCODER_PCM); // 设置流0为PCM编码audio_stream_set_sample_rate(handles[1], 48000); // 设置流1采样率48kHz audio_stream_set_channels(handles[1], 2); // 设置流1为立体声audio_stream_set_coding_type(handles[1], AUDIO_ENCODER_AAC); // 设置流1为AAC编码printf("✅ 参数配置完成\n"); // 输出成功信息// 步骤3: 启动多个音频流printf("步骤3: 启动多个音频流...\n"); // 输出步骤信息for (i = 0; i < 2; i++) { // 循环启动2个音频流if (audio_stream_start(handles[i]) != 0) { // 启动音频流printf("错误: 音频流%d启动失败\n", i); // 输出错误信息// 清理资源for (int j = 0; j < 2; j++) { // 遍历所有音频流if (j <= i) audio_stream_stop(handles[j]); // 停止已启动的流audio_stream_release(handles[j]); // 释放音频流}test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}printf("✅ 音频流%d启动成功\n", i); // 输出成功信息}// 步骤4: 模拟并发运行printf("步骤4: 模拟并发运行...\n"); // 输出步骤信息sleep(3); // 等待3秒模拟并发运行printf("✅ 并发运行完成\n"); // 输出成功信息// 步骤5: 停止和释放所有音频流printf("步骤5: 停止和释放所有音频流...\n"); // 输出步骤信息for (i = 0; i < 2; i++) { // 循环处理2个音频流audio_stream_stop(handles[i]); // 停止音频流audio_stream_release(handles[i]); // 释放音频流printf("✅ 音频流%d清理完成\n", i); // 输出成功信息}test_record_result(ctx, 1); // 记录成功结果return 0; // 返回成功
}
/*** 测试用例6: 性能基准测试* 设计模式: 模板方法模式 - 标准化性能测试流程* 性能分析: 时间统计 + 资源使用监控*/
int test_performance_benchmark(test_context_t* ctx)
{astream_handle handle; // 音频流句柄struct timespec start, end; // 时间统计long long duration; // 持续时间printf("\n⏱️ 测试6: 性能基准测试\n"); // 输出测试开始信息printf("================================\n"); // 分隔线// 测试创建性能printf("测试音频流创建性能...\n"); // 输出测试信息clock_gettime(CLOCK_MONOTONIC, &start); // 记录开始时间handle = audio_stream_creat(); // 创建音频流clock_gettime(CLOCK_MONOTONIC, &end); // 记录结束时间if (handle == NULL) { // 检查创建是否成功printf("错误: 性能测试创建失败\n"); // 输出错误信息test_record_result(ctx, 0); // 记录失败结果return -1; // 返回错误}duration = (end.tv_sec - start.tv_sec) * 1000000000LL + // 计算纳秒时间(end.tv_nsec - start.tv_nsec);printf("✅ 音频流创建时间: %lld 纳秒\n", duration); // 输出创建时间// 测试启动性能printf("测试音频流启动性能...\n"); // 输出测试信息clock_gettime(CLOCK_MONOTONIC, &start); // 记录开始时间audio_stream_start(handle); // 启动音频流clock_gettime(CLOCK_MONOTONIC, &end); // 记录结束时间duration = (end.tv_sec - start.tv_sec) * 1000000000LL + // 计算纳秒时间(end.tv_nsec - start.tv_nsec);printf("✅ 音频流启动时间: %lld 纳秒\n", duration); // 输出启动时间// 测试编码启动性能printf("测试编码启动性能...\n"); // 输出测试信息clock_gettime(CLOCK_MONOTONIC, &start); // 记录开始时间port_info_t *port = audio_stream_start_enc(handle); // 启动编码clock_gettime(CLOCK_MONOTONIC, &end); // 记录结束时间if (port) { // 如果编码启动成功duration = (end.tv_sec - start.tv_sec) * 1000000000LL + // 计算纳秒时间(end.tv_nsec - start.tv_nsec);printf("✅ 编码启动时间: %lld 纳秒\n", duration); // 输出编码启动时间// 清理编码audio_stream_stop_enc(handle, port); // 停止编码}// 清理资源audio_stream_stop(handle); // 停止音频流audio_stream_release(handle); // 释放音频流test_record_result(ctx, 1); // 记录成功结果return 0; // 返回成功
}
// 设计模式: 观察者模式 - 信号处理
void signal_handler(int sig)
{printf("\n收到信号 %d, 正在停止测试...\n", sig); // 输出信号信息g_ctx.running = 0; // 设置停止标志
}
/*** 主测试函数* 设计模式: 外观模式 - 提供统一的测试接口* 性能分析: 总体测试统计 + 结果汇总*/
int main(int argc, char *argv[])
{test_context_t* ctx; // 测试上下文int overall_result = 0; // 总体结果printf("================================\n"); // 分隔线printf(" Linux音频框架测试程序\n"); // 程序标题printf("================================\n"); // 分隔线// 注册信号处理signal(SIGINT, signal_handler); // 注册Ctrl+C信号处理signal(SIGTERM, signal_handler); // 注册终止信号处理// 初始化测试上下文ctx = test_context_create(); // 创建测试上下文if (!ctx) { // 检查创建是否成功printf("错误: 测试上下文创建失败\n"); // 输出错误信息return -1; // 返回错误}printf("测试开始...\n\n"); // 输出开始信息// 执行测试用例if (test_audio_stream_create_release(ctx) != 0) // 测试用例1overall_result = -1; // 更新总体结果if (test_audio_parameter_config(ctx) != 0) // 测试用例2overall_result = -1; // 更新总体结果if (test_audio_effects(ctx) != 0) // 测试用例3overall_result = -1; // 更新总体结果if (test_audio_encoding(ctx) != 0) // 测试用例4overall_result = -1; // 更新总体结果if (test_multiple_audio_streams(ctx) != 0) // 测试用例5overall_result = -1; // 更新总体结果if (test_performance_benchmark(ctx) != 0) // 测试用例6overall_result = -1; // 更新总体结果// 输出测试总结printf("\n================================\n"); // 分隔线printf(" 测试总结\n"); // 总结标题printf("================================\n"); // 分隔线printf("总测试用例: %d\n", ctx->test_case); // 输出总测试用例数printf("通过: %d\n", ctx->success_count); // 输出通过数printf("失败: %d\n", ctx->fail_count); // 输出失败数printf("成功率: %.2f%%\n", // 输出成功率(float)ctx->success_count / ctx->test_case * 100);if (overall_result == 0) { // 如果总体成功printf("\n🎉 所有测试通过!\n"); // 输出成功信息} else {printf("\n💥 部分测试失败!\n"); // 输出失败信息}// 清理资源test_context_destroy(ctx); // 销毁测试上下文return overall_result; // 返回总体结果
}关键测试函数树形结构对比分析
测试框架结构
test_main ├── test_audio_stream_create_release (基础功能) │ ├── 音频流创建 │ ├── 状态验证 │ ├── 引用计数 │ └── 资源释放 ├── test_audio_parameter_config (参数配置) │ ├── 采样率设置 │ ├── 采样位宽设置 │ ├── 声道数设置 │ └── 参数回读验证 ├── test_audio_effects (音效测试) │ ├── 回声消除 │ ├── 噪声抑制 │ ├── 自动增益 │ └── 静音控制 ├── test_audio_encoding (编码测试) │ ├── 编码器配置 │ ├── 流启动停止 │ ├── 端口管理 │ └── 编码流程 ├── test_multiple_audio_streams (并发测试) │ ├── 多流创建 │ ├── 参数差异化 │ ├── 并发运行 │ └── 资源清理 └── test_performance_benchmark (性能测试)├── 创建时间├── 启动时间└── 编码时间
与音频框架模块对比
测试模块 ↔ 框架模块 ─────────────────────────────── 基础功能测试 ↔ audio_stream_creat/release 参数配置测试 ↔ set_sample_rate/width/channels 音效测试 ↔ set_aec/anr/agc/mute 编码测试 ↔ start_enc/stop_enc + 端口管理 并发测试 ↔ 多实例管理 + 资源分配 性能测试 ↔ 时间统计 + 资源监控
框架管理机制分析
1. 资源管理
引用计数: 通过
audio_stream_inc_refcnt管理对象生命周期端口管理: 使用位图管理分流器端口分配
状态机: 严格的状态转换确保操作序列正确性
2. 并发控制
互斥锁:
ASTREAM_LOCK/UNLOCK保护共享资源线程安全: 所有API都设计为线程安全
资源隔离: 多音频流实例间资源隔离
3. 错误处理
参数验证:
oscl_param_check宏进行参数检查状态验证: 操作前验证状态机状态
资源清理: 失败时自动清理已分配资源
4. 性能优化
对象池: 预分配音频流对象减少动态分配
位图操作: 高效的端口管理
批量操作: 支持多端口批量启用/禁用
这个测试框架全面覆盖了音频框架的所有核心功能,通过模块化的测试用例验证每个组件的正确性和性能。
