mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Refine SRT code, with StateThread adpater
This commit is contained in:
parent
3ed4aed824
commit
94fa0ff7bd
25 changed files with 4131 additions and 68 deletions
789
trunk/src/protocol/srs_service_st_srt.cpp
Normal file
789
trunk/src/protocol/srs_service_st_srt.cpp
Normal file
|
@ -0,0 +1,789 @@
|
|||
//
|
||||
// Copyright (c) 2013-2021 The SRS Authors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT or MulanPSL-2.0
|
||||
//
|
||||
|
||||
#include <srs_service_st_srt.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_core_autofree.hpp>
|
||||
|
||||
#define SET_SRT_OPT_STR(srtfd, optname, buf, size) \
|
||||
if (srt_setsockflag(srtfd, optname, buf, size) == SRT_ERROR) { \
|
||||
std::stringstream ss; \
|
||||
ss << "srtfd=" << srtfd << ",set " << #optname \
|
||||
<< " failed,err=" << srt_getlasterror_str(); \
|
||||
return srs_error_new(ERROR_SRT_SOCKOPT, "%s", ss.str().c_str()); \
|
||||
}
|
||||
|
||||
#define SET_SRT_OPT(srtfd, optname, val) \
|
||||
if (srt_setsockflag(srtfd, optname, &val, sizeof(val)) == SRT_ERROR) { \
|
||||
std::stringstream ss; \
|
||||
ss << "srtfd=" << srtfd << ",set " << #optname << "=" << val \
|
||||
<< " failed,err=" << srt_getlasterror_str(); \
|
||||
return srs_error_new(ERROR_SRT_SOCKOPT, "%s", ss.str().c_str()); \
|
||||
}
|
||||
|
||||
#define GET_SRT_OPT(srtfd, optname, val) \
|
||||
do { \
|
||||
int size = sizeof(val); \
|
||||
if (srt_getsockflag(srtfd, optname, &val, &size) == SRT_ERROR) { \
|
||||
std::stringstream ss; \
|
||||
ss << "srtfd=" << srtfd << ",get " << #optname \
|
||||
<< " failed,err=" << srt_getlasterror_str(); \
|
||||
return srs_error_new(ERROR_SRT_SOCKOPT, "%s", ss.str().c_str()); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static srs_error_t do_srs_srt_listen(SRTSOCKET srt_fd, addrinfo* r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = srs_srt_nonblock(srt_fd)) != srs_success) {
|
||||
return srs_error_wrap(err, "nonblock");
|
||||
}
|
||||
|
||||
if (srt_bind(srt_fd, r->ai_addr, r->ai_addrlen) == -1) {
|
||||
return srs_error_new(ERROR_SOCKET_BIND, "bind");
|
||||
}
|
||||
|
||||
if (srt_listen(srt_fd, 100) == -1) {
|
||||
return srs_error_new(ERROR_SOCKET_LISTEN, "listen");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static srs_error_t do_srs_srt_get_streamid(SRTSOCKET srt_fd, string& streamid)
|
||||
{
|
||||
// SRT max streamid length is 512.
|
||||
char sid[512];
|
||||
GET_SRT_OPT(srt_fd, SRTO_STREAMID, sid);
|
||||
|
||||
streamid.assign(sid);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_socket(SRTSOCKET* pfd)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
SRTSOCKET srt_fd = 0;
|
||||
if ((srt_fd = srt_create_socket()) < 0) {
|
||||
return srs_error_new(ERROR_SOCKET_CREATE, "create srt socket");
|
||||
}
|
||||
|
||||
*pfd = srt_fd;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_socket_with_default_option(SRTSOCKET* pfd)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
SRTSOCKET srt_fd = 0;
|
||||
if ((srt_fd = srt_create_socket()) < 0) {
|
||||
return srs_error_new(ERROR_SOCKET_CREATE, "create srt socket");
|
||||
}
|
||||
|
||||
if ((err = srs_srt_nonblock(srt_fd)) != srs_success) {
|
||||
return srs_error_wrap(err, "nonblock");
|
||||
}
|
||||
|
||||
if ((err = srs_srt_set_tsbpdmode(srt_fd, false)) != srs_success) {
|
||||
return srs_error_wrap(err, "set tsbpdmode");
|
||||
}
|
||||
|
||||
if ((err = srs_srt_set_tlpktdrop(srt_fd, false)) != srs_success) {
|
||||
return srs_error_wrap(err, "set tlpktdrop");
|
||||
}
|
||||
|
||||
if ((err = srs_srt_set_latency(srt_fd, false)) != srs_success) {
|
||||
return srs_error_wrap(err, "set latency");
|
||||
}
|
||||
|
||||
*pfd = srt_fd;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_listen(SRTSOCKET srt_fd, std::string ip, int port)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
char sport[8];
|
||||
snprintf(sport, sizeof(sport), "%d", port);
|
||||
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
|
||||
addrinfo* r = NULL;
|
||||
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
|
||||
if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) {
|
||||
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "getaddrinfo hints=(%d,%d,%d)",
|
||||
hints.ai_family, hints.ai_socktype, hints.ai_flags);
|
||||
}
|
||||
|
||||
if ((err = do_srs_srt_listen(srt_fd, r)) != srs_success) {
|
||||
srt_close(srt_fd);
|
||||
return srs_error_wrap(err, "srt_fd=%d", srt_fd);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_nonblock(SRTSOCKET srt_fd)
|
||||
{
|
||||
int sync = 0;
|
||||
SET_SRT_OPT(srt_fd, SRTO_SNDSYN, sync);
|
||||
SET_SRT_OPT(srt_fd, SRTO_RCVSYN, sync);
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_maxbw(SRTSOCKET srt_fd, int maxbw)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_MAXBW, maxbw);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_mss(SRTSOCKET srt_fd, int mss)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_MSS, mss);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_payload_size(SRTSOCKET srt_fd, int payload_size)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_PAYLOADSIZE, payload_size);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_connect_timeout(SRTSOCKET srt_fd, int timeout)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_CONNTIMEO, timeout);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_peer_idle_timeout(SRTSOCKET srt_fd, int timeout)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_PEERIDLETIMEO, timeout);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_tsbpdmode(SRTSOCKET srt_fd, bool tsbpdmode)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_TSBPDMODE, tsbpdmode);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_sndbuf(SRTSOCKET srt_fd, int sndbuf)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_SNDBUF, sndbuf);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_rcvbuf(SRTSOCKET srt_fd, int rcvbuf)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_RCVBUF, rcvbuf);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_tlpktdrop(SRTSOCKET srt_fd, bool tlpktdrop)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_TLPKTDROP, tlpktdrop);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_latency(SRTSOCKET srt_fd, int latency)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_LATENCY, latency);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_rcv_latency(SRTSOCKET srt_fd, int rcv_latency)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_RCVLATENCY, rcv_latency);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_peer_latency(SRTSOCKET srt_fd, int peer_latency)
|
||||
{
|
||||
SET_SRT_OPT(srt_fd, SRTO_PEERLATENCY, peer_latency);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_set_streamid(SRTSOCKET srt_fd, const std::string& streamid)
|
||||
{
|
||||
SET_SRT_OPT_STR(srt_fd, SRTO_STREAMID, streamid.data(), streamid.size());
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_maxbw(SRTSOCKET srt_fd, int& maxbw)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_MAXBW, maxbw);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_mss(SRTSOCKET srt_fd, int& mss)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_MSS, mss);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_payload_size(SRTSOCKET srt_fd, int& payload_size)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_PAYLOADSIZE, payload_size);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_connect_timeout(SRTSOCKET srt_fd, int& timeout)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_CONNTIMEO, timeout);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_peer_idle_timeout(SRTSOCKET srt_fd, int& timeout)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_PEERIDLETIMEO, timeout);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_tsbpdmode(SRTSOCKET srt_fd, bool& tsbpdmode)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_TSBPDMODE, tsbpdmode);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_sndbuf(SRTSOCKET srt_fd, int& sndbuf)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_SNDBUF, sndbuf);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_rcvbuf(SRTSOCKET srt_fd, int& rcvbuf)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_RCVBUF, rcvbuf);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_tlpktdrop(SRTSOCKET srt_fd, bool& tlpktdrop)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_TLPKTDROP, tlpktdrop);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_latency(SRTSOCKET srt_fd, int& latency)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_LATENCY, latency);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_rcv_latency(SRTSOCKET srt_fd, int& rcv_latency)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_RCVLATENCY, rcv_latency);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_peer_latency(SRTSOCKET srt_fd, int& peer_latency)
|
||||
{
|
||||
GET_SRT_OPT(srt_fd, SRTO_PEERLATENCY, peer_latency);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_streamid(SRTSOCKET srt_fd, std::string& streamid)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = do_srs_srt_get_streamid(srt_fd, streamid)) != srs_success) {
|
||||
return srs_error_wrap(err, "srt get streamid");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_local_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// discovery client information
|
||||
sockaddr_storage addr;
|
||||
int addrlen = sizeof(addr);
|
||||
if (srt_getsockname(srt_fd, (sockaddr*)&addr, &addrlen) == -1) {
|
||||
return srs_error_new(ERROR_SRT_SOCKOPT, "srt_getsockname");
|
||||
}
|
||||
|
||||
char saddr[64];
|
||||
char* h = (char*)saddr;
|
||||
socklen_t nbh = (socklen_t)sizeof(saddr);
|
||||
const int r0 = getnameinfo((const sockaddr*)&addr, addrlen, h, nbh,NULL, 0, NI_NUMERICHOST);
|
||||
if (r0) {
|
||||
return srs_error_new(ERROR_SRT_SOCKOPT, "getnameinfo");
|
||||
}
|
||||
|
||||
switch(addr.ss_family) {
|
||||
case AF_INET:
|
||||
port = ntohs(((sockaddr_in*)&addr)->sin_port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
port = ntohs(((sockaddr_in6*)&addr)->sin6_port);
|
||||
break;
|
||||
}
|
||||
|
||||
ip.assign(saddr);
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// discovery client information
|
||||
sockaddr_storage addr;
|
||||
int addrlen = sizeof(addr);
|
||||
if (srt_getpeername(srt_fd, (sockaddr*)&addr, &addrlen) == -1) {
|
||||
return srs_error_new(ERROR_SRT_SOCKOPT, "srt_getpeername");
|
||||
}
|
||||
|
||||
char saddr[64];
|
||||
char* h = (char*)saddr;
|
||||
socklen_t nbh = (socklen_t)sizeof(saddr);
|
||||
const int r0 = getnameinfo((const sockaddr*)&addr, addrlen, h, nbh,NULL, 0, NI_NUMERICHOST);
|
||||
if (r0) {
|
||||
return srs_error_new(ERROR_SRT_SOCKOPT, "getnameinfo");
|
||||
}
|
||||
|
||||
switch(addr.ss_family) {
|
||||
case AF_INET:
|
||||
port = ntohs(((sockaddr_in*)&addr)->sin_port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
port = ntohs(((sockaddr_in6*)&addr)->sin6_port);
|
||||
break;
|
||||
}
|
||||
|
||||
ip.assign(saddr);
|
||||
return err;
|
||||
}
|
||||
|
||||
SrsSrtPoller::SrsSrtPoller()
|
||||
{
|
||||
srt_epoller_fd_ = -1;
|
||||
}
|
||||
|
||||
SrsSrtPoller::~SrsSrtPoller()
|
||||
{
|
||||
if (srt_epoller_fd_ > 0) {
|
||||
srt_epoll_release(srt_epoller_fd_);
|
||||
}
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtPoller::initialize()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srt_epoller_fd_ = srt_epoll_create();
|
||||
events_.resize(1024);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtPoller::add_socket(SrsSrtSocket* srt_skt)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
int events = srt_skt->events();
|
||||
SRTSOCKET srtfd = srt_skt->fd();
|
||||
|
||||
int ret = srt_epoll_add_usock(srt_epoller_fd_, srtfd, &events);
|
||||
|
||||
srs_info("srt poller %d add srt socket %d, events=%d", srt_epoller_fd_, srtfd, events);
|
||||
if (ret == SRT_ERROR) {
|
||||
return srs_error_new(ERROR_SRT_EPOLL, "srt epoll add socket=%lu failed, err=%s", srtfd, srt_getlasterror_str());
|
||||
}
|
||||
|
||||
// record srtfd to SrsSrtSocket*
|
||||
fd_sockets_[srtfd] = srt_skt;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtPoller::del_socket(SrsSrtSocket* srt_skt)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
SRTSOCKET srtfd = srt_skt->fd();
|
||||
|
||||
int ret = srt_epoll_remove_usock(srt_epoller_fd_, srtfd);
|
||||
srs_info("srt poller %d remove srt socket %d", srt_epoller_fd_, srtfd);
|
||||
if (ret == SRT_ERROR) {
|
||||
return srs_error_new(ERROR_SRT_EPOLL, "srt epoll remove socket=%lu failed, err=%s", srtfd, srt_getlasterror_str());
|
||||
}
|
||||
|
||||
fd_sockets_.erase(srtfd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtPoller::wait(int timeout_ms)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// wait srt event fired, will timeout after `timeout_ms` milliseconds.
|
||||
int ret = srt_epoll_uwait(srt_epoller_fd_, events_.data(), events_.size(), timeout_ms);
|
||||
if (ret < 0) {
|
||||
return srs_error_new(ERROR_SRT_EPOLL, "srt_epoll_uwait, ret=%d", ret);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ret; ++i) {
|
||||
SRT_EPOLL_EVENT event = events_[i];
|
||||
map<SRTSOCKET, SrsSrtSocket*>::iterator iter = fd_sockets_.find(event.fd);
|
||||
if (iter == fd_sockets_.end()) {
|
||||
srs_assert(false);
|
||||
}
|
||||
|
||||
SrsSrtSocket* srt_skt = iter->second;
|
||||
srs_assert(srt_skt != NULL);
|
||||
|
||||
// notify error, don't notify read/write event.
|
||||
if (event.events & SRT_EPOLL_ERR) {
|
||||
srt_skt->notify_error();
|
||||
} else {
|
||||
if (event.events & SRT_EPOLL_IN) {
|
||||
srt_skt->notify_readable();
|
||||
}
|
||||
if (event.events & SRT_EPOLL_OUT) {
|
||||
srt_skt->notify_writeable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtPoller::mod_socket(SrsSrtSocket* srt_skt)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
int events = srt_skt->events();
|
||||
SRTSOCKET srtfd = srt_skt->fd();
|
||||
|
||||
int ret = srt_epoll_update_usock(srt_epoller_fd_, srtfd, &events);
|
||||
srs_info("srt poller %d update srt socket %d, events=%d", srt_epoller_fd_, srtfd, events);
|
||||
|
||||
if (ret == SRT_ERROR) {
|
||||
return srs_error_new(ERROR_SRT_EPOLL, "srt epoll update socket=%lu failed, err=%s", srtfd, srt_getlasterror_str());
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SrsSrtSocket::SrsSrtSocket(SrsSrtPoller* srt_poller, SRTSOCKET srt_fd)
|
||||
{
|
||||
srt_poller_ = srt_poller;
|
||||
srt_fd_ = srt_fd;
|
||||
has_error_ = 0;
|
||||
read_cond_ = srs_cond_new();
|
||||
write_cond_ = srs_cond_new();
|
||||
|
||||
recv_timeout_ = 5 * SRS_UTIME_SECONDS;
|
||||
send_timeout_ = 5 * SRS_UTIME_SECONDS;
|
||||
|
||||
recv_bytes_ = 0;
|
||||
send_bytes_ = 0;
|
||||
|
||||
events_ = 0;
|
||||
}
|
||||
|
||||
SrsSrtSocket::~SrsSrtSocket()
|
||||
{
|
||||
srs_error_t err = srt_poller_->del_socket(this);
|
||||
if (err != srs_success) {
|
||||
srs_error("srt poller remove socket failed, err=%s", srs_error_desc(err).c_str());
|
||||
srs_error_reset(err);
|
||||
}
|
||||
|
||||
srs_cond_destroy(read_cond_);
|
||||
srs_cond_destroy(write_cond_);
|
||||
|
||||
srs_trace("close srt_fd=%d", srt_fd_);
|
||||
srt_close(srt_fd_);
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::connect(const string& ip, int port)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
sockaddr_in inaddr;
|
||||
inaddr.sin_family = AF_INET;
|
||||
inaddr.sin_port = htons(port);
|
||||
// TODO: FIXME: inet_addr is deprecated
|
||||
inaddr.sin_addr.s_addr = inet_addr(ip.c_str());
|
||||
|
||||
int ret = srt_connect(srt_fd_, (const sockaddr*)&inaddr, sizeof(inaddr));
|
||||
|
||||
// TODO: FIXME: check return value.
|
||||
SRT_SOCKSTATUS srt_status = srt_getsockstate(srt_fd_);
|
||||
if (srt_status != SRTS_CONNECTED) {
|
||||
// Connect is in progress, wait until it finish or error.
|
||||
if ((err = wait_writeable()) != srs_success) {
|
||||
return srs_error_wrap(err, "wait writeable");
|
||||
}
|
||||
|
||||
// Double check if connect is established.
|
||||
srt_status = srt_getsockstate(srt_fd_);
|
||||
if (srt_status != SRTS_CONNECTED) {
|
||||
return srs_error_new(ERROR_SRT_IO, "srt_connect, err=%s", srt_getlasterror_str());
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::accept(SRTSOCKET* client_srt_fd)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
while (true) {
|
||||
sockaddr_in inaddr;
|
||||
int addrlen = sizeof(inaddr);
|
||||
SRTSOCKET srt_fd = srt_accept(srt_fd_, (sockaddr*)&inaddr, &addrlen);
|
||||
if (srt_fd == SRT_INVALID_SOCK) {
|
||||
if (srt_getlasterror(NULL) == SRT_EASYNCRCV) {
|
||||
// Accept would block, wait until new client connect or error.
|
||||
if ((err = wait_readable()) != srs_success) {
|
||||
return srs_error_wrap(err, "wait readable");
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
return srs_error_new(ERROR_SRT_IO, "srt_accept, err=%s", srt_getlasterror_str());
|
||||
}
|
||||
} else {
|
||||
*client_srt_fd = srt_fd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::recvmsg(void* buf, size_t size, ssize_t* nread)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
while (true) {
|
||||
int ret = srt_recvmsg(srt_fd_, (char*)buf, size);
|
||||
if (ret < 0) {
|
||||
if (srt_getlasterror(NULL) == SRT_EASYNCRCV) {
|
||||
if ((err = wait_readable()) != srs_success) {
|
||||
return srs_error_wrap(err, "wait readable");
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
return srs_error_new(ERROR_SRT_IO, "srt_recvmsg, err=%s", srt_getlasterror_str());
|
||||
}
|
||||
} else {
|
||||
recv_bytes_ += ret;
|
||||
*nread = ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::sendmsg(void* buf, size_t size, ssize_t* nwrite)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
while (true) {
|
||||
int ret = srt_sendmsg(srt_fd_, (const char*)buf, size, -1, 1);
|
||||
if (ret < 0) {
|
||||
if (srt_getlasterror(NULL) == SRT_EASYNCSND) {
|
||||
if ((err = wait_writeable()) != srs_success) {
|
||||
return srs_error_wrap(err, "wait writeable");
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
return srs_error_new(ERROR_SRT_IO, "srt_sendmsg, err=%s", srt_getlasterror_str());
|
||||
}
|
||||
} else {
|
||||
send_bytes_ += ret;
|
||||
*nwrite = ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::wait_readable()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// Check if error occured.
|
||||
if ((err = check_error()) != srs_success) {
|
||||
return srs_error_wrap(err, "has error");
|
||||
}
|
||||
|
||||
// Subscribe in and error event
|
||||
if ((err = enable_read()) != srs_success) {
|
||||
return srs_error_wrap(err, "enable read");
|
||||
}
|
||||
|
||||
// Wait event fired or timeout.
|
||||
int ret = srs_cond_timedwait(read_cond_, recv_timeout_);
|
||||
// TODO: FIXME: need to disable it?
|
||||
err = disable_read();
|
||||
if (err != srs_success) {
|
||||
srs_freep(err);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
// Timeout and events no fired.
|
||||
if (errno == ETIME) {
|
||||
return srs_error_new(ERROR_SRT_TIMEOUT, "srt socket %d timeout", srt_fd_);
|
||||
}
|
||||
// Interrupted, maybe coroutine terminated.
|
||||
if (errno == EINTR) {
|
||||
return srs_error_new(ERROR_SRT_INTERRUPT, "srt socket %d interrupted", srt_fd_);
|
||||
}
|
||||
return srs_error_new(ERROR_SRT_IO, "srt socket %d wait read", srt_fd_);
|
||||
}
|
||||
|
||||
// Check if we are notify with error event.
|
||||
if ((err = check_error()) != srs_success) {
|
||||
return srs_error_wrap(err, "has error");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::wait_writeable()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if ((err = check_error()) != srs_success) {
|
||||
return srs_error_wrap(err, "has error");
|
||||
}
|
||||
|
||||
if ((err = enable_write()) != srs_success) {
|
||||
return srs_error_wrap(err, "enable write");
|
||||
}
|
||||
|
||||
int ret = srs_cond_timedwait(write_cond_, send_timeout_);
|
||||
err = disable_write();
|
||||
if (err != srs_success) {
|
||||
srs_freep(err);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (errno == ETIME) {
|
||||
return srs_error_new(ERROR_SRT_TIMEOUT, "srt socket %d timeout", srt_fd_);
|
||||
}
|
||||
if (errno == EINTR) {
|
||||
return srs_error_new(ERROR_SRT_INTERRUPT, "srt socket %d interrupted", srt_fd_);
|
||||
}
|
||||
return srs_error_new(ERROR_SRT_IO, "srt socket %d wait write", srt_fd_);
|
||||
}
|
||||
|
||||
if ((err = check_error()) != srs_success) {
|
||||
return srs_error_wrap(err, "has error");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void SrsSrtSocket::notify_readable()
|
||||
{
|
||||
srs_cond_signal(read_cond_);
|
||||
}
|
||||
|
||||
void SrsSrtSocket::notify_writeable()
|
||||
{
|
||||
srs_cond_signal(write_cond_);
|
||||
}
|
||||
|
||||
void SrsSrtSocket::notify_error()
|
||||
{
|
||||
// mark error, and check when read/write
|
||||
has_error_ = true;
|
||||
srs_cond_signal(read_cond_);
|
||||
srs_cond_signal(write_cond_);
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::enable_read()
|
||||
{
|
||||
return enable_event(SRT_EPOLL_IN | SRT_EPOLL_ERR);
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::disable_read()
|
||||
{
|
||||
return disable_event(SRT_EPOLL_IN);
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::enable_write()
|
||||
{
|
||||
return enable_event(SRT_EPOLL_OUT | SRT_EPOLL_ERR);
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::disable_write()
|
||||
{
|
||||
return disable_event(SRT_EPOLL_OUT);
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::enable_event(int event) {
|
||||
srs_error_t err = srs_success;
|
||||
// Event has been subscribed.
|
||||
if ((events_ & event) == event) {
|
||||
return err;
|
||||
}
|
||||
|
||||
int old_events = events_;
|
||||
events_ |= event;
|
||||
|
||||
if (old_events == 0) {
|
||||
err = srt_poller_->add_socket(this);
|
||||
} else {
|
||||
err = srt_poller_->mod_socket(this);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::disable_event(int event) {
|
||||
srs_error_t err = srs_success;
|
||||
// Event has been unsubscribed.
|
||||
if ((events_ & event) == 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
events_ &= (~event);
|
||||
|
||||
if (events_ == 0) {
|
||||
err = srt_poller_->del_socket(this);
|
||||
} else {
|
||||
err = srt_poller_->mod_socket(this);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSrtSocket::check_error() {
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (has_error_) {
|
||||
return srs_error_new(ERROR_SRT_IO, "has error");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
154
trunk/src/protocol/srs_service_st_srt.hpp
Normal file
154
trunk/src/protocol/srs_service_st_srt.hpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
//
|
||||
// Copyright (c) 2013-2021 The SRS Authors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT or MulanPSL-2.0
|
||||
//
|
||||
|
||||
#ifndef SRS_SERVICE_ST_SRT_HPP
|
||||
#define SRS_SERVICE_ST_SRT_HPP
|
||||
|
||||
#include <srs_core.hpp>
|
||||
#include <srs_service_st.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <srt/srt.h>
|
||||
|
||||
// Create srt socket only, with libsrt's default option.
|
||||
extern srs_error_t srs_srt_socket(SRTSOCKET* pfd);
|
||||
|
||||
// Create srt socket with srs recommend default option(tsbpdmode=false,tlpktdrop=false,latency=0,sndsyn=0,rcvsyn=0)
|
||||
extern srs_error_t srs_srt_socket_with_default_option(SRTSOCKET* pfd);
|
||||
|
||||
// For server, listen at SRT endpoint.
|
||||
extern srs_error_t srs_srt_listen(SRTSOCKET srt_fd, std::string ip, int port);
|
||||
|
||||
// Set read/write no block.
|
||||
extern srs_error_t srs_srt_nonblock(SRTSOCKET srt_fd);
|
||||
|
||||
// Set SRT options.
|
||||
extern srs_error_t srs_srt_set_maxbw(SRTSOCKET srt_fd, int maxbw);
|
||||
extern srs_error_t srs_srt_set_mss(SRTSOCKET srt_fd, int mss);
|
||||
extern srs_error_t srs_srt_set_payload_size(SRTSOCKET srt_fd, int payload_size);
|
||||
extern srs_error_t srs_srt_set_connect_timeout(SRTSOCKET srt_fd, int timeout);
|
||||
extern srs_error_t srs_srt_set_peer_idle_timeout(SRTSOCKET srt_fd, int timeout);
|
||||
extern srs_error_t srs_srt_set_tsbpdmode(SRTSOCKET srt_fd, bool tsbpdmode);
|
||||
extern srs_error_t srs_srt_set_sndbuf(SRTSOCKET srt_fd, int sndbuf);
|
||||
extern srs_error_t srs_srt_set_rcvbuf(SRTSOCKET srt_fd, int rcvbuf);
|
||||
extern srs_error_t srs_srt_set_tlpktdrop(SRTSOCKET srt_fd, bool tlpktdrop);
|
||||
extern srs_error_t srs_srt_set_latency(SRTSOCKET srt_fd, int latency);
|
||||
extern srs_error_t srs_srt_set_rcv_latency(SRTSOCKET srt_fd, int rcv_latency);
|
||||
extern srs_error_t srs_srt_set_peer_latency(SRTSOCKET srt_fd, int peer_latency);
|
||||
extern srs_error_t srs_srt_set_streamid(SRTSOCKET srt_fd, const std::string& streamid);
|
||||
|
||||
// Get SRT options.
|
||||
extern srs_error_t srs_srt_get_maxbw(SRTSOCKET srt_fd, int& maxbw);
|
||||
extern srs_error_t srs_srt_get_mss(SRTSOCKET srt_fd, int& mss);
|
||||
extern srs_error_t srs_srt_get_payload_size(SRTSOCKET srt_fd, int& payload_size);
|
||||
extern srs_error_t srs_srt_get_connect_timeout(SRTSOCKET srt_fd, int& timeout);
|
||||
extern srs_error_t srs_srt_get_peer_idle_timeout(SRTSOCKET srt_fd, int& timeout);
|
||||
extern srs_error_t srs_srt_get_tsbpdmode(SRTSOCKET srt_fd, bool& tsbpdmode);
|
||||
extern srs_error_t srs_srt_get_sndbuf(SRTSOCKET srt_fd, int& sndbuf);
|
||||
extern srs_error_t srs_srt_get_rcvbuf(SRTSOCKET srt_fd, int& rcvbuf);
|
||||
extern srs_error_t srs_srt_get_tlpktdrop(SRTSOCKET srt_fd, bool& tlpktdrop);
|
||||
extern srs_error_t srs_srt_get_latency(SRTSOCKET srt_fd, int& latency);
|
||||
extern srs_error_t srs_srt_get_rcv_latency(SRTSOCKET srt_fd, int& rcv_latency);
|
||||
extern srs_error_t srs_srt_get_peer_latency(SRTSOCKET srt_fd, int& peer_latency);
|
||||
extern srs_error_t srs_srt_get_streamid(SRTSOCKET srt_fd, std::string& streamid);
|
||||
|
||||
// Get SRT socket info.
|
||||
extern srs_error_t srs_srt_get_local_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port);
|
||||
extern srs_error_t srs_srt_get_remote_ip_port(SRTSOCKET srt_fd, std::string& ip, int& port);
|
||||
|
||||
class SrsSrtSocket;
|
||||
|
||||
// Srt poller, subscribe/unsubscribed events and wait them fired.
|
||||
class SrsSrtPoller
|
||||
{
|
||||
public:
|
||||
SrsSrtPoller();
|
||||
virtual ~SrsSrtPoller();
|
||||
public:
|
||||
srs_error_t initialize();
|
||||
srs_error_t add_socket(SrsSrtSocket* srt_skt);
|
||||
srs_error_t mod_socket(SrsSrtSocket* srt_skt);
|
||||
srs_error_t del_socket(SrsSrtSocket* srt_skt);
|
||||
srs_error_t wait(int timeout_ms);
|
||||
private:
|
||||
// Find SrsSrtSocket* context by SRTSOCKET.
|
||||
std::map<SRTSOCKET, SrsSrtSocket*> fd_sockets_;
|
||||
int srt_epoller_fd_;
|
||||
std::vector<SRT_EPOLL_EVENT> events_;
|
||||
};
|
||||
|
||||
// Srt ST socket, wrap SRT io and make it adapt to ST-thread.
|
||||
class SrsSrtSocket
|
||||
{
|
||||
public:
|
||||
SrsSrtSocket(SrsSrtPoller* srt_poller, SRTSOCKET srt_fd);
|
||||
virtual ~SrsSrtSocket();
|
||||
public: // IO API
|
||||
srs_error_t connect(const std::string& ip, int port);
|
||||
srs_error_t accept(SRTSOCKET* client_srt_fd);
|
||||
srs_error_t recvmsg(void* buf, size_t size, ssize_t* nread);
|
||||
srs_error_t sendmsg(void* buf, size_t size, ssize_t* nwrite);
|
||||
public:
|
||||
SRTSOCKET fd() const { return srt_fd_; }
|
||||
int events() const { return events_; }
|
||||
public:
|
||||
void set_recv_timeout(srs_utime_t tm) { recv_timeout_ = tm; }
|
||||
void set_send_timeout(srs_utime_t tm) { send_timeout_ = tm; }
|
||||
srs_utime_t get_send_timeout() { return send_timeout_; }
|
||||
srs_utime_t get_recv_timeout() { return recv_timeout_; }
|
||||
int64_t get_send_bytes() { return send_bytes_; }
|
||||
int64_t get_recv_bytes() { return recv_bytes_; }
|
||||
// Yiled coroutine and wait this socket readable.
|
||||
srs_error_t wait_readable();
|
||||
// Yiled coroutine and wait this socket writeable.
|
||||
srs_error_t wait_writeable();
|
||||
// Notify this socket readable, and resume coroutine later.
|
||||
void notify_readable();
|
||||
// Notify this socket writeable, and resume coroutine later.
|
||||
void notify_writeable();
|
||||
// Notify this socket error, resume coroutine later and error will return in all the operator of this socket.
|
||||
void notify_error();
|
||||
public:
|
||||
// Subscribed IN/ERR event to srt poller.
|
||||
srs_error_t enable_read();
|
||||
// Unsubscribed IN event to srt poller.
|
||||
srs_error_t disable_read();
|
||||
// Subscribed OUT/ERR event to srt poller.
|
||||
srs_error_t enable_write();
|
||||
// Unsubscribed OUT event to srt poller.
|
||||
srs_error_t disable_write();
|
||||
private:
|
||||
srs_error_t enable_event(int event);
|
||||
srs_error_t disable_event(int event);
|
||||
srs_error_t check_error();
|
||||
|
||||
private:
|
||||
SRTSOCKET srt_fd_;
|
||||
// Mark if some error occured in srt socket.
|
||||
bool has_error_;
|
||||
// When read operator like recvmsg/accept would block, wait this condition timeout or notified,
|
||||
// and the coroutine itself will be yiled and resume when condition be notified.
|
||||
srs_cond_t read_cond_;
|
||||
// When write operator like sendmsg/connectt would block, wait this condition timeout or notified,
|
||||
// and the coroutine itself will be yiled and resume when condition be notified.
|
||||
srs_cond_t write_cond_;
|
||||
|
||||
srs_utime_t recv_timeout_;
|
||||
srs_utime_t send_timeout_;
|
||||
|
||||
int64_t recv_bytes_;
|
||||
int64_t send_bytes_;
|
||||
|
||||
// Event of this socket subscribed.
|
||||
int events_;
|
||||
// Srt poller which this socket attach to.
|
||||
SrsSrtPoller* srt_poller_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue