一、软件设计需求
二、设计概要
Java层先做sip协商,协商成功后调用缓冲模块并传递相关参数,缓冲模块监听两路约定端口,根据数据包的序列号做数据排序,按时间做数据对齐,整理完毕后从两路端口发送给live555服务器,live555转成一路数据发送给Android opencore播放框架。
三、软件大概流程
1. 初始化数据结构,获取handle;
2. 设置handle,创建线程:
a) 创建video RTCP线程,接收到video RTCP并初始化first_rtp和ntp后退出;
b) 创建audio RTCP线程,接收到audio RTCP并初始化first_rtp和ntp后退出;
c) 创建sync线程,转换得出video和audio各自的first_rtp_timestamp完成后退出;
d) 创建video数据处理线程,负责video数据的接收与发送;
e) 创建audio数据处理线程,负责audio数据的接收与发送;
f) 创建STC线程,每1ms更新一次,在RTCP完成同步后,在video数据处理线程和audio数据处理线程中每个packet发送时间受限于STC时间;
g) 创建monitor线程,负责统计数据的接收与发送情况以及可能涉及到的需要打点的情况;
3. 只有接收到java层停止命令,循环线程才会退出,线程不会主动退出;
四、重要数据流程图解
1. RTCP数据同步流程
2. 数据处理线程threadWrapper流程图
五、重要数据结构
typePI v_packet = {
.ptype= "video",//结构体名称标识
.iname_idle= V_IDLE_LIST,//详细结构体名称数字标识
.iname_busy= V_BUSY_LIST, //详细结构体名称数字标识
.name_idle= "v_idle",//详细结构体名称字符串标识
.name_busy= "v_busy",//详细结构体名称字符串标识
.first_idle= NULL,//idle链表首指针
.first_busy= NULL,//busy链表首指针
.decode_header= rtpDecoderNALUHeader,//函数指针,指向解NALU解码
.set_priv_para= setVideoPara,//设置video私有数据
.read_stc= readSTC,//读取stc时间
.timescale= 90000,//目前我们平台所用videotimescale
};
typePI a_packet = {
.ptype= "audio",
.iname_idle= A_IDLE_LIST,
.iname_busy= A_BUSY_LIST,
.name_idle= "a_idle",
.name_busy= "a_busy",
.first_idle= NULL,
.first_busy= NULL,
.decode_header= rtpDecoderAMRHeader,//函数指针,指向AMR解码,目前未用到
.set_priv_para= setAudioPara, //设置video私有数据
.read_stc= readSTC,
.timescale= 8000, //目前我们平台所用videotimescale
};
//list结构体
typedef struct typePI{
char*ptype; //结构体名称标识
intiname_idle; //详细结构体名称数字标识
intiname_busy; //详细结构体名称数字标识
char*name_idle; //详细结构体名称字符串标识
char*name_busy; //详细结构体名称字符串标识
typePacketInfo*first_idle; //idle链表首指针
typePacketInfo*first_busy; //busy链表首指针
bool(*decode_header)(struct typePI *x, typePacketInfo *p, bool *finished); //函数指针,指向 video和audio各自的解码
structtimeval start_time;//起始时间,用来标识开始缓冲时间
structtimeval end_time; //结束时间,用来计算播放缓冲时延
typeSocketInfosi;//socket相关的文件描述符,端口,超时等
typeBufferStatusbs;//仅保留分配缓冲区个数,大小,其余向typeStatistics cs迁移
//typeTestDatatd;//需要删除
void(*set_priv_para)(struct typePI *pi);//指向video与audio私有数据设置
int64_t(*read_stc)(void); //ms级,读取stc时间用来控制发包时间
boolenable;//用来表明该结构体对应的线程否被允许创建
typeRTCPInfori;//获取RTCP SR内的相关数据
boolforce_out;//强制退出标识
pthread_ttid;//本结构体所使用的线程tid号
inttimescale;//音视频标尺
typeStatisticscs;//数据统计信息
}typePI;
//socket fd与port结构体
typedef struct typeSocketInfo{
intrecv_fd;
intsend_fd;
intrtcp_send_fd;
intrtcp_recv_fd;
intrtp_recv_port;
intrtp_send_port;
intrtcp_recv_port;
intrtcp_send_port;
inttimeout_us;//socket发送/接收超时
intrtcp_timeout;//rtcp接收超时
}typeSocketInfo;
Video与Audio与端口示例如下:
六、待确认问题(待补充…)
1. 缓冲区长度计算
Video
delay_time(sec)*帧率*帧长度/1500 = 缓冲区长度
Audio
delay_time(sec)*帧率*1 = 缓冲区长度
考虑到突发情况,缓冲区冗余设多少?120%?
2. Socket超时时间设定
Socket接收与发送超时目前暂定200ms。