mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-29 22:55:52 +08:00
适配ZLToolKit代码,简化程序退出流程代码
This commit is contained in:
parent
315cd180d4
commit
cc7844a994
@ -1 +1 @@
|
|||||||
Subproject commit d3a1bd9d8a3162d0237954034d85f1313008cab2
|
Subproject commit 98d824bdc6604b4e761657922c913ea46bd90223
|
@ -26,17 +26,13 @@
|
|||||||
|
|
||||||
#include "UDPServer.h"
|
#include "UDPServer.h"
|
||||||
#include "Util/TimeTicker.h"
|
#include "Util/TimeTicker.h"
|
||||||
|
#include "Util/onceToken.h"
|
||||||
|
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
UDPServer &UDPServer::Instance() {
|
INSTANCE_IMP(UDPServer);
|
||||||
static UDPServer *instance(new UDPServer());
|
|
||||||
return *instance;
|
|
||||||
}
|
|
||||||
void UDPServer::Destory() {
|
|
||||||
delete &UDPServer::Instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPServer::UDPServer() {
|
UDPServer::UDPServer() {
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,9 @@
|
|||||||
#ifndef RTSP_UDPSERVER_H_
|
#ifndef RTSP_UDPSERVER_H_
|
||||||
#define RTSP_UDPSERVER_H_
|
#define RTSP_UDPSERVER_H_
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include "Util/util.h"
|
#include "Util/util.h"
|
||||||
@ -40,18 +41,23 @@ using namespace toolkit;
|
|||||||
|
|
||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
class UDPServer {
|
class UDPServer : public std::enable_shared_from_this<UDPServer> {
|
||||||
public:
|
public:
|
||||||
typedef function< bool(int, const Buffer::Ptr &, struct sockaddr *)> onRecvData;
|
typedef function< bool(int, const Buffer::Ptr &, struct sockaddr *)> onRecvData;
|
||||||
UDPServer();
|
~UDPServer();
|
||||||
virtual ~UDPServer();
|
|
||||||
static UDPServer &Instance();
|
static UDPServer &Instance();
|
||||||
static void Destory();
|
|
||||||
|
/**
|
||||||
|
* 废弃的接口,无实际操作
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
static void Destory(){};
|
||||||
|
|
||||||
Socket::Ptr getSock(const char *strLocalIp, int iTrackIndex,uint16_t iLocalPort = 0);
|
Socket::Ptr getSock(const char *strLocalIp, int iTrackIndex,uint16_t iLocalPort = 0);
|
||||||
void listenPeer(const char *strPeerIp, void *pSelf, const onRecvData &cb);
|
void listenPeer(const char *strPeerIp, void *pSelf, const onRecvData &cb);
|
||||||
void stopListenPeer(const char *strPeerIp, void *pSelf);
|
void stopListenPeer(const char *strPeerIp, void *pSelf);
|
||||||
private:
|
private:
|
||||||
|
UDPServer();
|
||||||
void onRcvData(int iTrackId, const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr);
|
void onRcvData(int iTrackId, const Buffer::Ptr &pBuf,struct sockaddr *pPeerAddr);
|
||||||
void onErr(const string &strKey,const SockException &err);
|
void onErr(const string &strKey,const SockException &err);
|
||||||
unordered_map<string, Socket::Ptr> _mapUpdSock;
|
unordered_map<string, Socket::Ptr> _mapUpdSock;
|
||||||
|
@ -142,7 +142,7 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
WarnL << "不支持的rtp类型:" << nal.type << " " << rtppack->sequence;
|
WarnL << "不支持的rtp类型:" << (int)nal.type << " " << rtppack->sequence;
|
||||||
return false;
|
return false;
|
||||||
// 29 FU-B 单NAL单元B模式
|
// 29 FU-B 单NAL单元B模式
|
||||||
// 24 STAP-A 单一时间的组合包
|
// 24 STAP-A 单一时间的组合包
|
||||||
|
@ -41,9 +41,10 @@ using namespace mediakit;
|
|||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
//设置退出信号处理函数
|
//设置退出信号处理函数
|
||||||
signal(SIGINT, [](int) { EventPoller::Instance().shutdown(); });
|
signal(SIGINT, [](int) { EventPollerPool::Instance().shutdown(); });
|
||||||
|
|
||||||
//设置日志
|
//设置日志
|
||||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
|
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
|
|
||||||
if (argc != 5) {
|
if (argc != 5) {
|
||||||
@ -55,42 +56,33 @@ int main(int argc, char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
{
|
list<MediaPlayer::Ptr> playerList;
|
||||||
list<MediaPlayer::Ptr> playerList;
|
auto playerCnt = atoi(argv[1]);//启动的播放器个数
|
||||||
auto playerCnt = atoi(argv[1]);//启动的播放器个数
|
atomic_int alivePlayerCnt(0);
|
||||||
atomic_int alivePlayerCnt(0);
|
//每隔若干毫秒启动一个播放器(如果一次性全部启动,服务器和客户端可能都承受不了)
|
||||||
//每隔若干毫秒启动一个播放器(如果一次性全部启动,服务器和客户端可能都承受不了)
|
AsyncTaskThread::Instance().DoTaskDelay(0, atoi(argv[2]), [&]() {
|
||||||
AsyncTaskThread::Instance().DoTaskDelay(0, atoi(argv[2]), [&]() {
|
MediaPlayer::Ptr player(new MediaPlayer());
|
||||||
MediaPlayer::Ptr player(new MediaPlayer());
|
player->setOnPlayResult([&](const SockException &ex) {
|
||||||
player->setOnPlayResult([&](const SockException &ex) {
|
if (!ex) {
|
||||||
if (!ex) {
|
++alivePlayerCnt;
|
||||||
++alivePlayerCnt;
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
player->setOnShutdown([&](const SockException &ex) {
|
|
||||||
--alivePlayerCnt;
|
|
||||||
});
|
|
||||||
(*player)[RtspPlayer::kRtpType] = atoi(argv[4]);
|
|
||||||
player->play(argv[3]);
|
|
||||||
playerList.push_back(player);
|
|
||||||
return playerCnt--;
|
|
||||||
});
|
});
|
||||||
|
player->setOnShutdown([&](const SockException &ex) {
|
||||||
AsyncTaskThread::Instance().DoTaskDelay(0, 1000, [&]() {
|
--alivePlayerCnt;
|
||||||
InfoL << "存活播放器个数:" << alivePlayerCnt.load();
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
EventPoller::Instance().runLoop();
|
(*player)[RtspPlayer::kRtpType] = atoi(argv[4]);
|
||||||
AsyncTaskThread::Instance().CancelTask(0);
|
player->play(argv[3]);
|
||||||
}
|
playerList.push_back(player);
|
||||||
|
return playerCnt--;
|
||||||
static onceToken token(nullptr, []() {
|
|
||||||
WorkThreadPool::Instance();
|
|
||||||
UDPServer::Destory();
|
|
||||||
EventPoller::Destory();
|
|
||||||
AsyncTaskThread::Destory();
|
|
||||||
Logger::Destory();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AsyncTaskThread::Instance().DoTaskDelay(0, 1000, [&]() {
|
||||||
|
InfoL << "存活播放器个数:" << alivePlayerCnt.load();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
EventPollerPool::Instance().wait();
|
||||||
|
AsyncTaskThread::Instance().CancelTask(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,10 +102,11 @@ static onceToken s_token([](){
|
|||||||
|
|
||||||
int main(int argc,char *argv[]){
|
int main(int argc,char *argv[]){
|
||||||
//设置退出信号处理函数
|
//设置退出信号处理函数
|
||||||
signal(SIGINT, [](int){EventPoller::Instance().shutdown();});
|
signal(SIGINT, [](int){EventPollerPool::Instance().shutdown();});
|
||||||
//设置日志
|
//设置日志
|
||||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
|
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
|
|
||||||
//加载配置文件,如果配置文件不存在就创建一个
|
//加载配置文件,如果配置文件不存在就创建一个
|
||||||
loadIniConfig();
|
loadIniConfig();
|
||||||
|
|
||||||
@ -132,14 +133,7 @@ int main(int argc,char *argv[]){
|
|||||||
|
|
||||||
InfoL << "你可以在浏览器输入:http://127.0.0.1/api/my_api?key0=val0&key1=参数1" << endl;
|
InfoL << "你可以在浏览器输入:http://127.0.0.1/api/my_api?key0=val0&key1=参数1" << endl;
|
||||||
|
|
||||||
EventPoller::Instance().runLoop();
|
EventPollerPool::Instance().wait();
|
||||||
|
|
||||||
static onceToken s_token(nullptr,[]() {
|
|
||||||
//TcpServer用到了WorkThreadPool
|
|
||||||
WorkThreadPool::Destory();
|
|
||||||
EventPoller::Destory();
|
|
||||||
Logger::Destory();
|
|
||||||
});
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,93 +41,132 @@ using namespace mediakit;
|
|||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
//设置退出信号处理函数
|
//设置退出信号处理函数
|
||||||
signal(SIGINT, [](int) { EventPoller::Instance().shutdown(); });
|
signal(SIGINT, [](int) { EventPollerPool::Instance().shutdown(); });
|
||||||
//设置日志
|
//设置日志
|
||||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
|
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
{
|
|
||||||
///////////////////////////////http downloader///////////////////////
|
|
||||||
//下载器map
|
|
||||||
map<string, HttpDownloader::Ptr> downloaderMap;
|
|
||||||
//下载两个文件,一个是http下载,一个https下载
|
|
||||||
auto urlList = {"https://timgsa.baidu.com/timg?image&quality=80&"
|
|
||||||
"size=b9999_10000&sec=1537717640404&"
|
|
||||||
"di=f602efbebbc1e7f6b9ccb0bf0def89d0&"
|
|
||||||
"imgtype=0&"
|
|
||||||
"src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F241f95cad1c8a786ff65052a6d09c93d70cf5042.jpg",};
|
|
||||||
|
|
||||||
for (auto &url : urlList) {
|
///////////////////////////////http downloader///////////////////////
|
||||||
//创建下载器
|
//下载器map
|
||||||
HttpDownloader::Ptr downloader(new HttpDownloader());
|
map<string, HttpDownloader::Ptr> downloaderMap;
|
||||||
downloader->setOnResult([](ErrCode code, const char *errMsg, const char *filePath) {
|
//下载两个文件,一个是http下载,一个https下载
|
||||||
DebugL << "=====================HttpDownloader result=======================";
|
auto urlList = {"https://timgsa.baidu.com/timg?image&quality=80&"
|
||||||
//下载结果回调
|
"size=b9999_10000&sec=1537717640404&"
|
||||||
if (code == Err_success) {
|
"di=f602efbebbc1e7f6b9ccb0bf0def89d0&"
|
||||||
//文件下载成功
|
"imgtype=0&"
|
||||||
InfoL << "download file success:" << filePath;
|
"src=http%3A%2F%2Fimgsrc.baidu.com%2Fimgad%2Fpic%2Fitem%2F241f95cad1c8a786ff65052a6d09c93d70cf5042.jpg",};
|
||||||
} else {
|
|
||||||
//下载失败
|
|
||||||
WarnL << "code:" << code << " msg:" << errMsg;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//断点续传功能,开启后可能会遇到416的错误(因为上次文件已经下载完全)
|
|
||||||
downloader->startDownload(url, exeDir() + MD5(url).hexdigest() + ".jpg", true);
|
|
||||||
//下载器必须被强引用,否则作用域一失效就会导致对象销毁
|
|
||||||
downloaderMap.emplace(url, downloader);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////http get///////////////////////
|
for (auto &url : urlList) {
|
||||||
//创建一个Http请求器
|
//创建下载器
|
||||||
HttpRequester::Ptr requesterGet(new HttpRequester());
|
HttpDownloader::Ptr downloader(new HttpDownloader());
|
||||||
//使用GET方式请求
|
downloader->setOnResult([](ErrCode code, const char *errMsg, const char *filePath) {
|
||||||
requesterGet->setMethod("GET");
|
DebugL << "=====================HttpDownloader result=======================";
|
||||||
//设置http请求头,我们假设设置cookie,当然你也可以设置其他http头
|
//下载结果回调
|
||||||
requesterGet->addHeader("Cookie", "SESSIONID=e1aa89b3-f79f-4ac6-8ae2-0cea9ae8e2d7");
|
if (code == Err_success) {
|
||||||
//开启请求,该api会返回当前主机外网ip等信息
|
//文件下载成功
|
||||||
requesterGet->startRequester("http://pv.sohu.com/cityjson?ie=utf-8",//url地址
|
InfoL << "download file success:" << filePath;
|
||||||
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
|
} else {
|
||||||
const string &status, //http回复的状态码,比如说200/404
|
//下载失败
|
||||||
const HttpClient::HttpHeader &header, //http回复头
|
WarnL << "code:" << code << " msg:" << errMsg;
|
||||||
const string &strRecvBody) { //http回复body
|
}
|
||||||
DebugL << "=====================HttpRequester GET===========================";
|
});
|
||||||
if (ex) {
|
//断点续传功能,开启后可能会遇到416的错误(因为上次文件已经下载完全)
|
||||||
//网络相关的错误
|
downloader->startDownload(url, exeDir() + MD5(url).hexdigest() + ".jpg", true);
|
||||||
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
|
//下载器必须被强引用,否则作用域一失效就会导致对象销毁
|
||||||
} else {
|
downloaderMap.emplace(url, downloader);
|
||||||
//打印http回复信息
|
}
|
||||||
_StrPrinter printer;
|
|
||||||
for (auto &pr: header) {
|
///////////////////////////////http get///////////////////////
|
||||||
printer << pr.first << ":" << pr.second << "\r\n";
|
//创建一个Http请求器
|
||||||
}
|
HttpRequester::Ptr requesterGet(new HttpRequester());
|
||||||
InfoL << "status:" << status << "\r\n"
|
//使用GET方式请求
|
||||||
<< "header:\r\n" << (printer << endl)
|
requesterGet->setMethod("GET");
|
||||||
<< "\r\nbody:" << strRecvBody;
|
//设置http请求头,我们假设设置cookie,当然你也可以设置其他http头
|
||||||
|
requesterGet->addHeader("Cookie", "SESSIONID=e1aa89b3-f79f-4ac6-8ae2-0cea9ae8e2d7");
|
||||||
|
//开启请求,该api会返回当前主机外网ip等信息
|
||||||
|
requesterGet->startRequester("http://pv.sohu.com/cityjson?ie=utf-8",//url地址
|
||||||
|
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
|
||||||
|
const string &status, //http回复的状态码,比如说200/404
|
||||||
|
const HttpClient::HttpHeader &header, //http回复头
|
||||||
|
const string &strRecvBody) { //http回复body
|
||||||
|
DebugL << "=====================HttpRequester GET===========================";
|
||||||
|
if (ex) {
|
||||||
|
//网络相关的错误
|
||||||
|
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
|
||||||
|
} else {
|
||||||
|
//打印http回复信息
|
||||||
|
_StrPrinter printer;
|
||||||
|
for (auto &pr: header) {
|
||||||
|
printer << pr.first << ":" << pr.second << "\r\n";
|
||||||
}
|
}
|
||||||
});
|
InfoL << "status:" << status << "\r\n"
|
||||||
|
<< "header:\r\n" << (printer << endl)
|
||||||
|
<< "\r\nbody:" << strRecvBody;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
///////////////////////////////http post///////////////////////
|
///////////////////////////////http post///////////////////////
|
||||||
//创建一个Http请求器
|
//创建一个Http请求器
|
||||||
HttpRequester::Ptr requesterPost(new HttpRequester());
|
HttpRequester::Ptr requesterPost(new HttpRequester());
|
||||||
//使用POST方式请求
|
//使用POST方式请求
|
||||||
requesterPost->setMethod("POST");
|
requesterPost->setMethod("POST");
|
||||||
//设置http请求头
|
//设置http请求头
|
||||||
requesterPost->addHeader("X-Requested-With", "XMLHttpRequest");
|
requesterPost->addHeader("X-Requested-With", "XMLHttpRequest");
|
||||||
requesterPost->addHeader("Origin", "http://fanyi.baidu.com");
|
requesterPost->addHeader("Origin", "http://fanyi.baidu.com");
|
||||||
//设置POST参数列表
|
//设置POST参数列表
|
||||||
HttpArgs args;
|
HttpArgs args;
|
||||||
args["query"] = "test";
|
args["query"] = "test";
|
||||||
args["from"] = "en";
|
args["from"] = "en";
|
||||||
args["to"] = "zh";
|
args["to"] = "zh";
|
||||||
args["transtype"] = "translang";
|
args["transtype"] = "translang";
|
||||||
args["simple_means_flag"] = "3";
|
args["simple_means_flag"] = "3";
|
||||||
requesterPost->setBody(args.make());
|
requesterPost->setBody(args.make());
|
||||||
//开启请求
|
//开启请求
|
||||||
requesterPost->startRequester("http://fanyi.baidu.com/langdetect",//url地址
|
requesterPost->startRequester("http://fanyi.baidu.com/langdetect",//url地址
|
||||||
|
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
|
||||||
|
const string &status, //http回复的状态码,比如说200/404
|
||||||
|
const HttpClient::HttpHeader &header, //http回复头
|
||||||
|
const string &strRecvBody) { //http回复body
|
||||||
|
DebugL << "=====================HttpRequester POST==========================";
|
||||||
|
if (ex) {
|
||||||
|
//网络相关的错误
|
||||||
|
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
|
||||||
|
} else {
|
||||||
|
//打印http回复信息
|
||||||
|
_StrPrinter printer;
|
||||||
|
for (auto &pr: header) {
|
||||||
|
printer << pr.first << ":" << pr.second << "\r\n";
|
||||||
|
}
|
||||||
|
InfoL << "status:" << status << "\r\n"
|
||||||
|
<< "header:\r\n" << (printer << endl)
|
||||||
|
<< "\r\nbody:" << strRecvBody;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
///////////////////////////////http upload///////////////////////
|
||||||
|
//创建一个Http请求器
|
||||||
|
HttpRequester::Ptr requesterUploader(new HttpRequester());
|
||||||
|
//使用POST方式请求
|
||||||
|
requesterUploader->setMethod("POST");
|
||||||
|
//设置http请求头
|
||||||
|
HttpArgs argsUploader;
|
||||||
|
argsUploader["query"] = "test";
|
||||||
|
argsUploader["from"] = "en";
|
||||||
|
argsUploader["to"] = "zh";
|
||||||
|
argsUploader["transtype"] = "translang";
|
||||||
|
argsUploader["simple_means_flag"] = "3";
|
||||||
|
|
||||||
|
static string boundary = "0xKhTmLbOuNdArY";
|
||||||
|
HttpMultiFormBody::Ptr body(new HttpMultiFormBody(argsUploader, exePath(), boundary));
|
||||||
|
requesterUploader->setBody(body);
|
||||||
|
requesterUploader->addHeader("Content-Type", HttpMultiFormBody::multiFormContentType(boundary));
|
||||||
|
//开启请求
|
||||||
|
requesterUploader->startRequester("http://fanyi.baidu.com/langdetect",//url地址
|
||||||
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
|
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
|
||||||
const string &status, //http回复的状态码,比如说200/404
|
const string &status, //http回复的状态码,比如说200/404
|
||||||
const HttpClient::HttpHeader &header, //http回复头
|
const HttpClient::HttpHeader &header, //http回复头
|
||||||
const string &strRecvBody) { //http回复body
|
const string &strRecvBody) { //http回复body
|
||||||
DebugL << "=====================HttpRequester POST==========================";
|
DebugL << "=====================HttpRequester Uploader==========================";
|
||||||
if (ex) {
|
if (ex) {
|
||||||
//网络相关的错误
|
//网络相关的错误
|
||||||
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
|
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
|
||||||
@ -143,52 +182,8 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
///////////////////////////////http upload///////////////////////
|
//事件轮询
|
||||||
//创建一个Http请求器
|
EventPollerPool::Instance().wait();
|
||||||
HttpRequester::Ptr requesterUploader(new HttpRequester());
|
|
||||||
//使用POST方式请求
|
|
||||||
requesterUploader->setMethod("POST");
|
|
||||||
//设置http请求头
|
|
||||||
HttpArgs argsUploader;
|
|
||||||
argsUploader["query"] = "test";
|
|
||||||
argsUploader["from"] = "en";
|
|
||||||
argsUploader["to"] = "zh";
|
|
||||||
argsUploader["transtype"] = "translang";
|
|
||||||
argsUploader["simple_means_flag"] = "3";
|
|
||||||
|
|
||||||
static string boundary = "0xKhTmLbOuNdArY";
|
|
||||||
HttpMultiFormBody::Ptr body(new HttpMultiFormBody(argsUploader, exePath(), boundary));
|
|
||||||
requesterUploader->setBody(body);
|
|
||||||
requesterUploader->addHeader("Content-Type", HttpMultiFormBody::multiFormContentType(boundary));
|
|
||||||
//开启请求
|
|
||||||
requesterUploader->startRequester("http://fanyi.baidu.com/langdetect",//url地址
|
|
||||||
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
|
|
||||||
const string &status, //http回复的状态码,比如说200/404
|
|
||||||
const HttpClient::HttpHeader &header, //http回复头
|
|
||||||
const string &strRecvBody) { //http回复body
|
|
||||||
DebugL << "=====================HttpRequester Uploader==========================";
|
|
||||||
if (ex) {
|
|
||||||
//网络相关的错误
|
|
||||||
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
|
|
||||||
} else {
|
|
||||||
//打印http回复信息
|
|
||||||
_StrPrinter printer;
|
|
||||||
for (auto &pr: header) {
|
|
||||||
printer << pr.first << ":" << pr.second << "\r\n";
|
|
||||||
}
|
|
||||||
InfoL << "status:" << status << "\r\n"
|
|
||||||
<< "header:\r\n" << (printer << endl)
|
|
||||||
<< "\r\nbody:" << strRecvBody;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//事件轮询
|
|
||||||
EventPoller::Instance().runLoop();
|
|
||||||
}
|
|
||||||
//程序开始退出
|
|
||||||
EventPoller::Destory();
|
|
||||||
AsyncTaskThread::Destory();
|
|
||||||
Logger::Destory();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,8 @@ int main(int argc, char *argv[]) {
|
|||||||
//设置退出信号处理函数
|
//设置退出信号处理函数
|
||||||
signal(SIGINT, [](int) { SDLDisplayerHelper::Instance().shutdown(); });
|
signal(SIGINT, [](int) { SDLDisplayerHelper::Instance().shutdown(); });
|
||||||
//设置日志
|
//设置日志
|
||||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
|
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||||
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
|
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
ErrorL << "\r\n测试方法:./test_player rtxp_url rtp_type\r\n"
|
ErrorL << "\r\n测试方法:./test_player rtxp_url rtp_type\r\n"
|
||||||
@ -54,51 +55,46 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
MediaPlayer::Ptr player(new MediaPlayer());
|
||||||
MediaPlayer::Ptr player(new MediaPlayer());
|
weak_ptr<MediaPlayer> weakPlayer = player;
|
||||||
weak_ptr<MediaPlayer> weakPlayer = player;
|
player->setOnPlayResult([weakPlayer](const SockException &ex) {
|
||||||
player->setOnPlayResult([weakPlayer](const SockException &ex) {
|
InfoL << "OnPlayResult:" << ex.what();
|
||||||
InfoL << "OnPlayResult:" << ex.what();
|
auto strongPlayer = weakPlayer.lock();
|
||||||
auto strongPlayer = weakPlayer.lock();
|
if (ex || !strongPlayer) {
|
||||||
if (ex || !strongPlayer) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto viedoTrack = strongPlayer->getTrack(TrackVideo);
|
auto viedoTrack = strongPlayer->getTrack(TrackVideo);
|
||||||
if (!viedoTrack || viedoTrack->getCodecId() != CodecH264) {
|
if (!viedoTrack || viedoTrack->getCodecId() != CodecH264) {
|
||||||
WarnL << "没有视频或者视频不是264编码!";
|
WarnL << "没有视频或者视频不是264编码!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SDLDisplayerHelper::Instance().doTask([viedoTrack]() {
|
SDLDisplayerHelper::Instance().doTask([viedoTrack]() {
|
||||||
std::shared_ptr<H264Decoder> decoder(new H264Decoder);
|
std::shared_ptr<H264Decoder> decoder(new H264Decoder);
|
||||||
std::shared_ptr<YuvDisplayer> displayer(new YuvDisplayer);
|
std::shared_ptr<YuvDisplayer> displayer(new YuvDisplayer);
|
||||||
viedoTrack->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([decoder, displayer](const Frame::Ptr &frame) {
|
viedoTrack->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([decoder, displayer](const Frame::Ptr &frame) {
|
||||||
SDLDisplayerHelper::Instance().doTask([decoder, displayer, frame]() {
|
SDLDisplayerHelper::Instance().doTask([decoder, displayer, frame]() {
|
||||||
AVFrame *pFrame = nullptr;
|
AVFrame *pFrame = nullptr;
|
||||||
bool flag = decoder->inputVideo((unsigned char *) frame->data(), frame->size(),
|
bool flag = decoder->inputVideo((unsigned char *) frame->data(), frame->size(),
|
||||||
frame->stamp(), &pFrame);
|
frame->stamp(), &pFrame);
|
||||||
if (flag) {
|
if (flag) {
|
||||||
displayer->displayYUV(pFrame);
|
displayer->displayYUV(pFrame);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
return true;
|
return true;
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
player->setOnShutdown([](const SockException &ex) {
|
player->setOnShutdown([](const SockException &ex) {
|
||||||
ErrorL << "OnShutdown:" << ex.what();
|
ErrorL << "OnShutdown:" << ex.what();
|
||||||
});
|
});
|
||||||
(*player)[RtspPlayer::kRtpType] = atoi(argv[2]);
|
(*player)[RtspPlayer::kRtpType] = atoi(argv[2]);
|
||||||
player->play(argv[1]);
|
player->play(argv[1]);
|
||||||
SDLDisplayerHelper::Instance().runLoop();
|
|
||||||
}
|
SDLDisplayerHelper::Instance().runLoop();
|
||||||
UDPServer::Destory();
|
|
||||||
EventPoller::Destory();
|
|
||||||
AsyncTaskThread::Destory();
|
|
||||||
Logger::Destory();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,37 +83,26 @@ void rePushDelay(const string &app, const string &stream, const string &url) {
|
|||||||
//这里才是真正执行main函数,你可以把函数名(domain)改成main,然后就可以输入自定义url了
|
//这里才是真正执行main函数,你可以把函数名(domain)改成main,然后就可以输入自定义url了
|
||||||
int domain(const string &playUrl, const string &pushUrl) {
|
int domain(const string &playUrl, const string &pushUrl) {
|
||||||
//设置退出信号处理函数
|
//设置退出信号处理函数
|
||||||
signal(SIGINT, [](int) { EventPoller::Instance().shutdown(); });
|
signal(SIGINT, [](int) { EventPollerPool::Instance().shutdown(); });
|
||||||
//设置日志
|
//设置日志
|
||||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
|
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
|
|
||||||
{
|
//拉一个流,生成一个RtmpMediaSource,源的名称是"app/stream"
|
||||||
//拉一个流,生成一个RtmpMediaSource,源的名称是"app/stream"
|
//你也可以以其他方式生成RtmpMediaSource,比如说MP4文件(请查看test_rtmpPusherMp4.cpp代码)
|
||||||
//你也可以以其他方式生成RtmpMediaSource,比如说MP4文件(请查看test_rtmpPusherMp4.cpp代码)
|
PlayerProxy::Ptr player(new PlayerProxy(DEFAULT_VHOST, "app", "stream"));
|
||||||
PlayerProxy::Ptr player(new PlayerProxy(DEFAULT_VHOST, "app", "stream"));
|
player->play(playUrl.data());
|
||||||
player->play(playUrl.data());
|
|
||||||
|
|
||||||
//监听RtmpMediaSource注册事件,在PlayerProxy播放成功后触发
|
//监听RtmpMediaSource注册事件,在PlayerProxy播放成功后触发
|
||||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastMediaChanged,
|
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastMediaChanged,
|
||||||
[pushUrl](BroadcastMediaChangedArgs) {
|
[pushUrl](BroadcastMediaChangedArgs) {
|
||||||
//媒体源"app/stream"已经注册,这时方可新建一个RtmpPusher对象并绑定该媒体源
|
//媒体源"app/stream"已经注册,这时方可新建一个RtmpPusher对象并绑定该媒体源
|
||||||
if(bRegist && schema == RTMP_SCHEMA){
|
if(bRegist && schema == RTMP_SCHEMA){
|
||||||
createPusher(app, stream, pushUrl);
|
createPusher(app, stream, pushUrl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
//事件轮询
|
||||||
//事件轮询
|
EventPollerPool::Instance().wait();
|
||||||
EventPoller::Instance().runLoop();
|
|
||||||
pusher.reset();
|
|
||||||
}
|
|
||||||
//删除事件监听
|
|
||||||
NoticeCenter::Instance().delListener(nullptr);
|
|
||||||
|
|
||||||
//清理程序
|
|
||||||
EventPoller::Destory();
|
|
||||||
AsyncTaskThread::Destory();
|
|
||||||
Logger::Destory();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +92,9 @@ void rePushDelay(const string &app,const string &stream,const string &url){
|
|||||||
//这里才是真正执行main函数,你可以把函数名(domain)改成main,然后就可以输入自定义url了
|
//这里才是真正执行main函数,你可以把函数名(domain)改成main,然后就可以输入自定义url了
|
||||||
int domain(const string & filePath,const string & pushUrl){
|
int domain(const string & filePath,const string & pushUrl){
|
||||||
//设置退出信号处理函数
|
//设置退出信号处理函数
|
||||||
signal(SIGINT, [](int){EventPoller::Instance().shutdown();});
|
signal(SIGINT, [](int){EventPollerPool::Instance().shutdown();});
|
||||||
//设置日志
|
//设置日志
|
||||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
|
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
|
|
||||||
//录像应用名称默认为record
|
//录像应用名称默认为record
|
||||||
@ -104,16 +104,7 @@ int domain(const string & filePath,const string & pushUrl){
|
|||||||
createPusher(appName,filePath,pushUrl);
|
createPusher(appName,filePath,pushUrl);
|
||||||
|
|
||||||
//开始事件轮询
|
//开始事件轮询
|
||||||
EventPoller::Instance().runLoop();
|
EventPollerPool::Instance().wait();
|
||||||
//删除事件监听
|
|
||||||
NoticeCenter::Instance().delListener(nullptr);
|
|
||||||
//销毁推流器
|
|
||||||
pusher.reset();
|
|
||||||
|
|
||||||
//程序清理
|
|
||||||
EventPoller::Destory();
|
|
||||||
AsyncTaskThread::Destory();
|
|
||||||
Logger::Destory();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,141 +229,132 @@ static onceToken s_token([](){
|
|||||||
|
|
||||||
int main(int argc,char *argv[]) {
|
int main(int argc,char *argv[]) {
|
||||||
//设置退出信号处理函数
|
//设置退出信号处理函数
|
||||||
signal(SIGINT, [](int) { EventPoller::Instance().shutdown(); });
|
signal(SIGINT, [](int) { EventPollerPool::Instance().shutdown(); });
|
||||||
signal(SIGHUP, [](int) { loadIniConfig(); });
|
signal(SIGHUP, [](int) { loadIniConfig(); });
|
||||||
|
|
||||||
//设置日志
|
//设置日志
|
||||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("stdout", LTrace));
|
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||||
|
Logger::Instance().add(std::make_shared<FileChannel>());
|
||||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||||
//加载配置文件,如果配置文件不存在就创建一个
|
//加载配置文件,如果配置文件不存在就创建一个
|
||||||
loadIniConfig();
|
loadIniConfig();
|
||||||
{
|
|
||||||
//这里是拉流地址,支持rtmp/rtsp协议,负载必须是H264+AAC
|
|
||||||
//如果是其他不识别的音视频将会被忽略(譬如说h264+adpcm转发后会去除音频)
|
|
||||||
auto urlList = {"rtmp://live.hkstv.hk.lxdns.com/live/hks1",
|
|
||||||
"rtmp://live.hkstv.hk.lxdns.com/live/hks2"
|
|
||||||
//rtsp链接支持输入用户名密码
|
|
||||||
/*"rtsp://admin:jzan123456@192.168.0.122/"*/};
|
|
||||||
map<string, PlayerProxy::Ptr> proxyMap;
|
|
||||||
int i = 0;
|
|
||||||
for (auto &url : urlList) {
|
|
||||||
//PlayerProxy构造函数前两个参数分别为应用名(app),流id(streamId)
|
|
||||||
//比如说应用为live,流id为0,那么直播地址为:
|
|
||||||
|
|
||||||
//hls地址 : http://127.0.0.1/live/0/hls.m3u8
|
//这里是拉流地址,支持rtmp/rtsp协议,负载必须是H264+AAC
|
||||||
//http-flv地址 : http://127.0.0.1/live/0.flv
|
//如果是其他不识别的音视频将会被忽略(譬如说h264+adpcm转发后会去除音频)
|
||||||
//rtsp地址 : rtsp://127.0.0.1/live/0
|
auto urlList = {"rtmp://live.hkstv.hk.lxdns.com/live/hks1",
|
||||||
//rtmp地址 : rtmp://127.0.0.1/live/0
|
"rtmp://live.hkstv.hk.lxdns.com/live/hks2"
|
||||||
|
//rtsp链接支持输入用户名密码
|
||||||
|
/*"rtsp://admin:jzan123456@192.168.0.122/"*/};
|
||||||
|
map<string, PlayerProxy::Ptr> proxyMap;
|
||||||
|
int i = 0;
|
||||||
|
for (auto &url : urlList) {
|
||||||
|
//PlayerProxy构造函数前两个参数分别为应用名(app),流id(streamId)
|
||||||
|
//比如说应用为live,流id为0,那么直播地址为:
|
||||||
|
|
||||||
//录像地址为(当然vlc不支持这么多级的rtmp url,可以用test_player测试rtmp点播):
|
//hls地址 : http://127.0.0.1/live/0/hls.m3u8
|
||||||
//http://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
//http-flv地址 : http://127.0.0.1/live/0.flv
|
||||||
//rtsp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
//rtsp地址 : rtsp://127.0.0.1/live/0
|
||||||
//rtmp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
//rtmp地址 : rtmp://127.0.0.1/live/0
|
||||||
|
|
||||||
PlayerProxy::Ptr player(new PlayerProxy(DEFAULT_VHOST, "live", to_string(i).data()));
|
//录像地址为(当然vlc不支持这么多级的rtmp url,可以用test_player测试rtmp点播):
|
||||||
//指定RTP over TCP(播放rtsp时有效)
|
//http://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
||||||
(*player)[RtspPlayer::kRtpType] = PlayerBase::RTP_TCP;
|
//rtsp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
||||||
//开始播放,如果播放失败或者播放中止,将会自动重试若干次,重试次数在配置文件中配置,默认一直重试
|
//rtmp://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
||||||
player->play(url);
|
|
||||||
//需要保存PlayerProxy,否则作用域结束就会销毁该对象
|
PlayerProxy::Ptr player(new PlayerProxy(DEFAULT_VHOST, "live", to_string(i).data()));
|
||||||
proxyMap.emplace(to_string(i), player);
|
//指定RTP over TCP(播放rtsp时有效)
|
||||||
++i;
|
(*player)[RtspPlayer::kRtpType] = PlayerBase::RTP_TCP;
|
||||||
|
//开始播放,如果播放失败或者播放中止,将会自动重试若干次,重试次数在配置文件中配置,默认一直重试
|
||||||
|
player->play(url);
|
||||||
|
//需要保存PlayerProxy,否则作用域结束就会销毁该对象
|
||||||
|
proxyMap.emplace(to_string(i), player);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugL << "\r\n"
|
||||||
|
" PlayerProxy构造函数前两个参数分别为应用名(app),流id(streamId)\n"
|
||||||
|
" 比如说应用为live,流id为0,那么直播地址为:\n"
|
||||||
|
" hls地址 : http://127.0.0.1/live/0/hls.m3u8\n"
|
||||||
|
" http-flv地址 : http://127.0.0.1/live/0.flv\n"
|
||||||
|
" rtsp地址 : rtsp://127.0.0.1/live/0\n"
|
||||||
|
" rtmp地址 : rtmp://127.0.0.1/live/0";
|
||||||
|
|
||||||
|
//请把证书"test_server.pem"放置在本程序可执行程序同目录下
|
||||||
|
try {
|
||||||
|
//加载证书,证书包含公钥和私钥
|
||||||
|
SSL_Initor::Instance().loadServerPem((exePath() + ".pem").data());
|
||||||
|
} catch (...) {
|
||||||
|
ErrorL << "请把证书:" << (exeName() + ".pem") << "放置在本程序可执行程序同目录下:" << exeDir() << endl;
|
||||||
|
proxyMap.clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t shellPort = mINI::Instance()[Shell::kPort];
|
||||||
|
uint16_t rtspPort = mINI::Instance()[Rtsp::kPort];
|
||||||
|
uint16_t rtspsPort = mINI::Instance()[Rtsp::kSSLPort];
|
||||||
|
uint16_t rtmpPort = mINI::Instance()[Rtmp::kPort];
|
||||||
|
uint16_t httpPort = mINI::Instance()[Http::kPort];
|
||||||
|
uint16_t httpsPort = mINI::Instance()[Http::kSSLPort];
|
||||||
|
|
||||||
|
//简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象
|
||||||
|
//测试方法:telnet 127.0.0.1 9000
|
||||||
|
TcpServer::Ptr shellSrv(new TcpServer());
|
||||||
|
TcpServer::Ptr rtspSrv(new TcpServer());
|
||||||
|
TcpServer::Ptr rtmpSrv(new TcpServer());
|
||||||
|
TcpServer::Ptr httpSrv(new TcpServer());
|
||||||
|
|
||||||
|
shellSrv->start<ShellSession>(shellPort);
|
||||||
|
rtspSrv->start<RtspSession>(rtspPort);//默认554
|
||||||
|
rtmpSrv->start<RtmpSession>(rtmpPort);//默认1935
|
||||||
|
//http服务器,支持websocket
|
||||||
|
httpSrv->start<EchoWebSocketSession>(httpPort);//默认80
|
||||||
|
|
||||||
|
//如果支持ssl,还可以开启https服务器
|
||||||
|
TcpServer::Ptr httpsSrv(new TcpServer());
|
||||||
|
//https服务器,支持websocket
|
||||||
|
httpsSrv->start<SSLEchoWebSocketSession>(httpsPort);//默认443
|
||||||
|
|
||||||
|
//支持ssl加密的rtsp服务器,可用于诸如亚马逊echo show这样的设备访问
|
||||||
|
TcpServer::Ptr rtspSSLSrv(new TcpServer());
|
||||||
|
rtspSSLSrv->start<RtspSessionWithSSL>(rtspsPort);//默认322
|
||||||
|
|
||||||
|
//服务器支持动态切换端口(不影响现有连接)
|
||||||
|
NoticeCenter::Instance().addListener(ReloadConfigTag,Broadcast::kBroadcastReloadConfig,[&](BroadcastReloadConfigArgs){
|
||||||
|
//重新创建服务器
|
||||||
|
if(shellPort != mINI::Instance()[Shell::kPort].as<uint16_t>()){
|
||||||
|
shellPort = mINI::Instance()[Shell::kPort];
|
||||||
|
shellSrv->start<ShellSession>(shellPort);
|
||||||
|
InfoL << "重启shell服务器:" << shellPort;
|
||||||
|
}
|
||||||
|
if(rtspPort != mINI::Instance()[Rtsp::kPort].as<uint16_t>()){
|
||||||
|
rtspPort = mINI::Instance()[Rtsp::kPort];
|
||||||
|
rtspSrv->start<RtspSession>(rtspPort);
|
||||||
|
InfoL << "重启rtsp服务器" << rtspPort;
|
||||||
|
}
|
||||||
|
if(rtmpPort != mINI::Instance()[Rtmp::kPort].as<uint16_t>()){
|
||||||
|
rtmpPort = mINI::Instance()[Rtmp::kPort];
|
||||||
|
rtmpSrv->start<RtmpSession>(rtmpPort);
|
||||||
|
InfoL << "重启rtmp服务器" << rtmpPort;
|
||||||
|
}
|
||||||
|
if(httpPort != mINI::Instance()[Http::kPort].as<uint16_t>()){
|
||||||
|
httpPort = mINI::Instance()[Http::kPort];
|
||||||
|
httpSrv->start<EchoWebSocketSession>(httpPort);
|
||||||
|
InfoL << "重启http服务器" << httpPort;
|
||||||
|
}
|
||||||
|
if(httpsPort != mINI::Instance()[Http::kSSLPort].as<uint16_t>()){
|
||||||
|
httpsPort = mINI::Instance()[Http::kSSLPort];
|
||||||
|
httpsSrv->start<SSLEchoWebSocketSession>(httpsPort);
|
||||||
|
InfoL << "重启https服务器" << httpsPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugL << "\r\n"
|
if(rtspsPort != mINI::Instance()[Rtsp::kSSLPort].as<uint16_t>()){
|
||||||
" PlayerProxy构造函数前两个参数分别为应用名(app),流id(streamId)\n"
|
rtspsPort = mINI::Instance()[Rtsp::kSSLPort];
|
||||||
" 比如说应用为live,流id为0,那么直播地址为:\n"
|
rtspSSLSrv->start<RtspSessionWithSSL>(rtspsPort);
|
||||||
" hls地址 : http://127.0.0.1/live/0/hls.m3u8\n"
|
InfoL << "重启rtsps服务器" << rtspsPort;
|
||||||
" http-flv地址 : http://127.0.0.1/live/0.flv\n"
|
|
||||||
" rtsp地址 : rtsp://127.0.0.1/live/0\n"
|
|
||||||
" rtmp地址 : rtmp://127.0.0.1/live/0";
|
|
||||||
|
|
||||||
//请把证书"test_server.pem"放置在本程序可执行程序同目录下
|
|
||||||
try {
|
|
||||||
//加载证书,证书包含公钥和私钥
|
|
||||||
SSL_Initor::Instance().loadServerPem((exePath() + ".pem").data());
|
|
||||||
} catch (...) {
|
|
||||||
ErrorL << "请把证书:" << (exeName() + ".pem") << "放置在本程序可执行程序同目录下:" << exeDir() << endl;
|
|
||||||
proxyMap.clear();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
uint16_t shellPort = mINI::Instance()[Shell::kPort];
|
EventPollerPool::Instance().wait();
|
||||||
uint16_t rtspPort = mINI::Instance()[Rtsp::kPort];
|
|
||||||
uint16_t rtspsPort = mINI::Instance()[Rtsp::kSSLPort];
|
|
||||||
uint16_t rtmpPort = mINI::Instance()[Rtmp::kPort];
|
|
||||||
uint16_t httpPort = mINI::Instance()[Http::kPort];
|
|
||||||
uint16_t httpsPort = mINI::Instance()[Http::kSSLPort];
|
|
||||||
|
|
||||||
//简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象
|
|
||||||
//测试方法:telnet 127.0.0.1 9000
|
|
||||||
TcpServer::Ptr shellSrv(new TcpServer());
|
|
||||||
TcpServer::Ptr rtspSrv(new TcpServer());
|
|
||||||
TcpServer::Ptr rtmpSrv(new TcpServer());
|
|
||||||
TcpServer::Ptr httpSrv(new TcpServer());
|
|
||||||
|
|
||||||
shellSrv->start<ShellSession>(shellPort);
|
|
||||||
rtspSrv->start<RtspSession>(rtspPort);//默认554
|
|
||||||
rtmpSrv->start<RtmpSession>(rtmpPort);//默认1935
|
|
||||||
//http服务器,支持websocket
|
|
||||||
httpSrv->start<EchoWebSocketSession>(httpPort);//默认80
|
|
||||||
|
|
||||||
//如果支持ssl,还可以开启https服务器
|
|
||||||
TcpServer::Ptr httpsSrv(new TcpServer());
|
|
||||||
//https服务器,支持websocket
|
|
||||||
httpsSrv->start<SSLEchoWebSocketSession>(httpsPort);//默认443
|
|
||||||
|
|
||||||
//支持ssl加密的rtsp服务器,可用于诸如亚马逊echo show这样的设备访问
|
|
||||||
TcpServer::Ptr rtspSSLSrv(new TcpServer());
|
|
||||||
rtspSSLSrv->start<RtspSessionWithSSL>(rtspsPort);//默认322
|
|
||||||
|
|
||||||
//服务器支持动态切换端口(不影响现有连接)
|
|
||||||
NoticeCenter::Instance().addListener(ReloadConfigTag,Broadcast::kBroadcastReloadConfig,[&](BroadcastReloadConfigArgs){
|
|
||||||
//重新创建服务器
|
|
||||||
if(shellPort != mINI::Instance()[Shell::kPort].as<uint16_t>()){
|
|
||||||
shellPort = mINI::Instance()[Shell::kPort];
|
|
||||||
shellSrv->start<ShellSession>(shellPort);
|
|
||||||
InfoL << "重启shell服务器:" << shellPort;
|
|
||||||
}
|
|
||||||
if(rtspPort != mINI::Instance()[Rtsp::kPort].as<uint16_t>()){
|
|
||||||
rtspPort = mINI::Instance()[Rtsp::kPort];
|
|
||||||
rtspSrv->start<RtspSession>(rtspPort);
|
|
||||||
InfoL << "重启rtsp服务器" << rtspPort;
|
|
||||||
}
|
|
||||||
if(rtmpPort != mINI::Instance()[Rtmp::kPort].as<uint16_t>()){
|
|
||||||
rtmpPort = mINI::Instance()[Rtmp::kPort];
|
|
||||||
rtmpSrv->start<RtmpSession>(rtmpPort);
|
|
||||||
InfoL << "重启rtmp服务器" << rtmpPort;
|
|
||||||
}
|
|
||||||
if(httpPort != mINI::Instance()[Http::kPort].as<uint16_t>()){
|
|
||||||
httpPort = mINI::Instance()[Http::kPort];
|
|
||||||
httpSrv->start<EchoWebSocketSession>(httpPort);
|
|
||||||
InfoL << "重启http服务器" << httpPort;
|
|
||||||
}
|
|
||||||
if(httpsPort != mINI::Instance()[Http::kSSLPort].as<uint16_t>()){
|
|
||||||
httpsPort = mINI::Instance()[Http::kSSLPort];
|
|
||||||
httpsSrv->start<SSLEchoWebSocketSession>(httpsPort);
|
|
||||||
InfoL << "重启https服务器" << httpsPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rtspsPort != mINI::Instance()[Rtsp::kSSLPort].as<uint16_t>()){
|
|
||||||
rtspsPort = mINI::Instance()[Rtsp::kSSLPort];
|
|
||||||
rtspSSLSrv->start<RtspSessionWithSSL>(rtspsPort);
|
|
||||||
InfoL << "重启rtsps服务器" << rtspsPort;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
EventPoller::Instance().runLoop();
|
|
||||||
}//设置作用域,作用域结束后会销毁临时变量;省去手动注销服务器
|
|
||||||
|
|
||||||
|
|
||||||
//rtsp服务器用到udp端口分配器了
|
|
||||||
UDPServer::Destory();
|
|
||||||
//TcpServer用到了WorkThreadPool
|
|
||||||
WorkThreadPool::Destory();
|
|
||||||
EventPoller::Destory();
|
|
||||||
AsyncTaskThread::Destory();
|
|
||||||
Logger::Destory();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user