自己写的jitter buffer

一、软件设计需求

 

 

二、设计概要

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。

你可能感兴趣的:(自己写的jitter buffer)