GB28181单端口接收流支持多线程

This commit is contained in:
ziyue 2021-06-08 14:03:25 +08:00
parent 92736db5b2
commit c4817c6d5f
5 changed files with 85 additions and 51 deletions

@ -1 +1 @@
Subproject commit 58d0e6a4488a290e966b2a0535445dc75af0529c Subproject commit 0c37146426d8fb0a6d98472739ec3bcc683922db

View File

@ -86,55 +86,69 @@ private:
void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable_tcp, const char *local_ip) { void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable_tcp, const char *local_ip) {
//创建udp服务器 //创建udp服务器
Socket::Ptr udp_server = Socket::createSocket(nullptr, true); Socket::Ptr rtp_socket = Socket::createSocket(nullptr, true);
Socket::Ptr rtcp_server = Socket::createSocket(nullptr, true); Socket::Ptr rtcp_socket = Socket::createSocket(nullptr, true);
if (local_port == 0) { if (local_port == 0) {
//随机端口rtp端口采用偶数 //随机端口rtp端口采用偶数
auto pair = std::make_pair(udp_server, rtcp_server); auto pair = std::make_pair(rtp_socket, rtcp_socket);
makeSockPair(pair, local_ip); makeSockPair(pair, local_ip);
//取偶数端口 //取偶数端口
udp_server = pair.first; rtp_socket = pair.first;
rtcp_server = pair.second; rtcp_socket = pair.second;
} else if (!udp_server->bindUdpSock(local_port, local_ip)) { } else if (!rtp_socket->bindUdpSock(local_port, local_ip)) {
//用户指定端口 //用户指定端口
throw std::runtime_error(StrPrinter << "创建rtp端口 " << local_ip << ":" << local_port << " 失败:" << get_uv_errmsg(true)); throw std::runtime_error(StrPrinter << "创建rtp端口 " << local_ip << ":" << local_port << " 失败:" << get_uv_errmsg(true));
} else if(!rtcp_server->bindUdpSock(udp_server->get_local_port() + 1, local_ip)) { } else if(!rtcp_socket->bindUdpSock(rtp_socket->get_local_port() + 1, local_ip)) {
// rtcp端口 // rtcp端口
throw std::runtime_error(StrPrinter << "创建rtcp端口 " << local_ip << ":" << local_port << " 失败:" << get_uv_errmsg(true)); throw std::runtime_error(StrPrinter << "创建rtcp端口 " << local_ip << ":" << local_port << " 失败:" << get_uv_errmsg(true));
} }
//设置udp socket读缓存 //设置udp socket读缓存
SockUtil::setRecvBuf(udp_server->rawFD(), 4 * 1024 * 1024); SockUtil::setRecvBuf(rtp_socket->rawFD(), 4 * 1024 * 1024);
TcpServer::Ptr tcp_server; TcpServer::Ptr tcp_server;
if (enable_tcp) { if (enable_tcp) {
//创建tcp服务器 //创建tcp服务器
tcp_server = std::make_shared<TcpServer>(udp_server->getPoller()); tcp_server = std::make_shared<TcpServer>(rtp_socket->getPoller());
(*tcp_server)[RtpSession::kStreamID] = stream_id; (*tcp_server)[RtpSession::kStreamID] = stream_id;
tcp_server->start<RtpSession>(udp_server->get_local_port(), local_ip); (*tcp_server)[RtpSession::kIsUDP] = 0;
tcp_server->start<RtpSession>(rtp_socket->get_local_port(), local_ip);
} }
//创建udp服务器
UdpServer::Ptr udp_server;
RtpProcess::Ptr process; RtpProcess::Ptr process;
if (!stream_id.empty()) { if (!stream_id.empty()) {
//指定了流id那么一个端口一个流(不管是否包含多个ssrc的多个流绑定rtp源后会筛选掉ip端口不匹配的流) //指定了流id那么一个端口一个流(不管是否包含多个ssrc的多个流绑定rtp源后会筛选掉ip端口不匹配的流)
//由于是一个端口一个流,单线程处理即可
process = RtpSelector::Instance().getProcess(stream_id, true); process = RtpSelector::Instance().getProcess(stream_id, true);
RtcpHelper::Ptr helper = std::make_shared<RtcpHelper>(std::move(rtcp_server), 90000); RtcpHelper::Ptr helper = std::make_shared<RtcpHelper>(std::move(rtcp_socket), 90000);
helper->startRtcp(); helper->startRtcp();
udp_server->setOnRead([udp_server, process, helper](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) { rtp_socket->setOnRead([rtp_socket, process, helper](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) {
helper->onRecvRtp(buf, addr, addr_len); helper->onRecvRtp(buf, addr, addr_len);
process->inputRtp(true, udp_server, buf->data(), buf->size(), addr); process->inputRtp(true, rtp_socket, buf->data(), buf->size(), addr);
}); });
} else { } else {
//未指定流id一个端口多个流通过ssrc来分流 #if 1
//单端口多线程接收多个流根据ssrc区分流
udp_server = std::make_shared<UdpServer>(rtp_socket->getPoller());
(*udp_server)[RtpSession::kIsUDP] = 1;
udp_server->start<RtpSession>(rtp_socket->get_local_port(), local_ip);
rtp_socket = nullptr;
#else
//单端口单线程接收多个流
auto &ref = RtpSelector::Instance(); auto &ref = RtpSelector::Instance();
udp_server->setOnRead([&ref, udp_server](const Buffer::Ptr &buf, struct sockaddr *addr, int) { rtp_socket->setOnRead([&ref, rtp_socket](const Buffer::Ptr &buf, struct sockaddr *addr, int) {
ref.inputRtp(udp_server, buf->data(), buf->size(), addr); ref.inputRtp(rtp_socket, buf->data(), buf->size(), addr);
}); });
#endif
} }
_on_clearup = [udp_server, process, stream_id]() { _on_clearup = [rtp_socket, process, stream_id]() {
//去除循环引用 if (rtp_socket) {
udp_server->setOnRead(nullptr); //去除循环引用
rtp_socket->setOnRead(nullptr);
}
if (process) { if (process) {
//删除rtp处理器 //删除rtp处理器
RtpSelector::Instance().delProcess(stream_id, process.get()); RtpSelector::Instance().delProcess(stream_id, process.get());
@ -143,6 +157,7 @@ void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable
_tcp_server = tcp_server; _tcp_server = tcp_server;
_udp_server = udp_server; _udp_server = udp_server;
_rtp_socket = rtp_socket;
_rtp_process = process; _rtp_process = process;
} }
@ -152,12 +167,8 @@ void RtpServer::setOnDetach(const function<void()> &cb){
} }
} }
EventPoller::Ptr RtpServer::getPoller() {
return _udp_server->getPoller();
}
uint16_t RtpServer::getPort() { uint16_t RtpServer::getPort() {
return _udp_server ? _udp_server->get_local_port() : 0; return _udp_server ? _udp_server->getPort() : _rtp_socket->get_local_port();
} }
}//namespace mediakit }//namespace mediakit

