SRT协议简介
SRT(Secure Reliable Transport)是一种开源视频传输协议,由Haivision和Wowza共同推动,旨在通过不可预测的网络(如互联网)实现安全、可靠的低延迟视频流传输。它结合了低延迟、抗丢包和加密功能,广泛应用于直播、远程制作和IP视频传输领域。
SRT的核心特性
低延迟:SRT通过优化传输机制,将端到端延迟控制在毫秒级,适合实时互动场景。
抗丢包:利用ARQ(自动重传请求)和FEC(前向纠错)技术,在丢包率高的网络中保持流畅传输。
端到端加密:支持AES加密,确保数据安全,防止窃听或篡改。
动态码率适应:根据网络状况自动调整码率,避免拥塞。
SRT的工作原理
SRT基于UDP协议,通过以下机制实现可靠传输:
- 握手阶段:建立连接时协商参数(如延迟、加密密钥)。
- 数据传输:发送方将数据分片并添加序列号,接收方通过ACK/NACK反馈丢包情况。
- 丢包恢复:通过重传或FEC修复丢失的数据包。
- 拥塞控制:基于网络状况动态调整发送速率。
SRT的应用场景
- 直播与广播:用于电视台、赛事直播等低延迟要求的场景。
- 远程制作:支持多地协同的云端视频制作。
- 企业通信:适用于视频会议、远程监控等实时交互应用。
SRT与同类协议对比
- RTMP:延迟较高(1-3秒),基于TCP,适合推流但不适应复杂网络。
- WebRTC:专注于浏览器端实时通信,但缺乏SRT的抗丢包优化。
- RIST:同为可靠传输协议,但SRT在开源生态和工具链上更成熟。
-
libsrt
-
libsrt 是一个开源库,用于支持 SRT(Secure Reliable Transport)协议。SRT 是一种基于 UDP 的低延迟流传输协议,广泛应用于视频直播、远程制作和低延迟流媒体传输场景。libsrt 提供了 SRT 协议的实现,支持加密、错误恢复和拥塞控制等功能。
-
服务端实现
- 自定义选项:
-
struct ProtocolOption
{
//同步方式发送和接收,为false就是异步
bool synSendReceive;
//发送缓冲区大小
int sendBufferSize;
//接收缓冲区大小
int receiveBufferSize;
//丢包后最大重传次数,0表示一直重传
int lossMaxTTL;
//延迟容忍时间(毫秒)
int latency;
//单个包最大长度
int payload;
//时间戳防抖动模式开启
bool tsbpdMode;
//关闭socket时等待数据全部发送完再退出
bool linger;ProtocolOption()
{
synSendReceive = true;
sendBufferSize = 80 * 1024 * 1024;
receiveBufferSize = 80 * 1024 * 1024;
lossMaxTTL = 10;
latency = 100;
payload = 1316;
tsbpdMode = true;
linger = false;
}
}; -
//创建服务
-
srt_startup();
SRTSOCKET handle = srt_create_socket();configureReceiveSocket(handle , opt);
sockaddr_in local_addr;
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(port);
local_addr.sin_addr.s_addr = INADDR_ANY;if (srt_bind(handle , (sockaddr*)&local_addr, sizeof(local_addr)) == SRT_ERROR)
return;if (srt_listen(handle , 10) == SRT_ERROR)
return;int nEpollid = srt_epoll_create();
int events = SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR;
if (SRT_ERROR == srt_epoll_add_usock(m_nEpollid, m_handle, &events))
return; -
//开启处理线程
-
std::shared_ptr<std::thread> ptrReceiveThread;
-
ptrReceiveThread.reset(new std::thread(threadFunction, this, handle, nEpollid ));
-
//线程函数
-
void threadFunction(SRTSOCKET handle, int epollid)
-
{
-
const int srtrfdslenmax = 100;
SRTSOCKET srtrfds[srtrfdslenmax];
std::fill(srtrfds, srtrfds + srtrfdslenmax, SRT_INVALID_SOCK); -
while (1)
{
int srtrfdslen = srtrfdslenmax;
//不处理系统socket,只处理srt的socket
int n = srt_epoll_wait(nEpollid, &srtrfds[0], &srtrfdslen, 0, 0, 100, 0, 0, 0, 0);
if (n <= 0)
continue;//处理事件
for (int i = 0; i < n; i++)
{
SRTSOCKET s = srtrfds[i];
if (s == SRT_INVALID_SOCK)
continue;//句柄去重
for (int j = 1; j < n; j++)
{
const SRTSOCKET next_s = srtrfds[j];
if (s == next_s)
srtrfds[j] = SRT_INVALID_SOCK;
}SRT_SOCKSTATUS status = srt_getsockstate(s);
if ((status == SRTS_BROKEN) ||
(status == SRTS_NONEXIST) ||
(status == SRTS_CLOSED))
{
cout << "source disconnected. status=" << status << endl;
srt_close(s);
srt_epoll_remove_usock(nEpollid, s);
continue;
}
else if (s == m_handle && status == SRTS_LISTENING)
{
SRTSOCKET fhandle;
sockaddr_storage clientaddr;
int addrlen = sizeof(clientaddr);fhandle = srt_accept(m_handle, (sockaddr*)&clientaddr, &addrlen);
if (SRT_INVALID_SOCK == fhandle)
{
cout << "srt_accept: " << srt_getlasterror_str() << endl;
continue;
} -
}
-
else if(status == SRTS_CONNECTED)
char buffer[2000];
{-
int bytes_read = 0;
int total_bytes_read = 0;
SRT_MSGCTRL mctrl;
srt_msgctrl_init(&mctrl); -
bytes_read = srt_recvmsg2(s, buffer, sizeof(buffer), &mctrl);
total_bytes_read += bytes_read;
if (bytes_read <= 0)
break;
-
-
}
-
}
- }
-
//配置选项方法
-
void configureReceiveSocket(SRTSOCKET sock, ProtocolOption opt)
{
int live = SRTT_LIVE;
srt_setsockflag(sock, SRTO_TRANSTYPE, &live, sizeof(live));int lossmaxttl = opt.lossMaxTTL;
srt_setsockflag(sock, SRTO_LOSSMAXTTL, &lossmaxttl, sizeof(lossmaxttl));int rcvbuf = opt.receiveBufferSize;
srt_setsockflag(sock, SRTO_UDP_RCVBUF, &rcvbuf, sizeof(rcvbuf));int latency = opt.latency;;
srt_setsockflag(sock, SRTO_LATENCY, &latency, sizeof(latency));int syn = opt.synSendReceive ? 1 : 0;
srt_setsockflag(sock, SRTO_RCVSYN, &syn, sizeof(syn));//单个数据包大小
int payload = opt.payload;
srt_setsockflag(sock, SRTO_PAYLOADSIZE, &payload, sizeof(int));//等待数据发送完毕再关闭
int linger = opt.linger ? 1 : 0;
srt_setsockflag(sock, SRTO_LINGER, &linger, sizeof(int));//时间戳防抖动策略
int tsbpd = opt.tsbpdMode ? 1 : 0;
srt_setsockflag(sock, SRTO_TSBPDMODE, &tsbpd, sizeof(int));
}

220

被折叠的 条评论
为什么被折叠?



