mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-07-05 19:08:09 +08:00
RtpServer新增tcp主动模式支持 (#1938)
This commit is contained in:
@@ -22,8 +22,8 @@ namespace mediakit{
|
||||
RtpServer::RtpServer() {}
|
||||
|
||||
RtpServer::~RtpServer() {
|
||||
if(_on_clearup){
|
||||
_on_clearup();
|
||||
if (_on_cleanup) {
|
||||
_on_cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ private:
|
||||
std::shared_ptr<struct sockaddr_storage> _rtcp_addr;
|
||||
};
|
||||
|
||||
void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable_tcp, const char *local_ip, bool re_use_port, uint32_t ssrc) {
|
||||
void RtpServer::start(uint16_t local_port, const string &stream_id, TcpMode tcp_mode, const char *local_ip, bool re_use_port, uint32_t ssrc) {
|
||||
//创建udp服务器
|
||||
Socket::Ptr rtp_socket = Socket::createSocket(nullptr, true);
|
||||
Socket::Ptr rtcp_socket = Socket::createSocket(nullptr, true);
|
||||
@@ -110,13 +110,19 @@ void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable_
|
||||
SockUtil::setRecvBuf(rtp_socket->rawFD(), 4 * 1024 * 1024);
|
||||
|
||||
TcpServer::Ptr tcp_server;
|
||||
if (enable_tcp) {
|
||||
_tcp_mode = tcp_mode;
|
||||
if (tcp_mode == PASSIVE || tcp_mode == ACTIVE) {
|
||||
//创建tcp服务器
|
||||
tcp_server = std::make_shared<TcpServer>(rtp_socket->getPoller());
|
||||
(*tcp_server)[RtpSession::kStreamID] = stream_id;
|
||||
(*tcp_server)[RtpSession::kIsUDP] = 0;
|
||||
(*tcp_server)[RtpSession::kSSRC] = ssrc;
|
||||
tcp_server->start<RtpSession>(rtp_socket->get_local_port(), local_ip);
|
||||
if (tcp_mode == PASSIVE) {
|
||||
tcp_server->start<RtpSession>(rtp_socket->get_local_port(), local_ip);
|
||||
} else if (stream_id.empty()) {
|
||||
// tcp主动模式时只能一个端口一个流,必须指定流id; 创建TcpServer对象也仅用于传参
|
||||
throw std::runtime_error(StrPrinter << "tcp主动模式时必需指定流id");
|
||||
}
|
||||
}
|
||||
|
||||
//创建udp服务器
|
||||
@@ -125,18 +131,21 @@ void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable_
|
||||
if (!stream_id.empty()) {
|
||||
//指定了流id,那么一个端口一个流(不管是否包含多个ssrc的多个流,绑定rtp源后,会筛选掉ip端口不匹配的流)
|
||||
process = RtpSelector::Instance().getProcess(stream_id, true);
|
||||
RtcpHelper::Ptr helper = std::make_shared<RtcpHelper>(std::move(rtcp_socket), process);
|
||||
helper->startRtcp();
|
||||
rtp_socket->setOnRead([rtp_socket, process, helper, ssrc](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) {
|
||||
RtpHeader *header = (RtpHeader *)buf->data();
|
||||
auto rtp_ssrc = ntohl(header->ssrc);
|
||||
if (ssrc && rtp_ssrc != ssrc) {
|
||||
WarnL << "ssrc不匹配,rtp已丢弃:" << rtp_ssrc << " != " << ssrc;
|
||||
} else {
|
||||
process->inputRtp(true, rtp_socket, buf->data(), buf->size(), addr);
|
||||
helper->onRecvRtp(buf, addr, addr_len);
|
||||
}
|
||||
});
|
||||
if (tcp_mode != ACTIVE) {
|
||||
RtcpHelper::Ptr helper = std::make_shared<RtcpHelper>(std::move(rtcp_socket), process);
|
||||
helper->startRtcp();
|
||||
rtp_socket->setOnRead(
|
||||
[rtp_socket, process, helper, ssrc](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) {
|
||||
RtpHeader *header = (RtpHeader *)buf->data();
|
||||
auto rtp_ssrc = ntohl(header->ssrc);
|
||||
if (ssrc && rtp_ssrc != ssrc) {
|
||||
WarnL << "ssrc不匹配,rtp已丢弃:" << rtp_ssrc << " != " << ssrc;
|
||||
} else {
|
||||
process->inputRtp(true, rtp_socket, buf->data(), buf->size(), addr);
|
||||
helper->onRecvRtp(buf, addr, addr_len);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
#if 1
|
||||
//单端口多线程接收多个流,根据ssrc区分流
|
||||
@@ -153,7 +162,7 @@ void RtpServer::start(uint16_t local_port, const string &stream_id, bool enable_
|
||||
#endif
|
||||
}
|
||||
|
||||
_on_clearup = [rtp_socket, process, stream_id]() {
|
||||
_on_cleanup = [rtp_socket, process, stream_id]() {
|
||||
if (rtp_socket) {
|
||||
//去除循环引用
|
||||
rtp_socket->setOnRead(nullptr);
|
||||
@@ -180,5 +189,42 @@ uint16_t RtpServer::getPort() {
|
||||
return _udp_server ? _udp_server->getPort() : _rtp_socket->get_local_port();
|
||||
}
|
||||
|
||||
void RtpServer::connectToServer(const std::string &url, uint16_t port, const function<void(const SockException &ex)> &cb) {
|
||||
if (_tcp_mode != ACTIVE || !_rtp_socket) {
|
||||
cb(SockException(Err_other, "仅支持tcp主动模式"));
|
||||
return;
|
||||
}
|
||||
weak_ptr<RtpServer> weak_self = shared_from_this();
|
||||
_rtp_socket->connect(url, port, [url, port, cb, weak_self](const SockException &err) {
|
||||
auto strong_self = weak_self.lock();
|
||||
if (!strong_self) {
|
||||
cb(SockException(Err_other, "服务对象已释放"));
|
||||
return;
|
||||
}
|
||||
if (err) {
|
||||
WarnL << "连接到服务器 " << url << ":" << port << " 失败 " << err.what();
|
||||
} else {
|
||||
InfoL << "连接到服务器 " << url << ":" << port << " 成功";
|
||||
strong_self->onConnect();
|
||||
}
|
||||
cb(err);
|
||||
},
|
||||
5.0F, "::", _rtp_socket->get_local_port());
|
||||
}
|
||||
|
||||
void RtpServer::onConnect() {
|
||||
auto rtp_session = std::make_shared<RtpSession>(_rtp_socket);
|
||||
rtp_session->attachServer(*_tcp_server);
|
||||
_rtp_socket->setOnRead([rtp_session](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) {
|
||||
rtp_session->onRecv(buf);
|
||||
});
|
||||
weak_ptr<RtpServer> weak_self = shared_from_this();
|
||||
_rtp_socket->setOnErr([weak_self](const SockException &err) {
|
||||
if (auto strong_self = weak_self.lock()) {
|
||||
strong_self->_rtp_socket->setOnRead(nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}//namespace mediakit
|
||||
#endif//defined(ENABLE_RTPPROXY)
|
||||
|
||||
@@ -23,10 +23,11 @@ namespace mediakit{
|
||||
/**
|
||||
* RTP服务器,支持UDP/TCP
|
||||
*/
|
||||
class RtpServer {
|
||||
class RtpServer : public std::enable_shared_from_this<RtpServer> {
|
||||
public:
|
||||
using Ptr = std::shared_ptr<RtpServer>;
|
||||
using onRecv = std::function<void(const toolkit::Buffer::Ptr &buf)>;
|
||||
enum TcpMode { NONE = 0, PASSIVE, ACTIVE };
|
||||
|
||||
RtpServer();
|
||||
~RtpServer();
|
||||
@@ -35,13 +36,22 @@ public:
|
||||
* 开启服务器,可能抛异常
|
||||
* @param local_port 本地端口,0时为随机端口
|
||||
* @param stream_id 流id,置空则使用ssrc
|
||||
* @param enable_tcp 是否启用tcp服务器
|
||||
* @param tcp_mode tcp服务模式
|
||||
* @param local_ip 绑定的本地网卡ip
|
||||
* @param re_use_port 是否设置socket为re_use属性
|
||||
* @param ssrc 指定的ssrc
|
||||
*/
|
||||
void start(uint16_t local_port, const std::string &stream_id = "", bool enable_tcp = true,
|
||||
void start(uint16_t local_port, const std::string &stream_id = "", TcpMode tcp_mode = PASSIVE,
|
||||
const char *local_ip = "::", bool re_use_port = true, uint32_t ssrc = 0);
|
||||
|
||||
/**
|
||||
* 连接到tcp服务(tcp主动模式)
|
||||
* @param url 服务器地址
|
||||
* @param port 服务器端口
|
||||
* @param cb 连接服务器是否成功的回调
|
||||
*/
|
||||
void connectToServer(const std::string &url, uint16_t port, const std::function<void(const toolkit::SockException &ex)> &cb);
|
||||
|
||||
/**
|
||||
* 获取绑定的本地端口
|
||||
*/
|
||||
@@ -52,12 +62,19 @@ public:
|
||||
*/
|
||||
void setOnDetach(const std::function<void()> &cb);
|
||||
|
||||
private:
|
||||
// tcp主动模式连接服务器成功回调
|
||||
void onConnect();
|
||||
|
||||
protected:
|
||||
toolkit::Socket::Ptr _rtp_socket;
|
||||
toolkit::UdpServer::Ptr _udp_server;
|
||||
toolkit::TcpServer::Ptr _tcp_server;
|
||||
RtpProcess::Ptr _rtp_process;
|
||||
std::function<void()> _on_clearup;
|
||||
std::function<void()> _on_cleanup;
|
||||
|
||||
//用于tcp主动模式
|
||||
TcpMode _tcp_mode = NONE;
|
||||
};
|
||||
|
||||
}//namespace mediakit
|
||||
|
||||
Reference in New Issue
Block a user