mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-23 03:10:04 +08:00
添加配置文件热加载功能
This commit is contained in:
parent
551b9a437b
commit
70bb1a652a
@ -43,7 +43,7 @@ bool loadIniConfig(const char *ini_path){
|
|||||||
}
|
}
|
||||||
try{
|
try{
|
||||||
mINI::Instance().parseFile(ini);
|
mINI::Instance().parseFile(ini);
|
||||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastUpdateConfig);
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastReloadConfig);
|
||||||
return true;
|
return true;
|
||||||
}catch (std::exception &ex) {
|
}catch (std::exception &ex) {
|
||||||
mINI::Instance().dumpFile(ini);
|
mINI::Instance().dumpFile(ini);
|
||||||
@ -60,7 +60,7 @@ const char kBroadcastOnRtspAuth[] = "kBroadcastOnRtspAuth";
|
|||||||
const char kBroadcastMediaPlayed[] = "kBroadcastMediaPlayed";
|
const char kBroadcastMediaPlayed[] = "kBroadcastMediaPlayed";
|
||||||
const char kBroadcastRtmpPublish[] = "kBroadcastRtmpPublish";
|
const char kBroadcastRtmpPublish[] = "kBroadcastRtmpPublish";
|
||||||
const char kBroadcastFlowReport[] = "kBroadcastFlowReport";
|
const char kBroadcastFlowReport[] = "kBroadcastFlowReport";
|
||||||
const char kBroadcastUpdateConfig[] = "kBroadcastUpdateConfig";
|
const char kBroadcastReloadConfig[] = "kBroadcastReloadConfig";
|
||||||
const char kBroadcastShellLogin[] = "kBroadcastShellLogin";
|
const char kBroadcastShellLogin[] = "kBroadcastShellLogin";
|
||||||
|
|
||||||
const char kFlowThreshold[] = "broadcast.flowThreshold";
|
const char kFlowThreshold[] = "broadcast.flowThreshold";
|
||||||
|
@ -28,9 +28,11 @@
|
|||||||
#ifndef COMMON_CONFIG_H
|
#ifndef COMMON_CONFIG_H
|
||||||
#define COMMON_CONFIG_H
|
#define COMMON_CONFIG_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include "Util/mini.h"
|
#include "Util/mini.h"
|
||||||
#include "Util/onceToken.h"
|
#include "Util/onceToken.h"
|
||||||
#include <functional>
|
#include "Util/NoticeCenter.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ZL::Util;
|
using namespace ZL::Util;
|
||||||
|
|
||||||
@ -114,10 +116,33 @@ extern const char kBroadcastFlowReport[];
|
|||||||
extern const char kFlowThreshold[];
|
extern const char kFlowThreshold[];
|
||||||
|
|
||||||
//更新配置文件事件广播,执行loadIniConfig函数加载配置文件成功后会触发该广播
|
//更新配置文件事件广播,执行loadIniConfig函数加载配置文件成功后会触发该广播
|
||||||
extern const char kBroadcastUpdateConfig[];
|
extern const char kBroadcastReloadConfig[];
|
||||||
#define BroadcastUpdateConfigArgs void
|
#define BroadcastReloadConfigArgs void
|
||||||
#define ReloadConfigTag ((void *)(0xFF))
|
#define ReloadConfigTag ((void *)(0xFF))
|
||||||
|
|
||||||
|
#define RELOAD_KEY(arg,key) \
|
||||||
|
do{ \
|
||||||
|
decltype(arg) arg##tmp = mINI::Instance()[key]; \
|
||||||
|
if(arg != arg##tmp ) { \
|
||||||
|
arg = arg##tmp; \
|
||||||
|
InfoL << "reload config:" << key << "=" << arg; \
|
||||||
|
} \
|
||||||
|
}while(0);
|
||||||
|
|
||||||
|
//监听某个配置发送变更
|
||||||
|
#define RELOAD_KEY_REGISTER(arg,key) \
|
||||||
|
do{ \
|
||||||
|
static onceToken s_token([](){ \
|
||||||
|
NoticeCenter::Instance().addListener(ReloadConfigTag,Config::Broadcast::kBroadcastReloadConfig,[](BroadcastReloadConfigArgs){ \
|
||||||
|
RELOAD_KEY(arg,key); \
|
||||||
|
}); \
|
||||||
|
}); \
|
||||||
|
}while(0);
|
||||||
|
|
||||||
|
#define GET_CONFIG_AND_REGISTER(type,arg,key) \
|
||||||
|
static type arg = mINI::Instance()[key]; \
|
||||||
|
RELOAD_KEY_REGISTER(arg,key);
|
||||||
|
|
||||||
} //namespace Broadcast
|
} //namespace Broadcast
|
||||||
|
|
||||||
////////////HTTP配置///////////
|
////////////HTTP配置///////////
|
||||||
|
@ -107,7 +107,7 @@ void DevChannel::inputH264(char* pcData, int iDataLen, uint32_t uiStamp) {
|
|||||||
auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
||||||
onGetRTP(pkt,bKeyPos);
|
onGetRTP(pkt,bKeyPos);
|
||||||
};
|
};
|
||||||
static uint32_t videoMtu = mINI::Instance()[Config::Rtp::kVideoMtuSize].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,videoMtu,Config::Rtp::kVideoMtuSize);
|
||||||
m_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ui32Ssrc,videoMtu));
|
m_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ui32Ssrc,videoMtu));
|
||||||
}
|
}
|
||||||
if (!m_bSdp_gotH264 && m_video) {
|
if (!m_bSdp_gotH264 && m_video) {
|
||||||
@ -130,7 +130,7 @@ void DevChannel::inputAAC(char *pcDataWithoutAdts,int iDataLen, uint32_t uiStamp
|
|||||||
auto lam = [this](const RtpPacket::Ptr &pkt, bool keyPos) {
|
auto lam = [this](const RtpPacket::Ptr &pkt, bool keyPos) {
|
||||||
onGetRTP(pkt,keyPos);
|
onGetRTP(pkt,keyPos);
|
||||||
};
|
};
|
||||||
static uint32_t audioMtu = mINI::Instance()[Config::Rtp::kAudioMtuSize].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,audioMtu,Config::Rtp::kAudioMtuSize);
|
||||||
m_pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc, audioMtu,m_audio->iSampleRate));
|
m_pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc, audioMtu,m_audio->iSampleRate));
|
||||||
}
|
}
|
||||||
if (!m_bSdp_gotAAC && m_audio && pcAdtsHeader) {
|
if (!m_bSdp_gotAAC && m_audio && pcAdtsHeader) {
|
||||||
|
@ -102,7 +102,8 @@ get_mime_type(const char* name) {
|
|||||||
|
|
||||||
HttpSession::HttpSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock) :
|
HttpSession::HttpSession(const std::shared_ptr<ThreadPool> &pTh, const Socket::Ptr &pSock) :
|
||||||
TcpLimitedSession(pTh, pSock) {
|
TcpLimitedSession(pTh, pSock) {
|
||||||
static string rootPath = mINI::Instance()[Config::Http::kRootPath];
|
GET_CONFIG_AND_REGISTER(string,rootPath,Config::Http::kRootPath);
|
||||||
|
|
||||||
m_strPath = rootPath;
|
m_strPath = rootPath;
|
||||||
static onceToken token([]() {
|
static onceToken token([]() {
|
||||||
g_mapCmdIndex.emplace("GET",&HttpSession::Handle_Req_GET);
|
g_mapCmdIndex.emplace("GET",&HttpSession::Handle_Req_GET);
|
||||||
@ -118,7 +119,8 @@ void HttpSession::onRecv(const Socket::Buffer::Ptr &pBuf) {
|
|||||||
onRecv(pBuf->data(),pBuf->size());
|
onRecv(pBuf->data(),pBuf->size());
|
||||||
}
|
}
|
||||||
void HttpSession::onRecv(const char *data,int size){
|
void HttpSession::onRecv(const char *data,int size){
|
||||||
static uint32_t reqSize = mINI::Instance()[Config::Http::kMaxReqSize].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,reqSize,Config::Http::kMaxReqSize);
|
||||||
|
|
||||||
m_ticker.resetTime();
|
m_ticker.resetTime();
|
||||||
if (m_strRcvBuf.size() + size >= reqSize) {
|
if (m_strRcvBuf.size() + size >= reqSize) {
|
||||||
WarnL << "接收缓冲区溢出:" << m_strRcvBuf.size() + size << "," << reqSize;
|
WarnL << "接收缓冲区溢出:" << m_strRcvBuf.size() + size << "," << reqSize;
|
||||||
@ -163,7 +165,8 @@ inline HttpSession::HttpCode HttpSession::parserHttpReq(const string &str) {
|
|||||||
}
|
}
|
||||||
void HttpSession::onError(const SockException& err) {
|
void HttpSession::onError(const SockException& err) {
|
||||||
//WarnL << err.what();
|
//WarnL << err.what();
|
||||||
static uint64_t iFlowThreshold = mINI::Instance()[Broadcast::kFlowThreshold];
|
GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);
|
||||||
|
|
||||||
if(m_previousTagSize > iFlowThreshold * 1024){
|
if(m_previousTagSize > iFlowThreshold * 1024){
|
||||||
uint64_t totalBytes = m_previousTagSize;
|
uint64_t totalBytes = m_previousTagSize;
|
||||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,m_mediaInfo,totalBytes);
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,m_mediaInfo,totalBytes);
|
||||||
@ -171,7 +174,8 @@ void HttpSession::onError(const SockException& err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HttpSession::onManager() {
|
void HttpSession::onManager() {
|
||||||
static uint32_t keepAliveSec = mINI::Instance()[Config::Http::kKeepAliveSecond].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,keepAliveSec,Config::Http::kKeepAliveSecond);
|
||||||
|
|
||||||
if(m_ticker.elapsedTime() > keepAliveSec * 1000){
|
if(m_ticker.elapsedTime() > keepAliveSec * 1000){
|
||||||
//1分钟超时
|
//1分钟超时
|
||||||
WarnL<<"HttpSession timeouted!";
|
WarnL<<"HttpSession timeouted!";
|
||||||
@ -318,7 +322,8 @@ inline HttpSession::HttpCode HttpSession::Handle_Req_GET() {
|
|||||||
|
|
||||||
string strFile = m_strPath + "/" + m_mediaInfo.m_vhost + m_parser.Url();
|
string strFile = m_strPath + "/" + m_mediaInfo.m_vhost + m_parser.Url();
|
||||||
/////////////HTTP连接是否需要被关闭////////////////
|
/////////////HTTP连接是否需要被关闭////////////////
|
||||||
static uint32_t reqCnt = mINI::Instance()[Config::Http::kMaxReqCount].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Config::Http::kMaxReqCount);
|
||||||
|
|
||||||
bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) && ( ++m_iReqCnt < reqCnt);
|
bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) && ( ++m_iReqCnt < reqCnt);
|
||||||
HttpCode eHttpCode = bClose ? Http_failed : Http_success;
|
HttpCode eHttpCode = bClose ? Http_failed : Http_success;
|
||||||
//访问的是文件夹
|
//访问的是文件夹
|
||||||
@ -384,7 +389,8 @@ inline HttpSession::HttpCode HttpSession::Handle_Req_GET() {
|
|||||||
std::shared_ptr<FILE> pFilePtr(pFile, [](FILE *pFp) {
|
std::shared_ptr<FILE> pFilePtr(pFile, [](FILE *pFp) {
|
||||||
fclose(pFp);
|
fclose(pFp);
|
||||||
});
|
});
|
||||||
static uint32_t sendBufSize = mINI::Instance()[Config::Http::kSendBufSize].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,sendBufSize,Config::Http::kSendBufSize);
|
||||||
|
|
||||||
//不允许主动丢包
|
//不允许主动丢包
|
||||||
sock->setShouldDropPacket(false);
|
sock->setShouldDropPacket(false);
|
||||||
//缓存大小为两个包,太大可能导致发送时间太长从而超时
|
//缓存大小为两个包,太大可能导致发送时间太长从而超时
|
||||||
@ -545,9 +551,9 @@ inline void HttpSession::sendResponse(const char* pcStatus, const KeyValue& head
|
|||||||
}
|
}
|
||||||
inline HttpSession::KeyValue HttpSession::makeHttpHeader(bool bClose, int64_t iContentSize,const char* pcContentType) {
|
inline HttpSession::KeyValue HttpSession::makeHttpHeader(bool bClose, int64_t iContentSize,const char* pcContentType) {
|
||||||
KeyValue headerOut;
|
KeyValue headerOut;
|
||||||
static string charSet = mINI::Instance()[Config::Http::kCharSet];
|
GET_CONFIG_AND_REGISTER(string,charSet,Config::Http::kCharSet);
|
||||||
static uint32_t keepAliveSec = mINI::Instance()[Config::Http::kKeepAliveSecond].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,keepAliveSec,Config::Http::kKeepAliveSecond);
|
||||||
static uint32_t reqCnt = mINI::Instance()[Config::Http::kMaxReqCount].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Config::Http::kMaxReqCount);
|
||||||
|
|
||||||
headerOut.emplace("Date", dateStr());
|
headerOut.emplace("Date", dateStr());
|
||||||
headerOut.emplace("Server", SERVER_NAME);
|
headerOut.emplace("Server", SERVER_NAME);
|
||||||
@ -568,7 +574,8 @@ inline HttpSession::KeyValue HttpSession::makeHttpHeader(bool bClose, int64_t iC
|
|||||||
string HttpSession::urlDecode(const string &str){
|
string HttpSession::urlDecode(const string &str){
|
||||||
auto ret = strCoding::UrlUTF8Decode(str);
|
auto ret = strCoding::UrlUTF8Decode(str);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static bool isGb2312 = !strcasecmp(mINI::Instance()[Config::Http::kCharSet].data(), "gb2312");
|
GET_CONFIG_AND_REGISTER(string,charSet,Config::Http::kCharSet);
|
||||||
|
bool isGb2312 = !strcasecmp(charSet.data(), "gb2312");
|
||||||
if (isGb2312) {
|
if (isGb2312) {
|
||||||
ret = strCoding::UTF8ToGB2312(ret);
|
ret = strCoding::UTF8ToGB2312(ret);
|
||||||
}
|
}
|
||||||
@ -585,7 +592,8 @@ inline void HttpSession::urlDecode(Parser &parser){
|
|||||||
|
|
||||||
inline bool HttpSession::emitHttpEvent(bool doInvoke){
|
inline bool HttpSession::emitHttpEvent(bool doInvoke){
|
||||||
///////////////////是否断开本链接///////////////////////
|
///////////////////是否断开本链接///////////////////////
|
||||||
static uint32_t reqCnt = mINI::Instance()[Config::Http::kMaxReqCount].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,reqCnt,Config::Http::kMaxReqCount);
|
||||||
|
|
||||||
bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) && ( ++m_iReqCnt < reqCnt);
|
bool bClose = (strcasecmp(m_parser["Connection"].data(),"close") == 0) && ( ++m_iReqCnt < reqCnt);
|
||||||
auto Origin = m_parser["Origin"];
|
auto Origin = m_parser["Origin"];
|
||||||
/////////////////////异步回复Invoker///////////////////////////////
|
/////////////////////异步回复Invoker///////////////////////////////
|
||||||
@ -643,7 +651,8 @@ void HttpSession::responseDelay(const string &Origin,bool bClose,
|
|||||||
sendResponse(codeOut.data(), headerOut, contentOut);
|
sendResponse(codeOut.data(), headerOut, contentOut);
|
||||||
}
|
}
|
||||||
inline void HttpSession::sendNotFound(bool bClose) {
|
inline void HttpSession::sendNotFound(bool bClose) {
|
||||||
static string notFound = mINI::Instance()[Config::Http::kNotFound];
|
GET_CONFIG_AND_REGISTER(string,notFound,Config::Http::kNotFound);
|
||||||
|
|
||||||
sendResponse("404 Not Found", makeHttpHeader(bClose, notFound.size()), notFound);
|
sendResponse("404 Not Found", makeHttpHeader(bClose, notFound.size()), notFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,8 @@ namespace MediaFile {
|
|||||||
|
|
||||||
#ifdef ENABLE_MP4V2
|
#ifdef ENABLE_MP4V2
|
||||||
MediaReader::MediaReader(const string &strVhost,const string &strApp, const string &strId) {
|
MediaReader::MediaReader(const string &strVhost,const string &strApp, const string &strId) {
|
||||||
static string recordPath = mINI::Instance()[Config::Record::kFilePath];
|
GET_CONFIG_AND_REGISTER(string,recordPath,Config::Record::kFilePath);
|
||||||
|
|
||||||
auto strFileName = recordPath + "/" + strVhost + "/" + strApp + "/" + strId;
|
auto strFileName = recordPath + "/" + strVhost + "/" + strApp + "/" + strId;
|
||||||
|
|
||||||
m_hMP4File = MP4Read(strFileName.data());
|
m_hMP4File = MP4Read(strFileName.data());
|
||||||
@ -168,7 +169,8 @@ MediaReader::~MediaReader() {
|
|||||||
|
|
||||||
void MediaReader::startReadMP4() {
|
void MediaReader::startReadMP4() {
|
||||||
auto strongSelf = shared_from_this();
|
auto strongSelf = shared_from_this();
|
||||||
static uint32_t sampleMS = mINI::Instance()[Config::Record::kSampleMS].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,sampleMS,Config::Record::kSampleMS);
|
||||||
|
|
||||||
AsyncTaskThread::Instance().DoTaskDelay(reinterpret_cast<uint64_t>(this), sampleMS, [strongSelf](){
|
AsyncTaskThread::Instance().DoTaskDelay(reinterpret_cast<uint64_t>(this), sampleMS, [strongSelf](){
|
||||||
return strongSelf->readSample();
|
return strongSelf->readSample();
|
||||||
});
|
});
|
||||||
@ -321,7 +323,8 @@ void MediaReader::seek(int iSeekTime,bool bReStart){
|
|||||||
|
|
||||||
MediaSource::Ptr MediaReader::onMakeMediaSource(const string &strSchema,const string &strVhost,const string &strApp, const string &strId){
|
MediaSource::Ptr MediaReader::onMakeMediaSource(const string &strSchema,const string &strVhost,const string &strApp, const string &strId){
|
||||||
#ifdef ENABLE_MP4V2
|
#ifdef ENABLE_MP4V2
|
||||||
static string appName = mINI::Instance()[Config::Record::kAppName];
|
GET_CONFIG_AND_REGISTER(string,appName,Config::Record::kAppName);
|
||||||
|
|
||||||
if (strApp != appName) {
|
if (strApp != appName) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -44,12 +44,12 @@ MediaRecorder::MediaRecorder(const string &strVhost_tmp,
|
|||||||
bool enableHls,
|
bool enableHls,
|
||||||
bool enableMp4) {
|
bool enableMp4) {
|
||||||
|
|
||||||
static string hlsPrefix = mINI::Instance()[Config::Hls::kHttpPrefix];
|
GET_CONFIG_AND_REGISTER(string,hlsPrefix,Config::Hls::kHttpPrefix);
|
||||||
static string hlsPrefixDefaultVhost = mINI::Instance()[Config::Hls::kHttpPrefixDefaultVhost];
|
GET_CONFIG_AND_REGISTER(string,hlsPrefixDefaultVhost,Config::Hls::kHttpPrefixDefaultVhost);
|
||||||
static string hlsPath = mINI::Instance()[Config::Hls::kFilePath];
|
GET_CONFIG_AND_REGISTER(string,hlsPath,Config::Hls::kFilePath);
|
||||||
static uint32_t hlsBufSize = mINI::Instance()[Config::Hls::kFileBufSize].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,hlsBufSize,Config::Hls::kFileBufSize);
|
||||||
static uint32_t hlsDuration = mINI::Instance()[Config::Hls::kSegmentDuration].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,hlsDuration,Config::Hls::kSegmentDuration);
|
||||||
static uint32_t hlsNum = mINI::Instance()[Config::Hls::kSegmentNum].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,hlsNum,Config::Hls::kSegmentNum);
|
||||||
|
|
||||||
string strVhost = strVhost_tmp;
|
string strVhost = strVhost_tmp;
|
||||||
if(trim(strVhost).empty()){
|
if(trim(strVhost).empty()){
|
||||||
@ -80,8 +80,9 @@ MediaRecorder::MediaRecorder(const string &strVhost_tmp,
|
|||||||
hlsBufSize, hlsDuration, hlsNum));
|
hlsBufSize, hlsDuration, hlsNum));
|
||||||
}
|
}
|
||||||
#ifdef ENABLE_MP4V2
|
#ifdef ENABLE_MP4V2
|
||||||
static string recordPath = mINI::Instance()[Config::Record::kFilePath];
|
GET_CONFIG_AND_REGISTER(string,recordPath,Config::Record::kFilePath);
|
||||||
static string recordAppName = mINI::Instance()[Config::Record::kAppName];
|
GET_CONFIG_AND_REGISTER(string,recordAppName,Config::Record::kAppName);
|
||||||
|
|
||||||
if(enableMp4){
|
if(enableMp4){
|
||||||
m_mp4Maker.reset(new Mp4Maker(recordPath + "/" + strVhost + "/" + recordAppName + "/" + strApp + "/" + strId + "/",
|
m_mp4Maker.reset(new Mp4Maker(recordPath + "/" + strVhost + "/" + recordAppName + "/" + strApp + "/" + strId + "/",
|
||||||
strVhost,strApp,strId,pPlayer));
|
strVhost,strApp,strId,pPlayer));
|
||||||
|
@ -119,8 +119,9 @@ void Mp4Maker::inputAAC(void *pData, uint32_t ui32Length, uint32_t ui32TimeStamp
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::_inputH264(void* pData, uint32_t ui32Length, uint32_t ui32Duration, int iType) {
|
void Mp4Maker::_inputH264(void* pData, uint32_t ui32Length, uint32_t ui32Duration, int iType) {
|
||||||
static uint32_t recordMS = 1000 * mINI::Instance()[Config::Record::kFileSecond].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,recordSec,Config::Record::kFileSecond);
|
||||||
if(iType == 5 && (m_hMp4 == MP4_INVALID_FILE_HANDLE || m_ticker.elapsedTime() > recordMS)){
|
|
||||||
|
if(iType == 5 && (m_hMp4 == MP4_INVALID_FILE_HANDLE || m_ticker.elapsedTime() > recordSec * 1000)){
|
||||||
//在I帧率处新建MP4文件
|
//在I帧率处新建MP4文件
|
||||||
//如果文件未创建或者文件超过10分钟则创建新文件
|
//如果文件未创建或者文件超过10分钟则创建新文件
|
||||||
createFile();
|
createFile();
|
||||||
@ -131,8 +132,9 @@ void Mp4Maker::_inputH264(void* pData, uint32_t ui32Length, uint32_t ui32Duratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Maker::_inputAAC(void* pData, uint32_t ui32Length, uint32_t ui32Duration) {
|
void Mp4Maker::_inputAAC(void* pData, uint32_t ui32Length, uint32_t ui32Duration) {
|
||||||
static uint32_t recordMS = 1000 * mINI::Instance()[Config::Record::kFileSecond].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,recordSec,Config::Record::kFileSecond);
|
||||||
if (!m_pPlayer->containVideo() && (m_hMp4 == MP4_INVALID_FILE_HANDLE || m_ticker.elapsedTime() > recordMS)) {
|
|
||||||
|
if (!m_pPlayer->containVideo() && (m_hMp4 == MP4_INVALID_FILE_HANDLE || m_ticker.elapsedTime() > recordSec * 1000)) {
|
||||||
//在I帧率处新建MP4文件
|
//在I帧率处新建MP4文件
|
||||||
//如果文件未创建或者文件超过10分钟则创建新文件
|
//如果文件未创建或者文件超过10分钟则创建新文件
|
||||||
createFile();
|
createFile();
|
||||||
@ -158,7 +160,9 @@ void Mp4Maker::createFile() {
|
|||||||
m_info.ui64StartedTime = ::time(NULL);
|
m_info.ui64StartedTime = ::time(NULL);
|
||||||
m_info.strFileName = strTime + ".mp4";
|
m_info.strFileName = strTime + ".mp4";
|
||||||
m_info.strFilePath = strFile;
|
m_info.strFilePath = strFile;
|
||||||
static string appName = mINI::Instance()[Config::Record::kAppName];
|
|
||||||
|
GET_CONFIG_AND_REGISTER(string,appName,Config::Record::kAppName);
|
||||||
|
|
||||||
m_info.strUrl = m_info.strVhost + "/"
|
m_info.strUrl = m_info.strVhost + "/"
|
||||||
+ appName + "/"
|
+ appName + "/"
|
||||||
+ m_info.strAppName + "/"
|
+ m_info.strAppName + "/"
|
||||||
|
@ -36,7 +36,8 @@ namespace ZL {
|
|||||||
namespace Rtsp {
|
namespace Rtsp {
|
||||||
|
|
||||||
void RtpMaker_AAC::makeRtp(const char *pcData, int iLen, uint32_t uiStamp) {
|
void RtpMaker_AAC::makeRtp(const char *pcData, int iLen, uint32_t uiStamp) {
|
||||||
static uint32_t cycleMS = mINI::Instance()[Config::Rtp::kCycleMS].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,cycleMS,Config::Rtp::kCycleMS);
|
||||||
|
|
||||||
uiStamp %= cycleMS;
|
uiStamp %= cycleMS;
|
||||||
char *ptr = (char *) pcData;
|
char *ptr = (char *) pcData;
|
||||||
int iSize = iLen;
|
int iSize = iLen;
|
||||||
|
@ -36,7 +36,8 @@ namespace ZL {
|
|||||||
namespace Rtsp {
|
namespace Rtsp {
|
||||||
|
|
||||||
void RtpMaker_H264::makeRtp(const char* pcData, int iLen, uint32_t uiStamp) {
|
void RtpMaker_H264::makeRtp(const char* pcData, int iLen, uint32_t uiStamp) {
|
||||||
static uint32_t cycleMS = mINI::Instance()[Config::Rtp::kCycleMS].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,cycleMS,Config::Rtp::kCycleMS);
|
||||||
|
|
||||||
uiStamp %= cycleMS;
|
uiStamp %= cycleMS;
|
||||||
int iSize = m_iMtuSize - 2;
|
int iSize = m_iMtuSize - 2;
|
||||||
if (iLen > iSize) { //超过MTU
|
if (iLen > iSize) { //超过MTU
|
||||||
|
@ -54,7 +54,8 @@ void RtmpSession::onError(const SockException& err) {
|
|||||||
DebugL << err.what();
|
DebugL << err.what();
|
||||||
|
|
||||||
//流量统计事件广播
|
//流量统计事件广播
|
||||||
static uint64_t iFlowThreshold = mINI::Instance()[Broadcast::kFlowThreshold];
|
GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);
|
||||||
|
|
||||||
if(m_ui64TotalBytes > iFlowThreshold * 1024){
|
if(m_ui64TotalBytes > iFlowThreshold * 1024){
|
||||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,m_mediaInfo,m_ui64TotalBytes);
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,m_mediaInfo,m_ui64TotalBytes);
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,8 @@ void RtmpToRtspMediaSource::makeSDP() {
|
|||||||
auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
||||||
m_pRtspSrc->onGetRTP(pkt,bKeyPos);
|
m_pRtspSrc->onGetRTP(pkt,bKeyPos);
|
||||||
};
|
};
|
||||||
static uint32_t videoMtu = mINI::Instance()[Config::Rtp::kVideoMtuSize].as<uint32_t>();
|
|
||||||
|
GET_CONFIG_AND_REGISTER(uint32_t,videoMtu,Config::Rtp::kVideoMtuSize);
|
||||||
m_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ssrc0,videoMtu));
|
m_pRtpMaker_h264.reset(new RtpMaker_H264(lam, ssrc0,videoMtu));
|
||||||
|
|
||||||
char strTemp[100];
|
char strTemp[100];
|
||||||
@ -140,7 +141,7 @@ void RtmpToRtspMediaSource::makeSDP() {
|
|||||||
auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
auto lam = [this](const RtpPacket::Ptr &pkt, bool bKeyPos) {
|
||||||
m_pRtspSrc->onGetRTP(pkt,bKeyPos);
|
m_pRtspSrc->onGetRTP(pkt,bKeyPos);
|
||||||
};
|
};
|
||||||
static uint32_t audioMtu = mINI::Instance()[Config::Rtp::kAudioMtuSize].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,audioMtu,Config::Rtp::kAudioMtuSize);
|
||||||
m_pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc1, audioMtu,m_pParser->getAudioSampleRate()));
|
m_pRtpMaker_aac.reset(new RtpMaker_AAC(lam, ssrc1, audioMtu,m_pParser->getAudioSampleRate()));
|
||||||
|
|
||||||
char configStr[32];
|
char configStr[32];
|
||||||
|
@ -47,8 +47,10 @@ static uint32_t addressToInt(const string &ip){
|
|||||||
|
|
||||||
std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t iTry) {
|
std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t iTry) {
|
||||||
lock_guard<recursive_mutex> lck(m_mtx);
|
lock_guard<recursive_mutex> lck(m_mtx);
|
||||||
static uint32_t addrMin = addressToInt(mINI::Instance()[Config::MultiCast::kAddrMin]);
|
GET_CONFIG_AND_REGISTER(string,addrMinStr,Config::MultiCast::kAddrMin);
|
||||||
static uint32_t addrMax = addressToInt(mINI::Instance()[Config::MultiCast::kAddrMax]);
|
GET_CONFIG_AND_REGISTER(string,addrMaxStr,Config::MultiCast::kAddrMax);
|
||||||
|
uint32_t addrMin = addressToInt(addrMinStr);
|
||||||
|
uint32_t addrMax = addressToInt(addrMaxStr);
|
||||||
|
|
||||||
if(m_iAddr > addrMax || m_iAddr == 0){
|
if(m_iAddr > addrMax || m_iAddr == 0){
|
||||||
m_iAddr = addrMin;
|
m_iAddr = addrMin;
|
||||||
@ -106,7 +108,8 @@ RtpBroadCaster::RtpBroadCaster(const string &strLocalIp,const string &strVhost,c
|
|||||||
throw std::runtime_error(strErr);
|
throw std::runtime_error(strErr);
|
||||||
}
|
}
|
||||||
auto fd = m_apUdpSock[i]->rawFD();
|
auto fd = m_apUdpSock[i]->rawFD();
|
||||||
static uint32_t udpTTL = mINI::Instance()[Config::MultiCast::kUdpTTL].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,udpTTL,Config::MultiCast::kUdpTTL);
|
||||||
|
|
||||||
SockUtil::setMultiTTL(fd, udpTTL);
|
SockUtil::setMultiTTL(fd, udpTTL);
|
||||||
SockUtil::setMultiLOOP(fd, false);
|
SockUtil::setMultiLOOP(fd, false);
|
||||||
SockUtil::setMultiIF(fd, strLocalIp.data());
|
SockUtil::setMultiIF(fd, strLocalIp.data());
|
||||||
|
@ -127,7 +127,7 @@ void RtspPlayer::play(const char* strUrl, const char *strUser, const char *strPw
|
|||||||
}
|
}
|
||||||
m_eType = eType;
|
m_eType = eType;
|
||||||
if (m_eType == RTP_TCP && !m_pucRtpBuf) {
|
if (m_eType == RTP_TCP && !m_pucRtpBuf) {
|
||||||
static uint32_t rtpSize = mINI::Instance()[Config::Rtp::kUdpBufSize].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,rtpSize,Config::Rtp::kUdpBufSize);
|
||||||
m_pucRtpBuf = new uint8_t[rtpSize];
|
m_pucRtpBuf = new uint8_t[rtpSize];
|
||||||
}
|
}
|
||||||
auto ip = FindField(strUrl, "://", "/");
|
auto ip = FindField(strUrl, "://", "/");
|
||||||
@ -203,7 +203,7 @@ void RtspPlayer::onRecv(const Socket::Buffer::Ptr& pBuf) {
|
|||||||
if (m_eType == RTP_TCP && m_pucRtpBuf) {
|
if (m_eType == RTP_TCP && m_pucRtpBuf) {
|
||||||
//RTP data
|
//RTP data
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
static uint32_t rtpSize = mINI::Instance()[Config::Rtp::kUdpBufSize].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,rtpSize,Config::Rtp::kUdpBufSize);
|
||||||
int added = rtpSize - m_uiRtpBufLen;
|
int added = rtpSize - m_uiRtpBufLen;
|
||||||
added = (added > size ? size : added);
|
added = (added > size ? size : added);
|
||||||
memcpy(m_pucRtpBuf + m_uiRtpBufLen, buf, added);
|
memcpy(m_pucRtpBuf + m_uiRtpBufLen, buf, added);
|
||||||
@ -607,8 +607,8 @@ inline bool RtspPlayer::HandleOneRtp(int iTrackidx, unsigned char *pucData, unsi
|
|||||||
//开始排序缓存
|
//开始排序缓存
|
||||||
if (m_abSortStarted[iTrackidx]) {
|
if (m_abSortStarted[iTrackidx]) {
|
||||||
m_amapRtpSort[iTrackidx].emplace(rtppt.sequence, pt_ptr);
|
m_amapRtpSort[iTrackidx].emplace(rtppt.sequence, pt_ptr);
|
||||||
static uint32_t clearCount = mINI::Instance()[Config::Rtp::kClearCount].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,clearCount,Config::Rtp::kClearCount);
|
||||||
static uint32_t maxRtpCount = mINI::Instance()[Config::Rtp::kMaxRtpCount].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,maxRtpCount,Config::Rtp::kMaxRtpCount);
|
||||||
if (m_aui64SeqOkCnt[iTrackidx] >= clearCount) {
|
if (m_aui64SeqOkCnt[iTrackidx] >= clearCount) {
|
||||||
//网络环境改善,需要清空排序缓存
|
//网络环境改善,需要清空排序缓存
|
||||||
m_aui64SeqOkCnt[iTrackidx] = 0;
|
m_aui64SeqOkCnt[iTrackidx] = 0;
|
||||||
|
@ -127,7 +127,7 @@ void RtspSession::onError(const SockException& err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//流量统计事件广播
|
//流量统计事件广播
|
||||||
static uint64_t iFlowThreshold = mINI::Instance()[Broadcast::kFlowThreshold];
|
GET_CONFIG_AND_REGISTER(uint32_t,iFlowThreshold,Broadcast::kFlowThreshold);
|
||||||
if(m_ui64TotalBytes > iFlowThreshold * 1024){
|
if(m_ui64TotalBytes > iFlowThreshold * 1024){
|
||||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,m_mediaInfo,m_ui64TotalBytes);
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,m_mediaInfo,m_ui64TotalBytes);
|
||||||
}
|
}
|
||||||
@ -278,7 +278,7 @@ void RtspSession::onAuthFailed(const weak_ptr<RtspSession> &weakSelf,const strin
|
|||||||
|
|
||||||
int n;
|
int n;
|
||||||
char response[2 * 1024];
|
char response[2 * 1024];
|
||||||
static bool authBasic = mINI::Instance()[Config::Rtsp::kAuthBasic];
|
GET_CONFIG_AND_REGISTER(bool,authBasic,Config::Rtsp::kAuthBasic);
|
||||||
if (!authBasic) {
|
if (!authBasic) {
|
||||||
//我们需要客户端优先以md5方式认证
|
//我们需要客户端优先以md5方式认证
|
||||||
strongSelf->m_strNonce = makeRandStr(32);
|
strongSelf->m_strNonce = makeRandStr(32);
|
||||||
@ -617,7 +617,7 @@ bool RtspSession::handleReq_Setup() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
startListenPeerUdpData();
|
startListenPeerUdpData();
|
||||||
static uint32_t udpTTL = mINI::Instance()[MultiCast::kUdpTTL].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,udpTTL,MultiCast::kUdpTTL);
|
||||||
int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
int n = sprintf(m_pcBuf, "RTSP/1.0 200 OK\r\n"
|
||||||
"CSeq: %d\r\n"
|
"CSeq: %d\r\n"
|
||||||
"Server: %s-%0.2f(build in %s)\r\n"
|
"Server: %s-%0.2f(build in %s)\r\n"
|
||||||
|
@ -47,7 +47,7 @@ ShellSession::~ShellSession() {
|
|||||||
|
|
||||||
void ShellSession::onRecv(const Socket::Buffer::Ptr&buf) {
|
void ShellSession::onRecv(const Socket::Buffer::Ptr&buf) {
|
||||||
//DebugL << hexdump(buf->data(), buf->size());
|
//DebugL << hexdump(buf->data(), buf->size());
|
||||||
static uint32_t maxReqSize = mINI::Instance()[Config::Shell::kMaxReqSize].as<uint32_t>();
|
GET_CONFIG_AND_REGISTER(uint32_t,maxReqSize,Config::Shell::kMaxReqSize);
|
||||||
if (m_strRecvBuf.size() + buf->size() >= maxReqSize) {
|
if (m_strRecvBuf.size() + buf->size() >= maxReqSize) {
|
||||||
WarnL << "接收缓冲区溢出!";
|
WarnL << "接收缓冲区溢出!";
|
||||||
shutdown();
|
shutdown();
|
||||||
|
@ -145,6 +145,8 @@ int main(int argc,char *argv[]){
|
|||||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
//加载配置文件,如果配置文件不存在就创建一个
|
//加载配置文件,如果配置文件不存在就创建一个
|
||||||
Config::loadIniConfig();
|
Config::loadIniConfig();
|
||||||
|
|
||||||
|
{
|
||||||
//这里是拉流地址,支持rtmp/rtsp协议,负载必须是H264+AAC
|
//这里是拉流地址,支持rtmp/rtsp协议,负载必须是H264+AAC
|
||||||
//如果是其他不识别的音视频将会被忽略(譬如说h264+adpcm转发后会去除音频)
|
//如果是其他不识别的音视频将会被忽略(譬如说h264+adpcm转发后会去除音频)
|
||||||
auto urlList = {"rtmp://live.hkstv.hk.lxdns.com/live/hks",
|
auto urlList = {"rtmp://live.hkstv.hk.lxdns.com/live/hks",
|
||||||
@ -185,36 +187,63 @@ int main(int argc,char *argv[]){
|
|||||||
}
|
}
|
||||||
#endif //ENABLE_OPENSSL
|
#endif //ENABLE_OPENSSL
|
||||||
|
|
||||||
|
uint16_t shellPort = mINI::Instance()[Config::Shell::kPort];
|
||||||
|
uint16_t rtspPort = mINI::Instance()[Config::Rtsp::kPort];
|
||||||
|
uint16_t rtmpPort = mINI::Instance()[Config::Rtmp::kPort];
|
||||||
|
uint16_t httpPort = mINI::Instance()[Config::Http::kPort];
|
||||||
|
uint16_t httpsPort = mINI::Instance()[Config::Http::kSSLPort];
|
||||||
|
|
||||||
//简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象
|
//简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象
|
||||||
//测试方法:telnet 127.0.0.1 9000
|
//测试方法:telnet 127.0.0.1 9000
|
||||||
TcpServer<ShellSession>::Ptr shellSrv(new TcpServer<ShellSession>());
|
TcpServer<ShellSession>::Ptr shellSrv(new TcpServer<ShellSession>());
|
||||||
shellSrv->start(mINI::Instance()[Config::Shell::kPort]);
|
|
||||||
//开启rtsp/rtmp/http服务器
|
|
||||||
TcpServer<RtspSession>::Ptr rtspSrv(new TcpServer<RtspSession>());
|
TcpServer<RtspSession>::Ptr rtspSrv(new TcpServer<RtspSession>());
|
||||||
TcpServer<RtmpSession>::Ptr rtmpSrv(new TcpServer<RtmpSession>());
|
TcpServer<RtmpSession>::Ptr rtmpSrv(new TcpServer<RtmpSession>());
|
||||||
TcpServer<HttpSession>::Ptr httpSrv(new TcpServer<HttpSession>());
|
TcpServer<HttpSession>::Ptr httpSrv(new TcpServer<HttpSession>());
|
||||||
rtspSrv->start(mINI::Instance()[Config::Rtsp::kPort]);//默认554
|
shellSrv->start(shellPort);
|
||||||
rtmpSrv->start(mINI::Instance()[Config::Rtmp::kPort]);//默认1935
|
rtspSrv->start(rtspPort);//默认554
|
||||||
httpSrv->start(mINI::Instance()[Config::Http::kPort]);//默认80
|
rtmpSrv->start(rtmpPort);//默认1935
|
||||||
|
httpSrv->start(httpPort);//默认80
|
||||||
|
|
||||||
#ifdef ENABLE_OPENSSL
|
#ifdef ENABLE_OPENSSL
|
||||||
//如果支持ssl,还可以开启https服务器
|
//如果支持ssl,还可以开启https服务器
|
||||||
TcpServer<HttpsSession>::Ptr httpsSrv(new TcpServer<HttpsSession>());
|
TcpServer<HttpsSession>::Ptr httpsSrv(new TcpServer<HttpsSession>());
|
||||||
httpsSrv->start(mINI::Instance()[Config::Http::kSSLPort]);//默认443
|
httpsSrv->start(httpsPort);//默认443
|
||||||
#endif //ENABLE_OPENSSL
|
#endif //ENABLE_OPENSSL
|
||||||
|
|
||||||
|
NoticeCenter::Instance().addListener(ReloadConfigTag,Config::Broadcast::kBroadcastReloadConfig,[&](BroadcastReloadConfigArgs){
|
||||||
|
//重新创建服务器
|
||||||
|
if(shellPort != mINI::Instance()[Config::Shell::kPort].as<uint16_t>()){
|
||||||
|
shellPort = mINI::Instance()[Config::Shell::kPort];
|
||||||
|
shellSrv->start(shellPort);
|
||||||
|
InfoL << "重启shell服务器:" << shellPort;
|
||||||
|
}
|
||||||
|
if(rtspPort != mINI::Instance()[Config::Rtsp::kPort].as<uint16_t>()){
|
||||||
|
rtspPort = mINI::Instance()[Config::Rtsp::kPort];
|
||||||
|
rtspSrv->start(rtspPort);
|
||||||
|
InfoL << "重启rtsp服务器" << rtspPort;
|
||||||
|
}
|
||||||
|
if(rtmpPort != mINI::Instance()[Config::Rtmp::kPort].as<uint16_t>()){
|
||||||
|
rtmpPort = mINI::Instance()[Config::Rtmp::kPort];
|
||||||
|
rtmpSrv->start(rtmpPort);
|
||||||
|
InfoL << "重启rtmp服务器" << rtmpPort;
|
||||||
|
}
|
||||||
|
if(httpPort != mINI::Instance()[Config::Http::kPort].as<uint16_t>()){
|
||||||
|
httpPort = mINI::Instance()[Config::Http::kPort];
|
||||||
|
httpSrv->start(httpPort);
|
||||||
|
InfoL << "重启http服务器" << httpPort;
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_OPENSSL
|
||||||
|
if(httpsPort != mINI::Instance()[Config::Http::kSSLPort].as<uint16_t>()){
|
||||||
|
httpsPort = mINI::Instance()[Config::Http::kSSLPort];
|
||||||
|
httpsSrv->start(httpsPort);
|
||||||
|
InfoL << "重启https服务器" << httpsPort;
|
||||||
|
}
|
||||||
|
#endif //ENABLE_OPENSSL
|
||||||
|
});
|
||||||
|
|
||||||
EventPoller::Instance().runLoop();
|
EventPoller::Instance().runLoop();
|
||||||
//销毁拉流客户端
|
}//设置作用域,作用域结束后会销毁临时变量;省去手动注销服务器
|
||||||
proxyMap.clear();
|
|
||||||
//销毁服务器
|
|
||||||
shellSrv.reset();
|
|
||||||
rtspSrv.reset();
|
|
||||||
rtmpSrv.reset();
|
|
||||||
httpSrv.reset();
|
|
||||||
|
|
||||||
#ifdef ENABLE_OPENSSL
|
|
||||||
httpsSrv.reset();
|
|
||||||
#endif //ENABLE_OPENSSL
|
|
||||||
|
|
||||||
//rtsp服务器用到udp端口分配器了
|
//rtsp服务器用到udp端口分配器了
|
||||||
UDPServer::Destory();
|
UDPServer::Destory();
|
||||||
|
Loading…
Reference in New Issue
Block a user