基于usrsctp接入webrtc服务器中的DataChannel功能
1.DataChannel简介在webrtc中通过DataChannel,可以实现点对点的消息通信,这些消息和音视频数据是通过同一udp socket被发送给对方的,因此也是具备NAT穿透功能的。DataChannel可以用来进行聊天消息的发送、点对点传送文件等,作为音视频通信外的另一种通信方式,DataChannel的意义还是很重要的。2.方案概述待续...参考:1、SCTP通用报文格式2、ht
·
一.DataChannel简介
在webrtc中通过DataChannel,可以实现点对点的消息通信,这些消息和音视频数据是通过同一udp socket被发送给对方的,因此也是具备NAT穿透功能的。DataChannel可以用来进行聊天消息的发送、点对点传送文件等,作为音视频通信外的另一种通信方式,DataChannel的意义还是很重要的。
二.背景概述
在开发MediaSoup级联服务时,我们使用了PlainTransport与其对接,也就是说不使用webrtc native提供的相关接口,直接使用纯RTP流传输音视频数据,这样的话DataChannel也需要靠自己实现了。
三、代码
RtpIO是一个的UDP读写类
#include "sctp_association.h"
#include "rtc_util.h"
namespace mrtc {
#define DATA_CHANNEL_PPID_STRING (51) //字符串数据
#define DATA_CHANNEL_PPID_BINARY (53) //二进制数据
bool SctpAssociation::s_sctpRunning = false;
SctpAssociation::SctpAssociation(RtpIO* rtpIO)
: m_rtpIO(rtpIO)
{
int ret = 0;
Init();
usrsctp_register_address(this);
m_localSock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, onRecvSctpData, onSendSctpData, 0, this);
assert(NULL != m_localSock);
usrsctp_set_upcall(m_localSock, onUpcall, this);
struct sockaddr_conn sconn = {0};
sconn.sconn_family = AF_CONN;
sconn.sconn_port = htons(5000);
sconn.sconn_addr = this;
ret = usrsctp_bind(m_localSock, (struct sockaddr *)&sconn, sizeof(sconn));
assert(0 == ret);
ret = usrsctp_listen(m_localSock, 1);
assert(0 == ret);
RTC_INFO("Sctp Association Create Success!");
}
SctpAssociation::~SctpAssociation()
{
if(NULL != m_localSock) { usrsctp_close(m_localSock); }
if(NULL != m_remoteSock) { usrsctp_close(m_remoteSock); }
usrsctp_deregister_address(this);
RTC_DEBUG("~SctpAssociation");
}
void SctpAssociation::Init()
{
if(false == s_sctpRunning)
{
s_sctpRunning = true;
usrsctp_init_nothreads(0, sctpDataToUdp, sctpDebug);
usrsctp_sysctl_set_sctp_ecn_enable(0);
RTC_INFO("Sctp Association Init Success!");
}
}
int SctpAssociation::sctpDataToUdp(void* addr, void* buffer, size_t length, uint8_t tos, uint8_t set_df)
{
SctpAssociation* p = (SctpAssociation*)addr;
assert(nullptr != p);
p->m_rtpIO->writeData((const char*)buffer, length);
return 0;
}
void SctpAssociation::sctpDebug(const char *format, ...)
{
char buffer[4 * 1024] = {0};
va_list ap;
va_start(ap, format);
vsprintf(buffer, format, ap);
// Remove the artificial carriage return set by usrsctp.
buffer[std::strlen(buffer) - 1] = '\0';
RTC_WARNING("sctpDebug: %s", buffer);
va_end(ap);
}
void SctpAssociation::Destroy()
{
usrsctp_finish();
s_sctpRunning = false;
}
bool SctpAssociation::IsSctp(const void* data, size_t len)
{
return (
(len >= 12) &&
(Get2Bytes((const uint8_t*)data, 0) == 5000) &&
(Get2Bytes((const uint8_t*)data, 2) == 5000)
);
}
void SctpAssociation::sendSctpMessage(const void* data, size_t len)
{
int ret = 0;
struct sctp_sndinfo sndinfo = {0};
sndinfo.snd_sid = 0;
sndinfo.snd_flags = SCTP_EOR;
sndinfo.snd_ppid = htonl(DATA_CHANNEL_PPID_STRING);
sndinfo.snd_context = 0;
sndinfo.snd_assoc_id = 0;
if(NULL == m_remoteSock)
{
RTC_ERROR("send Sctp Message Error! Not accept");
return;
}
ret = usrsctp_sendv(m_remoteSock, data, len, NULL, 0, (void *)&sndinfo, (socklen_t)sizeof(sndinfo), SCTP_SENDV_SNDINFO, 0);
if(0 > ret)
{
perror("usrsctp_sendv");
RTC_ERROR("send Sctp Message Error! ret = %d", ret);
}
}
void SctpAssociation::processSctpData(const void* data, size_t len)
{
usrsctp_conninput(this, data, len, 0);
}
int SctpAssociation::onRecvSctpData(struct socket* sock, union sctp_sockstore addr, void* data, size_t datalen, struct sctp_rcvinfo rcvinfo, int flags, void* ulp_info)
{
SctpAssociation* p = (SctpAssociation*)ulp_info;
assert(nullptr != p);
if(nullptr != p->m_sctpRecvDataCallback)
{
p->m_sctpRecvDataCallback(data, datalen);
}
return 1;
}
int SctpAssociation::onSendSctpData(struct socket* sock, uint32_t sb_free, void* ulp_info)
{
return 1;
}
void SctpAssociation::onUpcall(struct socket* sock, void* arg, int flgs)
{
SctpAssociation* p = (SctpAssociation*)arg;
assert(nullptr != p);
if(NULL == p->m_remoteSock)
{
p->m_remoteSock = usrsctp_accept(sock, NULL, NULL);
}
}
}
参考:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献1条内容
所有评论(0)