一、简介
本文主要站在使用者角度对AVCom模块进行说明,模块内部的算法等实现细节可以参考www.mediapro.cc 上的详细文档说明。AVCom是一个封装了FEC前向纠错和QOS收端质量保证的RTP传输模块。它能够在传统RTP基础上增强数据传输对于丢包、乱序、重复包等情况的抵抗力,特别适用于WIFI、3G、4G等无线信道。这一切对于外层用户来说均是透明的,用户只需要调用发送接口,传入音视频数据即可,当接收到远端发送的音视频数据时,模块将调用相应的回调接口送出音视频数据,用户无需关心FEC、QOS等实现细节。
几种常见的使用场景:
(1)客户端-服务器模型
在这种模型下,一般服务器具备公网地址,客户端则私网地址。客户端在TCP登录到服务器后,服务器将做两件事情:
(A)为客户端分配两对共4个端口(紧挨着,比如10086、10087、10088、10089),这组端口将唯一用于该客户端的UDP音视频数据收发,其中10086将用于音频的RTP、10087用于音频的RTCP、10088用于视频的RTP、10089用于视频的RTCP。分配的端口将通过TCP返回给客户端,一般只需要返回起始端口10086就行,可以由它推算出其他端口。
(B)为该客户端创建一个AVCom对象。因为服务端并不知道客户端的IP和端口,创建时只将调用AVCom的“服务端Create接口”,提供自身服务器IP和上述(A)中为客户端分配的端口。当10086端口收到客户端发送的音频数据(或者心跳握手包数据)时,AVCom将记住对方的IP和端口以便服务端向客户端发送音频数据,视频的收发也是一样的道理。也就是说服务端AVCom创建之初并不能向客户端发送数据,只是在等待到了客户端的数据包后(心跳包或者音视频包)方能得到对方的出口IP和端口,并翻转作为发送的目的地址。这里用户并不需要关心细节,他只需要创建好就行,地址翻转均是AVCom自己实现的。如果客户端一直不向服务器发送音视频数据,是不是服务器就永远没法向客户端发送呢?当然不是,不管是客户端还是服务器,AVCom一旦create,其内部就将创建一个心跳包发送定时器,定时向对方发送握手包,后面我们会介绍该握手包还实现了收端传输信息的反馈,便于发端调整FEC策略。
客户端在得到了10086的端口信息后,便可以创建一个AVCom对象了,创建时调用AVCom的“客户端Create接口”,提供自身的IP和本地端口、服务器的IP和服务器给自己分配的端口。本地端口一般来说是固定的,避免与其他应用冲突即可。若需要实现本地多个客户端,则需要另外考虑如何分配。
接下来,客户端、服务器便可以通过AVCom提供的SendVideo、SendAudio向对方发送经过压缩后的音视频数据了,在收到对方的数据后AVCom的虚函数OnReceiveVideo、OnReceiveAudio将被调用,将收到的数据分别送音视频解码器即可。这里的接收回调为虚函数,方便用户自由实现接收后的处理动作。
(2)客户端-客户端模型
原理与客户端-服务器模型类似,不同的是双方均知道对方的IP和端口,所以都使用“客户端Create接口”创建各自AVCom即可。
二、接口说明
模块提供DLL和静态库版本,DLL可供其他语言调用(C#、Delphi等)
(1)Create接口
(A)服务器类型Create接口
BOOL Create(char *strLocalIP, USHORT shLocalPort, char * strRemoteIP, UINT unQosDropDelay,
FEC_REDUN_METHOD_TYPE eRedunMethod, UINT unRedunRatio,
ReciveDataCallBackFunc pfVideoRecCallBack = NULL,
ReciveDataCallBackFunc pfAudioRecCallBack = NULL, void *pObject = NULL);
说明:
/***
* 创建RtpAvCom(服务器方式)
* @param strLocalIP: 本地IP地址
* @param shLocalPort: 本地收发端口(该端口用于音频RTP,必须为偶数,+1为音频RTCP端口,+2为视频RTP端口,+3为视频RTCP端口)
* @param strRemoteIP: 对方IP地址,这个IP是从客户端TCP登陆时获得的客户端出口IP,AVCom将使用这个IP做UDP非法攻击的判定,若在合法的UDP端口上接收到其他IP的包,则认为是攻击行为,将予以丢弃。另外,AVCom还将对每一个发送的音视频包前加入随机CRC码,收端进行CRC校验,避免非法包的入侵。
* @param unQosDropDelay: QOS丢包时延ms(即发现丢包时的最大等待时延,等待该时长后若仍未收到则认定丢包,比如收到1号包、3号包,那么继续等待unQosDropDelay ms后,若仍未收到2号包,则认定2号包丢失,即便往后再收到2号包也做丢弃处理)
* @param eRedunMethod: FEC冗余度类型:动态或者固定(服务器下行到客户端的链路可以采用动态FEC冗余度以节省带宽,具体见文档)
* @param unRedunRatio: FEC冗余度为固定时,所采用的冗余度百分比,如:20, 30, 40, 50, 60, 70。
* @param pfVideoRecCallBack: 接收到对方发送的视频数据后的回调函数,用于C接口。当做类使用AVCom时需设置为NULL
* @param pfAudioRecCallBack: 接收到对方发送的音频数据后的回调函数,用于C接口。当做类使用AVCom时需设置为NULL
* @param pObject: 上述两个回调函数特定形参,因回调函数为static类型,本形参一般为对象指针,方便回调函数内访问成员变量,避免使用全局变量,用于C接口。当做类使用AVCom时需设置为NULL
* @return: 返回TRUE成功,为FALSE则失败
(B)客户端类型Create接口
BOOL Create(char *strLocalIP, USHORT shLocalPort, char *strRemoteIP, USHORT shRemotePort,
UINT unQosDropDelay,
FEC_REDUN_METHOD_TYPE eRedunMethod, UINT unRedunRatio,
ReciveDataCallBackFunc pfVideoRecCallBack = NULL,
ReciveDataCallBackFunc pfAudioRecCallBack = NULL,
void *pObject = NULL, UINT unFecGroupSize = DEFAULT_GROUP_SIZE);
* @param strLocalIP: 本地IP地址
* @param shLocalPort: 本地收发端口(一般固定)
* @param strRemoteIP: 服务端IP地址
* @param shRemotePort: 服务端收发端口(登陆时从服务器获得)
* @param unQosDropDelay: QOS丢包时延ms(即发现丢包时的最大等待时延,等待该时长后若仍未收到则认定丢包,具体见文档)
* @param eRedunMethod: FEC冗余度类型:动态或者固定(客户端接口时建议设置为固定模式,服务器与服务器之间通讯时(此时双方都知道对方的公网IP和端口,二者可以都创建为客户端模式)建议设置为较高的固定冗余度,因为双方的网络条件较好,传输的数据量不多但极为重要。客户端到服务器的上行通讯时建议设置为中等的固定冗余度,因为用户家庭上行带宽有限,传输的上行数据往往非常重要)
* @param unRedunRatio: FEC冗余度为固定时,所采用的冗余度百分比,如:20, 30, 40, 50, 60, 70。
* @param pfVideoRecCallBack: 接收到对方发送的视频数据后的回调函数,用于C接口。当做类使用AVCom时需设置为NULL
* @param pfAudioRecCallBack: 接收到对方发送的音频数据后的回调函数,用于C接口。当做类使用AVCom时需设置为NULL
* @param pObject: 上述两个回调函数特定形参,因回调函数为static类型,本形参一般为对象指针,方便回调函数内访问成员变量,避免使用全局变量,用于C接口。当做类使用AVCom时需设置为NULL
* @return: 返回TRUE成功,为FALSE则失败
(2)Close接口
void Close();
* @释放Create创建的资源
(3)音视频发送接口
BOOL SendAudioData(int nLen, BYTE *byBuf);
BOOL SendVideoData(int nLen, BYTE *byBuf);
(4)音视频接收虚函数[用户实现内容]
virtual void OnReciveAudioData(int nLen, BYTE *byBuf)
virtual void OnReciveVideoData(int nLen, BYTE *byBuf)