基本概念
房间:服务器上一个虚拟的概念,进入同一个房间的客户端才允许数据交互,不同房间之间的客户端并无交集。一个房间内客户端的最大数目理论不限,具体根据服务器端设置。服务器允许最大的房间数目同样依据服务端设置而定。最简单的模型是一个房间内一个发布者,一个接收者。
客户端UID:用于标识每个客户端的唯一ID,在系统中不允许有相同UID的客户端同时在线,否则新登录的客户端会将之前的客户端“顶下去”。
音视频发布者:具备上行音视频到服务器(房间)能力的客户端类型,同时也能接收来自服务器(房间)的音视频数据。
音视频接收者:只从服务器(房间)接收音视频的客户端类型,不具备上行能力,比如直播业务中的普通观众。
音视频位置:一个房间内允许同时多个音视频发布者,它们发布音视频到不同的“位置”上,接收者可选择接收某个或某些位置的音视频。目前单个房间允许32个“位置”。发布者登录后可以选择由服务器自动分配空闲的“位置”供其发布,也可以指定“位置”发布,若当前该“位置”上已有其他发布者,后者将顶替前者以保证同一位置上同时只有一个发布者。
音视频接收掩码:客户端可以根据业务需要选择接收房间内某个或某几个位置的音频或视频数据,可以通过设置自己期望接收的掩码到服务器。音频和视频使用各自独立的掩码,每个掩码32bit对应房间内的32个位置。
传输参数:本文传输参数是指视频通道的FEC上行冗余度、上行FEC Group组大小、接收Qos丢包等待时间,音频通道在内部已经根据经验数据配置好了合适的值且不对外开放。对于音视频接收者同样也可以设置FEC上行冗余度、上行FEC Group组大小,只是没有实际意义。
主动API接口:由外层应用主动发起的调用,比如登录、下线、发送音视频等。
被动API接口:称为回调接口更为贴切,比如接收到来自服务器的音视频数据、底层TCP连接状态发生错误的通知、底层要求获取服务器的IP地址。
主动接口
1、登录服务器
int IFace_OnlineUser(UINT unUid, UINT unRoomId, BYTE byUserType, UINT unDomainId = 1, BYTE byNetType = OPERATOR_OTHER);
参数:
@unUid,表示当前客户端使用的唯一用户ID,需要由用户自行保障唯一性。要求非0
@unRoomId,表示当前客户端进入的房间号,要求非0
@byUserType,表示客户端的类型,音视频发布者固定为USER_TYPE_AV_PROVIDE, 音视频接收者为USER_TYPE_AV_PLAYER
@unDomainId,域ID,默认为1即可,具体含义请参考SRTP-Server服务器设计相关文档。
@byNetType,客户端主动告知服务器自己的网络类型,便于域服务器快速分配优选的媒体服务器供其使用。若不提供或未知自己的网络类型,域服务器将根据客户端的出口IP查询IP地址库得到其运营商类型。
返回值:
返回0表示登录成功,返回负数则为失败,负数值为其错误码。
2、下线服务器
void IFace_OfflineUser();
参数:无
返回值:无
3、请求上传音视频到指定位置
int IFace_OnPosition(BYTE &byIndex);
参数:
@byIndex,大于等于0,小于服务器支持的最大位置数(具体依据服务器配置而定,比如[0,32))。特殊值:当设置为255时表示由服务器分配当前空闲的位置,分配结果将写回参数。请求成功后,将自动停止接收自己位置的音视频流(不看自己)。注意位置是从0开始编号。
返回值:
返回0表示请求发布成功,返回负数则为失败,负数值为其错误码。
4、请求从位置上下来
void IFace_OffPosition();
参数:无
返回值:无
对于当前在位置上的音视频发布者,OffPosition将从位置上下来并停止上行音视频数据,但它仍然保持在线状态并能接收其他位置的音视频流。当IFace_OfflineUser调用时将自动从位置上下来,而无需调用IFace_OffPosition(当然Offline前调用OffPosition也无妨)。请求成功后,将自动恢复接收自己之前位置的音视频流(可能有其他客户端加入该位置)。
5、上传视频数据
void IFace_SendVideoStreamData(BYTE* buf, UINT unLen, UINT unDts = 0);
向请求的位置发送视频码流,一次传入带H264起始码的一帧码流。
参数:
@buf,码流存放区。
@unLen,码流长度。
@unDts,可以使用外层时间戳,也可以(建议)由模块内部自行管理时间戳。内部将使用1KHZ时基(毫秒)生成时间戳。
返回值:无
6、上传音频数据
void IFace_SendAudioStreamData(BYTE* buf, UINT unLen, UINT unDts = 0);
向请求的位置发送音频码流,一次传一帧ADTS码流。
参数:
@buf,码流存放区。
@unLen,码流长度。
@unDts,可以使用外层时间戳,也可以(建议)由模块内部自行管理时间戳。内部将使用1KHZ时基(毫秒)生成时间戳。
返回值:无
7、设置音视频下行掩码
void IFace_SetAvTransStatus (UINT unAudioMask, UINT unVideoMask);
通过设置音视频下行掩码,可以选择从服务器接收哪几个位置的音视频数据。每一个bit对应一个位置,最低位对应0号位置,最高位对应31号位置。比如希望接收某个index位置的音视频时,可以设置为:
UINT unMask = 0x1 << (index);
unAudioDownChannelsMask |= unMask;
unVideoDownChannelsMask |= unMask;
当系统停止接收某个index位置的音视频时,可以设置为:
UINT unMask = 0x1 << (index);
unMask = ~unMask;
unAudioDownChannelsMask &= unMask;
unVideoDownChannelsMask &= unMask;
参数:
@unAudioMask,控制音频接收的掩码。
@unVideoMask,控制视频接收的掩码。
返回值:无
8、设置音视频传输参数
void IFace_SetTransParams(UINT unQosDropDelay, FEC_REDUN_METHOD_TYPE eRedunMethod, UINT unRedunRatio, UINT unFecGroupSize);
参数:
@unQosDropDelay,本客户端接收码流时的QOS丢包等待时间,可设置为80。
@eRedunMethod,为上行FEC冗余度方法,建议设置为FIX_REDUN。
@unRedunRatio,固定冗余度时对应的上行冗余比率,建议设置为30。
@unFecGroupSize,为上行FEC分组大小,720P分辨率,建议设置为22,1080P分辨率可设置为28,低分辨率低码率场合建议设置得比较小,比如12
返回值:无
注意:本函数需在IFace_OnlineUser之前调用,本API的使用若有疑问,请联系技术支持获得帮助。
被动接口
被动接口均使用CSDTermCmdIFace类虚函数方式提供,用户需要使用一个类继承CSDTermCmdIFace类并实现该虚函数。
1、请求获取服务器IP地址
virtual void GetDomianSerIp(char *strIp)
virtual void GetDomianSerIpSecond(char *strIp);
参数:
@strIp,在本函数内向该字符串填入服务器IP地址。
返回值:无
服务器可能为双IP的情况,所以我们预留了两个接口,若服务器为单IP,则无需实现GetDomianSerIpSecond函数。
2、收到服务器下发的视频数据
virtual void OnRemoteVideo(BYTE byIndex, BYTE* data, UINT unLen, UINT unPTS, VideoFrameInfo tFrameInfo);
参数:
@byIndex,当前码流属于哪一个“位置”。
@data,指向接收的码流帧存放区域
@unLen,接收码流帧的长度
@unPTS,当前码流帧的时间戳
@tFrameInfo,当前码流的详细描述,其定义如下:
typedef struct VideoFrameInfo
{
UINT unWidth;
UINT unHeight;
BOOL bPacketLost;
BOOL bKeyFrame;
}VideoFrameInfo;
模块内部会解析SPS获得当前码流的宽和高告知外层(可能外层根本不需要这个)。另外两个BOOL变量是用于外层实现丢帧冻结机制时的参考。bPacketLost表示当前帧是否接收完整,若网络丢包且FEC未能恢复时该标志将置位。bKeyFrame表示当前帧是否为IDR关键帧。如果使用这两个标志实现丢帧冻结可以联系技术支持获得帮助。需要说明的是,当没有丢包发生时,本函数的输出应与IFace_SendVideoStreamData函数的输入完全一致。
返回值:无
3、收到服务器下发的音频数据
virtual void OnRemoteAudio(BYTE byIndex, BYTE* data, UINT unLen, UINT unPTS, AudioFrameInfo tFrameInfo);
参数:
@byIndex,当前码流属于哪一个“位置”。
@data,指向接收的码流帧存放区域
@unLen,接收码流帧的长度
@unPTS,当前码流帧的时间戳
@tFrameInfo,当前码流的详细描述,其定义如下:
typedef struct AudioFrameInfo
{
UINT unCodecType;
UINT unSampleRate;
UINT unChannelNum;
}AudioFrameInfo;
音频帧为ADTS格式,其每个包头部均附带了采样率、通道数、编码格式等信息。我们暂时未做解析,tFrameInfo内容不可参考。
返回值:无
4、底层与服务器之间的TCP连接断开
virtual void OnSystemExit(UINT unUid, UINT unExitCause);
参数:
@unUid,当前登录使用的UID。
@unExitCause,当前与服务器的TCP连接已经断开,告知应用层的错误码
客户端登录服务器成功后将建立与服务器之间的TCP长连接,当因为网络等因素导致TCP连接断开时,内部将自动尝试重连。当相同账号在其他位置登录导致本客户端被“顶”下去时,将不会尝试重连,并通过本接口告知上层。
返回值:无
一种简单场景下的使用示意
下面演示一种纯发送端(不接收)的API调用情况,其他场景的API使用可以以此为参考或咨询技术支持。
1、new一个CSDTerminal类对象
2、使用一个现有类继承自CSDTermCmdIFace类,并实现该类的几个虚函数。一个典型的实现为:
// 获取主域服务器的IP地址1
void CTerminalTestDlg::GetDomianSerIp(char *strIp)
{
sprintf(strIp, “13.5.14.9”); //服务器的IP地址
}
// 获取主域服务器的IP地址2
void CTerminalTestDlg::GetDomianSerIpSecond(char *strIp)
{
//服务器为单IP类型时,直接为空
}
//来自底层的退出反馈(比如与服务器之间TCP连接断开时,将通过本接口反馈应用层)
void CTerminalTestDlg::OnSystemExit(UINT unUid, UINT unExitCause)
{
//通知上层
}
// 收到服务器发来的视频
void CTerminalTestDlg::OnRemoteVideo(BYTE byIndex, BYTE* data, UINT unLen, UINT unPTS, VideoFrameInfo tFrameInfo)
{
//纯发端无需处理本函数,直接为空
}
// 收到服务器发来的音频
void CTerminalTestDlg::OnRemoteAudio(BYTE byIndex, BYTE* data, UINT unLen, UINT unPTS, AudioFrameInfo tFrameInfo)
{
//纯发端无需处理本函数,直接为空
}
3、调用一次 IFace_SetTransParams 设置发端上行传输FEC参数,推荐调用为:
IFace_SetTransParams(0, FIX_REDUN, 30, 28);
参数说明:接收时QOS丢包延时为0(发端没有接收,直接设置0),使用固定冗余度方式FIX_REDUN,使用30%的上行冗余,使用Group大小为28
4、调用一次 IFace_OnlineUser 登录服务器,举例调用为:
IFace_OnlineUser(unUserId, unRoomId, USER_TYPE_AV_PROVIDE);
5、调用一次 IFace_OnPosition 设置上传音视频到房间的哪个位置,举例调用为:
IFace_OnPosition(0);
6、调用一次 IFace_SetAvTransStatus 设置发端从服务器接收音视频的情况,推荐调用为:
IFace_SetAvTransStatus(0, 0);
参数说明:第一个参数表示从服务器接收的音频掩码,第二个参数表示接收的视频掩码;二者均为32位整数,每个bit对应一个音视频位置,比如最低bit位对应0号位置,若希望接收该位置的视频或音频则设置该bit为1。因为发端只发不收,所以我们直接设置音频视频接收掩码都为0,表示什么也不接收。
7、N次调用IFace_SendVideoStreamData、IFace_SendAudioStreamData向服务器发送音视频数据
8、 结束前调用一次 IFace_OfflineUser (内部将自动OffPosition)
9、 delete回收CSDTerminal类对象