View File

@ -15,6 +15,7 @@
#include <memory> #include <memory>
#include "Network/Socket.h" #include "Network/Socket.h"
#include "Network/TcpServer.h" #include "Network/TcpServer.h"
#include "Network/UdpServer.h"
#include "RtpSession.h" #include "RtpSession.h"
using namespace std; using namespace std;
@ -47,18 +48,14 @@ public:
*/ */
uint16_t getPort(); uint16_t getPort();
/**
* 线
*/
EventPoller::Ptr getPoller();
/** /**
* RtpProcess onDetach事件回调 * RtpProcess onDetach事件回调
*/ */
void setOnDetach(const function<void()> &cb); void setOnDetach(const function<void()> &cb);
protected: protected:
Socket::Ptr _udp_server; Socket::Ptr _rtp_socket;
UdpServer::Ptr _udp_server;
TcpServer::Ptr _tcp_server; TcpServer::Ptr _tcp_server;
RtpProcess::Ptr _rtp_process; RtpProcess::Ptr _rtp_process;
function<void()> _on_clearup; function<void()> _on_clearup;

View File

@ -16,16 +16,27 @@
namespace mediakit{ namespace mediakit{
const string RtpSession::kStreamID = "stream_id"; const string RtpSession::kStreamID = "stream_id";
const string RtpSession::kIsUDP = "is_udp";
void RtpSession::attachServer(const Server &server) { void RtpSession::attachServer(const Server &server) {
_stream_id = const_cast<Server &>(server)[kStreamID]; _stream_id = const_cast<Server &>(server)[kStreamID];
_is_udp = const_cast<Server &>(server)[kIsUDP];
if (_is_udp) {
//设置udp socket读缓存
SockUtil::setRecvBuf(getSock()->rawFD(), 4 * 1024 * 1024);
_statistic_udp = std::make_shared<ObjectStatistic<UdpSession> >();
} else {
_statistic_tcp = std::make_shared<ObjectStatistic<TcpSession> >();
}
} }
RtpSession::RtpSession(const Socket::Ptr &sock) : TcpSession(sock) { RtpSession::RtpSession(const Socket::Ptr &sock) : Session(sock) {
DebugP(this); DebugP(this);
socklen_t addr_len = sizeof(addr); socklen_t addr_len = sizeof(_addr);
getpeername(sock->rawFD(), &addr, &addr_len); getpeername(sock->rawFD(), &_addr, &addr_len);
} }
RtpSession::~RtpSession() { RtpSession::~RtpSession() {
DebugP(this); DebugP(this);
if(_process){ if(_process){
@ -35,6 +46,10 @@ RtpSession::~RtpSession() {
void RtpSession::onRecv(const Buffer::Ptr &data) { void RtpSession::onRecv(const Buffer::Ptr &data) {
try { try {
if (_is_udp) {
onRtpPacket(data->data(), data->size());
return;
}
RtpSplitter::input(data->data(), data->size()); RtpSplitter::input(data->data(), data->size());
} catch (SockException &ex) { } catch (SockException &ex) {
shutdown(ex); shutdown(ex);
@ -58,19 +73,21 @@ void RtpSession::onManager() {
} }
void RtpSession::onRtpPacket(const char *data, size_t len) { void RtpSession::onRtpPacket(const char *data, size_t len) {
if (_search_rtp) { if (!_is_udp) {
//搜索上下文期间,数据丢弃 if (_search_rtp) {
if (_search_rtp_finished) { //搜索上下文期间,数据丢弃
//下个包开始就是正确的rtp包了 if (_search_rtp_finished) {
_search_rtp_finished = false; //下个包开始就是正确的rtp包了
_search_rtp = false; _search_rtp_finished = false;
_search_rtp = false;
}
return;
}
if (len > 1024 * 10) {
_search_rtp = true;
WarnL << "rtp包长度异常(" << len << ")发送端可能缓存溢出并覆盖开始搜索ssrc以便恢复上下文";
return;
} }
return;
}
if (len > 1024 * 10) {
_search_rtp = true;
WarnL << "rtp包长度异常(" << len << ")发送端可能缓存溢出并覆盖开始搜索ssrc以便恢复上下文";
return;
} }
if (!_process) { if (!_process) {
if (!RtpSelector::getSSRC(data, len, _ssrc)) { if (!RtpSelector::getSSRC(data, len, _ssrc)) {
@ -85,10 +102,14 @@ void RtpSession::onRtpPacket(const char *data, size_t len) {
_process->setListener(dynamic_pointer_cast<RtpSession>(shared_from_this())); _process->setListener(dynamic_pointer_cast<RtpSession>(shared_from_this()));
} }
try { try {
_process->inputRtp(false, getSock(), data, len, &addr); _process->inputRtp(false, getSock(), data, len, &_addr);
} catch (RtpReceiver::BadRtpException &ex) { } catch (RtpReceiver::BadRtpException &ex) {
WarnL << ex.what() << "开始搜索ssrc以便恢复上下文"; if (!_is_udp) {
_search_rtp = true; WarnL << ex.what() << "开始搜索ssrc以便恢复上下文";
_search_rtp = true;
} else {
throw;
}
} catch (...) { } catch (...) {
throw; throw;
} }

View File

@ -20,9 +20,11 @@ using namespace toolkit;
namespace mediakit{ namespace mediakit{
class RtpSession : public TcpSession , public RtpSplitter , public MediaSourceEvent{ class RtpSession : public Session , public RtpSplitter , public MediaSourceEvent{
public: public:
static const string kStreamID; static const string kStreamID;
static const string kIsUDP;
RtpSession(const Socket::Ptr &sock); RtpSession(const Socket::Ptr &sock);
~RtpSession() override; ~RtpSession() override;
void onRecv(const Buffer::Ptr &) override; void onRecv(const Buffer::Ptr &) override;
@ -41,13 +43,16 @@ protected:
const char *onSearchPacketTail(const char *data, size_t len) override; const char *onSearchPacketTail(const char *data, size_t len) override;
private: private:
bool _is_udp = false;
bool _search_rtp = false; bool _search_rtp = false;
bool _search_rtp_finished = false; bool _search_rtp_finished = false;
uint32_t _ssrc = 0; uint32_t _ssrc = 0;
Ticker _ticker; Ticker _ticker;
string _stream_id; string _stream_id;
struct sockaddr addr; struct sockaddr _addr;
RtpProcess::Ptr _process; RtpProcess::Ptr _process;
std::shared_ptr<ObjectStatistic<TcpSession> > _statistic_tcp;
std::shared_ptr<ObjectStatistic<UdpSession> > _statistic_udp;
}; };
}//namespace mediakit }//namespace mediakit