mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-03-21 13:30:53 +08:00
AI automatically translates all comments in the code into English (#3917)
This commit is contained in:
@@ -176,7 +176,8 @@ void DevChannelHK::onPreview(DWORD dwDataType, BYTE* pBuffer, DWORD dwBufSize) {
|
||||
break;
|
||||
}
|
||||
InfoL << "设置解码器成功!" << endl;
|
||||
//打开音频解码, 需要码流是复合流
|
||||
// 打开音频解码, 需要码流是复合流 [AUTO-TRANSLATED:ef6be0e4]
|
||||
// Open audio decoding, requires the bitstream to be a composite stream
|
||||
if (!PlayM4_PlaySoundShare(m_iPlayHandle)) {
|
||||
WarnL << "PlayM4_PlaySound:" << NET_DVR_GetLastError();
|
||||
break;
|
||||
|
||||
@@ -93,7 +93,8 @@ void process_file(const char *file,bool rm_bom){
|
||||
}
|
||||
|
||||
if (have_bom == !rm_bom) {
|
||||
// DebugL << "无需" << (rm_bom ? "删除" : "添加") << "bom:" << file;
|
||||
// DebugL << "无需" << (rm_bom ? "删除" : "添加") << "bom:" << file; [AUTO-TRANSLATED:6062a9ca]
|
||||
// DebugL << "No need to" << (rm_bom ? "remove" : "add") << "bom:" << file;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -102,7 +103,8 @@ void process_file(const char *file,bool rm_bom){
|
||||
InfoL << (rm_bom ? "删除" : "添加") << "bom:" << file;
|
||||
}
|
||||
|
||||
/// 这个程序是为了统一添加或删除utf-8 bom头
|
||||
// / 这个程序是为了统一添加或删除utf-8 bom头 [AUTO-TRANSLATED:945a36b6]
|
||||
// / This program is for unified adding or removing utf-8 bom header
|
||||
int main(int argc, char *argv[]) {
|
||||
CMD_main cmd_main;
|
||||
try {
|
||||
@@ -123,26 +125,31 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
bool no_filter = filter_set.find("*") != filter_set.end();
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||
File::scanDir(path, [&](const string &path, bool isDir) {
|
||||
if (isDir) {
|
||||
return true;
|
||||
}
|
||||
if (!no_filter) {
|
||||
//开启了过滤器
|
||||
// 开启了过滤器 [AUTO-TRANSLATED:331a77dd]
|
||||
// Filter enabled
|
||||
auto pos = strstr(path.data(), ".");
|
||||
if (pos == nullptr) {
|
||||
//没有后缀
|
||||
// 没有后缀 [AUTO-TRANSLATED:2273522f]
|
||||
// No suffix
|
||||
return true;
|
||||
}
|
||||
auto ext = pos + 1;
|
||||
if (filter_set.find(ext) == filter_set.end()) {
|
||||
//后缀不匹配
|
||||
// 后缀不匹配 [AUTO-TRANSLATED:7e30f0b4]
|
||||
// Suffix does not match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//该文件匹配
|
||||
// 该文件匹配 [AUTO-TRANSLATED:9dce5098]
|
||||
// File matches
|
||||
process_file(path.data(), rm_bom);
|
||||
return true;
|
||||
}, true);
|
||||
|
||||
@@ -107,7 +107,8 @@ void process_file(const char *file) {
|
||||
File::saveFile(str, file);
|
||||
}
|
||||
|
||||
/// 这个程序是为了统一替换tab为4个空格
|
||||
// / 这个程序是为了统一替换tab为4个空格 [AUTO-TRANSLATED:ecb3b523]
|
||||
// / This program is for unified replacement of tabs with 4 spaces
|
||||
int main(int argc, char *argv[]) {
|
||||
CMD_main cmd_main;
|
||||
try {
|
||||
@@ -127,26 +128,31 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
bool no_filter = filter_set.find("*") != filter_set.end();
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||
File::scanDir(path, [&](const string &path, bool isDir) {
|
||||
if (isDir) {
|
||||
return true;
|
||||
}
|
||||
if (!no_filter) {
|
||||
//开启了过滤器
|
||||
// 开启了过滤器 [AUTO-TRANSLATED:331a77dd]
|
||||
// Filter enabled
|
||||
auto pos = strstr(path.data(), ".");
|
||||
if (pos == nullptr) {
|
||||
//没有后缀
|
||||
// 没有后缀 [AUTO-TRANSLATED:2273522f]
|
||||
// No suffix
|
||||
return true;
|
||||
}
|
||||
auto ext = pos + 1;
|
||||
if (filter_set.find(ext) == filter_set.end()) {
|
||||
//后缀不匹配
|
||||
// 后缀不匹配 [AUTO-TRANSLATED:7e30f0b4]
|
||||
// Suffix does not match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//该文件匹配
|
||||
// 该文件匹配 [AUTO-TRANSLATED:9dce5098]
|
||||
// File matches
|
||||
process_file(path.data());
|
||||
return true;
|
||||
}, true);
|
||||
|
||||
@@ -99,7 +99,8 @@ public:
|
||||
};
|
||||
|
||||
|
||||
//此程序为zlm的转推性能测试工具,用于测试拉流代理转推性能
|
||||
// 此程序为zlm的转推性能测试工具,用于测试拉流代理转推性能 [AUTO-TRANSLATED:3d384f4f]
|
||||
// This program is a performance testing tool for zlm's relay push, used to test the relay push performance of the pull stream agent
|
||||
int main(int argc, char *argv[]) {
|
||||
CMD_main cmd_main;
|
||||
try {
|
||||
@@ -120,16 +121,20 @@ int main(int argc, char *argv[]) {
|
||||
auto delay_ms = cmd_main["delay"].as<int>();
|
||||
auto merge_ms = cmd_main["merge"].as<int>();
|
||||
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:b1bbb978]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel", logLevel));
|
||||
//启动异步日志线程
|
||||
// 启动异步日志线程 [AUTO-TRANSLATED:a3514cc7]
|
||||
// Start asynchronous log thread
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
//设置线程数
|
||||
// 设置线程数 [AUTO-TRANSLATED:cce432ca]
|
||||
// Set the number of threads
|
||||
EventPollerPool::setPoolSize(threads);
|
||||
WorkThreadPool::setPoolSize(threads);
|
||||
|
||||
//设置合并写
|
||||
// 设置合并写 [AUTO-TRANSLATED:e3aaf4f8]
|
||||
// Set merge write
|
||||
mINI::Instance()[General::kMergeWriteMS] = merge_ms;
|
||||
|
||||
|
||||
@@ -137,7 +142,8 @@ int main(int argc, char *argv[]) {
|
||||
std::vector<std::string> output_urls;
|
||||
|
||||
auto parse_urls = [&]() {
|
||||
// 获取输入源列表
|
||||
// 获取输入源列表 [AUTO-TRANSLATED:ff8fdf28]
|
||||
// Get input source list
|
||||
auto inputs = ::split(toolkit::File::loadFile(in_urls), "\n");
|
||||
for(auto &url : inputs){
|
||||
if(url.empty() || url.find("://") == std::string::npos) {
|
||||
@@ -146,7 +152,8 @@ int main(int argc, char *argv[]) {
|
||||
auto input_url = ::trim(url);
|
||||
input_urls.emplace_back(input_url);
|
||||
}
|
||||
// 获取输出源列表
|
||||
// 获取输出源列表 [AUTO-TRANSLATED:267eba3a]
|
||||
// Get output source list
|
||||
auto outputs = ::split(toolkit::File::loadFile(out_urls), "\n");
|
||||
for(auto &url : outputs){
|
||||
if(url.empty() || url.find("://") == std::string::npos){
|
||||
@@ -171,7 +178,8 @@ int main(int argc, char *argv[]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//推流器map
|
||||
// 推流器map [AUTO-TRANSLATED:d6af6562]
|
||||
// Pusher map
|
||||
recursive_mutex mtx;
|
||||
unordered_map<int, PlayerProxy::Ptr> proxy_map;
|
||||
unordered_map<int, MediaPusher::Ptr> pusher_map;
|
||||
@@ -179,38 +187,48 @@ int main(int argc, char *argv[]) {
|
||||
auto add_pusher = [&](const MediaSource::Ptr &src, const string &url, int index) {
|
||||
auto pusher = std::make_shared<MediaPusher>(src);
|
||||
pusher->setOnCreateSocket([](const EventPoller::Ptr &poller) {
|
||||
//socket关闭互斥锁,提高性能
|
||||
// socket关闭互斥锁,提高性能 [AUTO-TRANSLATED:d734e718]
|
||||
// Socket close mutex, improve performance
|
||||
return Socket::createSocket(poller, false);
|
||||
});
|
||||
//设置推流失败监听
|
||||
// 设置推流失败监听 [AUTO-TRANSLATED:8e799d62]
|
||||
// Set push failure listener
|
||||
pusher->setOnPublished([&mtx, &pusher_map, index](const SockException &ex) {
|
||||
if (ex) {
|
||||
//推流失败,移除之
|
||||
// 推流失败,移除之 [AUTO-TRANSLATED:92440807]
|
||||
// Push failure, remove it
|
||||
lock_guard<recursive_mutex> lck(mtx);
|
||||
pusher_map.erase(index);
|
||||
}
|
||||
});
|
||||
//设置推流中途断开监听
|
||||
// 设置推流中途断开监听 [AUTO-TRANSLATED:b1cc165d]
|
||||
// Set push midway disconnection listener
|
||||
pusher->setOnShutdown([&mtx, &pusher_map, index](const SockException &ex) {
|
||||
//推流中途失败,移除之
|
||||
// 推流中途失败,移除之 [AUTO-TRANSLATED:9d79c581]
|
||||
// Push midway failure, remove it
|
||||
lock_guard<recursive_mutex> lck(mtx);
|
||||
pusher_map.erase(index);
|
||||
});
|
||||
//设置rtsp推流方式(在rtsp推流时有效)
|
||||
// 设置rtsp推流方式(在rtsp推流时有效) [AUTO-TRANSLATED:92584646]
|
||||
// Set RTSP push mode (effective when pushing RTSP)
|
||||
(*pusher)[Client::kRtpType] = rtp_type;
|
||||
pusher->publish(url);
|
||||
//保持对象不销毁
|
||||
// 保持对象不销毁 [AUTO-TRANSLATED:43ddb698]
|
||||
// Keep the object from being destroyed
|
||||
lock_guard<recursive_mutex> lck(mtx);
|
||||
pusher_map.emplace(index, std::move(pusher));
|
||||
//休眠后再启动下一个推流,防止短时间海量链接
|
||||
// 休眠后再启动下一个推流,防止短时间海量链接 [AUTO-TRANSLATED:2f17b482]
|
||||
// Sleep and then start the next push to prevent massive connections in a short time
|
||||
if (delay_ms > 0) {
|
||||
usleep(1000 * delay_ms);
|
||||
}
|
||||
};
|
||||
|
||||
// 添加转推任务
|
||||
// 添加转推任务 [AUTO-TRANSLATED:122a8389]
|
||||
// Add relay task
|
||||
for(size_t i = 0; i < input_urls.size(); i++) {
|
||||
//休眠一秒打印
|
||||
// 休眠一秒打印 [AUTO-TRANSLATED:338a3b2c]
|
||||
// Sleep for one second and print
|
||||
sleep(1);
|
||||
auto schema = findSubString(output_urls[i].data(), nullptr, "://");
|
||||
if (schema != RTSP_SCHEMA && schema != RTMP_SCHEMA) {
|
||||
@@ -223,19 +241,23 @@ int main(int argc, char *argv[]) {
|
||||
option.enable_hls = false;
|
||||
option.enable_mp4 = false;
|
||||
option.modify_stamp = (int)ProtocolOption::kModifyStampRelative;
|
||||
//添加拉流代理
|
||||
// 添加拉流代理 [AUTO-TRANSLATED:aa516f44]
|
||||
// Add pull stream agent
|
||||
auto tuple = MediaTuple { DEFAULT_VHOST, "app", std::to_string(i), "" };
|
||||
auto proxy = std::make_shared<PlayerProxy>(tuple, option, -1, nullptr, 1);
|
||||
//开始拉流代理
|
||||
// 开始拉流代理 [AUTO-TRANSLATED:c9fe3c34]
|
||||
// Start pull stream agent
|
||||
proxy->play(input_urls[i]);
|
||||
proxy_map.emplace(i, std::move(proxy));
|
||||
}
|
||||
|
||||
// 设置退出信号
|
||||
// 设置退出信号 [AUTO-TRANSLATED:4f618479]
|
||||
// Set exit signal
|
||||
static bool exit_flag = false;
|
||||
signal(SIGINT, [](int) { exit_flag = true; });
|
||||
while (!exit_flag) {
|
||||
//休眠一秒打印
|
||||
// 休眠一秒打印 [AUTO-TRANSLATED:338a3b2c]
|
||||
// Sleep for one second and print
|
||||
sleep(1);
|
||||
|
||||
size_t alive_pusher = 0;
|
||||
|
||||
@@ -91,7 +91,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//此程序为zlm的拉流代理性能测试工具,用于测试拉流代理性能
|
||||
// 此程序为zlm的拉流代理性能测试工具,用于测试拉流代理性能 [AUTO-TRANSLATED:365ee033]
|
||||
// This program is a pull stream proxy performance test tool for zlm, used to test the pull stream proxy performance
|
||||
int main(int argc, char *argv[]) {
|
||||
{
|
||||
CMD_main cmd_main;
|
||||
@@ -114,16 +115,20 @@ int main(int argc, char *argv[]) {
|
||||
auto merge_ms = cmd_main["merge"].as<int>();
|
||||
auto demand = cmd_main["demand"].as<int>();
|
||||
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel", logLevel));
|
||||
//启动异步日志线程
|
||||
// 启动异步日志线程 [AUTO-TRANSLATED:c93cc6f4]
|
||||
// Start asynchronous log thread
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
//设置线程数
|
||||
// 设置线程数 [AUTO-TRANSLATED:22ec5cc9]
|
||||
// Set the number of threads
|
||||
EventPollerPool::setPoolSize(threads);
|
||||
WorkThreadPool::setPoolSize(threads);
|
||||
|
||||
//设置合并写
|
||||
// 设置合并写 [AUTO-TRANSLATED:7bf3456d]
|
||||
// Set merge write
|
||||
mINI::Instance()[General::kMergeWriteMS] = merge_ms;
|
||||
mINI::Instance()[Protocol::kRtspDemand] = demand;
|
||||
mINI::Instance()[Protocol::kRtmpDemand] = demand;
|
||||
@@ -142,7 +147,8 @@ int main(int argc, char *argv[]) {
|
||||
(*player)[Client::kRtpType] = rtp_type;
|
||||
player->play(in_url);
|
||||
proxyMap.emplace(stream, player);
|
||||
//休眠后再启动下一个拉流代理,防止短时间海量链接
|
||||
// 休眠后再启动下一个拉流代理,防止短时间海量链接 [AUTO-TRANSLATED:20fc6ab9]
|
||||
// Sleep before starting the next pull stream proxy to prevent a large number of connections in a short time
|
||||
if (delay_ms > 0) {
|
||||
usleep(1000 * delay_ms);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//此程序用于拉流播放性能测试
|
||||
// 此程序用于拉流播放性能测试 [AUTO-TRANSLATED:727e8fdb]
|
||||
// This program is used for pulling stream playback performance testing
|
||||
int main(int argc, char *argv[]) {
|
||||
CMD_main cmd_main;
|
||||
try {
|
||||
@@ -105,16 +106,20 @@ int main(int argc, char *argv[]) {
|
||||
auto delay_ms = cmd_main["delay"].as<int>();
|
||||
auto player_count = cmd_main["count"].as<int>();
|
||||
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel", logLevel));
|
||||
//启动异步日志线程
|
||||
// 启动异步日志线程 [AUTO-TRANSLATED:c93cc6f4]
|
||||
// Start asynchronous log thread
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
//设置线程数
|
||||
// 设置线程数 [AUTO-TRANSLATED:22ec5cc9]
|
||||
// Set the number of threads
|
||||
EventPollerPool::setPoolSize(threads);
|
||||
WorkThreadPool::setPoolSize(threads);
|
||||
|
||||
//播放器map
|
||||
// 播放器map [AUTO-TRANSLATED:53b5b4c4]
|
||||
// Player map
|
||||
recursive_mutex mtx;
|
||||
unordered_map<void *, MediaPlayer::Ptr> player_map;
|
||||
|
||||
@@ -122,52 +127,66 @@ int main(int argc, char *argv[]) {
|
||||
auto player = std::make_shared<MediaPlayer>();
|
||||
auto tag = player.get();
|
||||
player->setOnCreateSocket([](const EventPoller::Ptr &poller) {
|
||||
//socket关闭互斥锁,提高性能
|
||||
// socket关闭互斥锁,提高性能 [AUTO-TRANSLATED:471fc644]
|
||||
// Socket close mutex, improve performance
|
||||
return Socket::createSocket(poller, false);
|
||||
});
|
||||
//设置播放失败监听
|
||||
// 设置播放失败监听 [AUTO-TRANSLATED:14e18272]
|
||||
// Set playback failure listener
|
||||
player->setOnPlayResult([&mtx, &player_map, tag](const SockException &ex) {
|
||||
if (ex) {
|
||||
//播放失败,移除之
|
||||
// 播放失败,移除之 [AUTO-TRANSLATED:e3e1ce5e]
|
||||
// Playback failed, remove it
|
||||
lock_guard<recursive_mutex> lck(mtx);
|
||||
player_map.erase(tag);
|
||||
}
|
||||
});
|
||||
//设置播放中途断开监听
|
||||
// 设置播放中途断开监听 [AUTO-TRANSLATED:b1aa9531]
|
||||
// Set playback interruption listener
|
||||
player->setOnShutdown([&mtx, &player_map, tag](const SockException &ex) {
|
||||
//播放中途失败,移除之
|
||||
// 播放中途失败,移除之 [AUTO-TRANSLATED:5cd7df25]
|
||||
// Playback interrupted, remove it
|
||||
lock_guard<recursive_mutex> lck(mtx);
|
||||
player_map.erase(tag);
|
||||
});
|
||||
//设置为性能测试模式
|
||||
// 设置为性能测试模式 [AUTO-TRANSLATED:96c16cc1]
|
||||
// Set to performance test mode
|
||||
(*player)[Client::kBenchmarkMode] = true;
|
||||
//设置rtsp拉流方式(在rtsp拉流时有效)
|
||||
// 设置rtsp拉流方式(在rtsp拉流时有效) [AUTO-TRANSLATED:521f7bbd]
|
||||
// Set RTSP pull mode (effective when pulling RTSP stream)
|
||||
(*player)[Client::kRtpType] = rtp_type;
|
||||
//提高压测性能与正确性
|
||||
// 提高压测性能与正确性 [AUTO-TRANSLATED:947f0ef8]
|
||||
// Improve stress test performance and accuracy
|
||||
(*player)[Client::kWaitTrackReady] = false;
|
||||
//发起播放请求
|
||||
// 发起播放请求 [AUTO-TRANSLATED:43e28453]
|
||||
// Initiate playback request
|
||||
player->play(in_url);
|
||||
|
||||
//保持对象不销毁
|
||||
// 保持对象不销毁 [AUTO-TRANSLATED:650977d0]
|
||||
// Keep the object from being destroyed
|
||||
lock_guard<recursive_mutex> lck(mtx);
|
||||
player_map.emplace(tag, std::move(player));
|
||||
|
||||
//休眠后再启动下一个播放,防止短时间海量链接
|
||||
// 休眠后再启动下一个播放,防止短时间海量链接 [AUTO-TRANSLATED:96c03767]
|
||||
// Sleep and then start the next playback to prevent massive connections in a short time
|
||||
if (delay_ms > 0) {
|
||||
usleep(1000 * delay_ms);
|
||||
}
|
||||
};
|
||||
|
||||
//添加这么多播放器
|
||||
// 添加这么多播放器 [AUTO-TRANSLATED:b93d3a9f]
|
||||
// Add so many players
|
||||
for (auto i = 0; i < player_count; ++i) {
|
||||
add_player();
|
||||
}
|
||||
|
||||
// 设置退出信号
|
||||
// 设置退出信号 [AUTO-TRANSLATED:02c7fa30]
|
||||
// Set exit signal
|
||||
static bool exit_flag = false;
|
||||
signal(SIGINT, [](int) { exit_flag = true; });
|
||||
while (!exit_flag) {
|
||||
//休眠一秒打印
|
||||
// 休眠一秒打印 [AUTO-TRANSLATED:239dc996]
|
||||
// Sleep for one second and print
|
||||
sleep(1);
|
||||
|
||||
size_t alive_player = 0;
|
||||
@@ -178,7 +197,8 @@ int main(int argc, char *argv[]) {
|
||||
InfoL << "在线播放器个数:" << alive_player;
|
||||
size_t re_try = player_count - alive_player;
|
||||
while (!exit_flag && re_try--) {
|
||||
//有些播放器播放失败了,那么我们重试添加
|
||||
// 有些播放器播放失败了,那么我们重试添加 [AUTO-TRANSLATED:adcec1af]
|
||||
// Some players failed to play, so we retry adding them
|
||||
add_player();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,8 @@ public:
|
||||
const char *description() const override { return "主程序命令参数"; }
|
||||
};
|
||||
|
||||
// 此程序用于推流性能测试
|
||||
// 此程序用于推流性能测试 [AUTO-TRANSLATED:45b48457]
|
||||
// This program is used for streaming performance testing
|
||||
int main(int argc, char *argv[]) {
|
||||
CMD_main cmd_main;
|
||||
try {
|
||||
@@ -130,16 +131,20 @@ int main(int argc, char *argv[]) {
|
||||
const std::string app = "app";
|
||||
const std::string stream = "test";
|
||||
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel", logLevel));
|
||||
//启动异步日志线程
|
||||
// 启动异步日志线程 [AUTO-TRANSLATED:c93cc6f4]
|
||||
// Start asynchronous log thread
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
//设置线程数
|
||||
// 设置线程数 [AUTO-TRANSLATED:22ec5cc9]
|
||||
// Set the number of threads
|
||||
EventPollerPool::setPoolSize(threads);
|
||||
WorkThreadPool::setPoolSize(threads);
|
||||
|
||||
//设置合并写
|
||||
// 设置合并写 [AUTO-TRANSLATED:7bf3456d]
|
||||
// Set merge write
|
||||
mINI::Instance()[General::kMergeWriteMS] = merge_ms;
|
||||
|
||||
ProtocolOption option;
|
||||
@@ -156,16 +161,20 @@ int main(int argc, char *argv[]) {
|
||||
reader->startReadMP4(0, true, true);
|
||||
src = MediaSource::find(schema, DEFAULT_VHOST, app, stream, false);
|
||||
if (!src) {
|
||||
// mp4文件不存在
|
||||
// mp4文件不存在 [AUTO-TRANSLATED:80188fb8]
|
||||
// mp4 file does not exist
|
||||
WarnL << "no such file or directory: " << in_url;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
//添加拉流代理
|
||||
// 添加拉流代理 [AUTO-TRANSLATED:aa516f44]
|
||||
// Add pull stream proxy
|
||||
proxy = std::make_shared<PlayerProxy>(tuple, option);
|
||||
//rtsp拉流代理方式
|
||||
// rtsp拉流代理方式 [AUTO-TRANSLATED:065d328d]
|
||||
// rtsp pull stream proxy method
|
||||
(*proxy)[Client::kRtpType] = rtp_type;
|
||||
//开始拉流代理
|
||||
// 开始拉流代理 [AUTO-TRANSLATED:6937338d]
|
||||
// Start pull stream proxy
|
||||
proxy->play(in_url);
|
||||
|
||||
}
|
||||
@@ -174,7 +183,8 @@ int main(int argc, char *argv[]) {
|
||||
return MediaSource::find(schema, DEFAULT_VHOST, app, stream, false);
|
||||
};
|
||||
|
||||
//推流器map
|
||||
// 推流器map [AUTO-TRANSLATED:279fcfb0]
|
||||
// Streamer map
|
||||
recursive_mutex mtx;
|
||||
unordered_map<void *, MediaPusher::Ptr> pusher_map;
|
||||
|
||||
@@ -183,44 +193,55 @@ int main(int argc, char *argv[]) {
|
||||
auto pusher = std::make_shared<MediaPusher>(src);
|
||||
auto tag = pusher.get();
|
||||
pusher->setOnCreateSocket([](const EventPoller::Ptr &poller) {
|
||||
//socket关闭互斥锁,提高性能
|
||||
// socket关闭互斥锁,提高性能 [AUTO-TRANSLATED:471fc644]
|
||||
// Socket close mutex, improve performance
|
||||
return Socket::createSocket(poller, false);
|
||||
});
|
||||
//设置推流失败监听
|
||||
// 设置推流失败监听 [AUTO-TRANSLATED:4ad49de9]
|
||||
// Set push stream failure listener
|
||||
pusher->setOnPublished([&mtx, &pusher_map, tag](const SockException &ex) {
|
||||
if (ex) {
|
||||
//推流失败,移除之
|
||||
// 推流失败,移除之 [AUTO-TRANSLATED:97a29246]
|
||||
// Push stream failed, remove it
|
||||
lock_guard<recursive_mutex> lck(mtx);
|
||||
pusher_map.erase(tag);
|
||||
}
|
||||
});
|
||||
//设置推流中途断开监听
|
||||
// 设置推流中途断开监听 [AUTO-TRANSLATED:228076ef]
|
||||
// Set push stream disconnection listener
|
||||
pusher->setOnShutdown([&mtx, &pusher_map, tag](const SockException &ex) {
|
||||
//推流中途失败,移除之
|
||||
// 推流中途失败,移除之 [AUTO-TRANSLATED:00e0928a]
|
||||
// Push stream failed halfway, remove it
|
||||
lock_guard<recursive_mutex> lck(mtx);
|
||||
pusher_map.erase(tag);
|
||||
});
|
||||
//设置rtsp推流方式(在rtsp推流时有效)
|
||||
// 设置rtsp推流方式(在rtsp推流时有效) [AUTO-TRANSLATED:2dc733df]
|
||||
// Set rtsp push stream method (effective when rtsp push stream)
|
||||
(*pusher)[Client::kRtpType] = rtp_type;
|
||||
//发起推流请求,每个推流端的stream_id都不一样
|
||||
// 发起推流请求,每个推流端的stream_id都不一样 [AUTO-TRANSLATED:8b356fcb]
|
||||
// Initiate push stream request, each push stream end has a different stream_id
|
||||
string url = StrPrinter << out_url << "_" << rand_str << "_" << index;
|
||||
pusher->publish(url);
|
||||
|
||||
//保持对象不销毁
|
||||
// 保持对象不销毁 [AUTO-TRANSLATED:650977d0]
|
||||
// Keep the object from being destroyed
|
||||
lock_guard<recursive_mutex> lck(mtx);
|
||||
pusher_map.emplace(tag, std::move(pusher));
|
||||
|
||||
//休眠后再启动下一个推流,防止短时间海量链接
|
||||
// 休眠后再启动下一个推流,防止短时间海量链接 [AUTO-TRANSLATED:df224fc9]
|
||||
// Sleep and then start the next push stream to prevent massive connections in a short time
|
||||
if (delay_ms > 0) {
|
||||
usleep(1000 * delay_ms);
|
||||
}
|
||||
};
|
||||
|
||||
// 设置退出信号
|
||||
// 设置退出信号 [AUTO-TRANSLATED:02c7fa30]
|
||||
// Set exit signal
|
||||
static bool exit_flag = false;
|
||||
signal(SIGINT, [](int) { exit_flag = true; });
|
||||
while (!exit_flag) {
|
||||
//休眠一秒打印
|
||||
// 休眠一秒打印 [AUTO-TRANSLATED:239dc996]
|
||||
// Sleep for one second and print
|
||||
sleep(1);
|
||||
|
||||
size_t alive_pusher = 0;
|
||||
@@ -231,7 +252,8 @@ int main(int argc, char *argv[]) {
|
||||
InfoL << "在线推流器个数:" << alive_pusher;
|
||||
auto src = get_src();
|
||||
for(size_t i = 0; i < pusher_count - alive_pusher && src && !exit_flag; ++i){
|
||||
//有些推流器失败了,那么我们重试添加
|
||||
// 有些推流器失败了,那么我们重试添加 [AUTO-TRANSLATED:d01fb300]
|
||||
// Some push streamers failed, so we retry adding
|
||||
add_pusher(get_src(), makeRandStr(8), i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,9 +90,11 @@ static bool loadFile(const char *path){
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel"));
|
||||
//启动异步日志线程
|
||||
// 启动异步日志线程 [AUTO-TRANSLATED:c93cc6f4]
|
||||
// Start asynchronous log thread
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
loadIniConfig((exeDir() + "config.ini").data());
|
||||
TcpServer::Ptr rtspSrv(new TcpServer());
|
||||
|
||||
@@ -25,7 +25,8 @@ using namespace toolkit;
|
||||
using namespace mediakit;
|
||||
|
||||
namespace mediakit {
|
||||
////////////HTTP配置///////////
|
||||
// //////////HTTP配置/////////// [AUTO-TRANSLATED:a281d694]
|
||||
// //////////HTTP Configuration///////////
|
||||
namespace Http {
|
||||
#define HTTP_FIELD "http."
|
||||
#define HTTP_PORT 80
|
||||
@@ -46,7 +47,8 @@ void initEventListener(){
|
||||
if(strstr(parser.url().data(),"/api/") != parser.url().data()){
|
||||
return;
|
||||
}
|
||||
//url以"/api/起始,说明是http api"
|
||||
// url以"/api/起始,说明是http api" [AUTO-TRANSLATED:8af96c7e]
|
||||
// URLs starting with "/api/" indicate HTTP API
|
||||
consumed = true;//该http请求已被消费
|
||||
|
||||
_StrPrinter printer;
|
||||
@@ -70,13 +72,18 @@ void initEventListener(){
|
||||
printer << "\r\ncontent:\r\n" << parser.content();
|
||||
auto contentOut = printer << endl;
|
||||
|
||||
////////////////我们测算异步回复,当然你也可以同步回复/////////////////
|
||||
// //////////////我们测算异步回复,当然你也可以同步回复///////////////// [AUTO-TRANSLATED:5c112e50]
|
||||
// //////////////We measure asynchronous responses, but you can also respond synchronously/////////////////
|
||||
EventPollerPool::Instance().getPoller()->async([invoker,contentOut](){
|
||||
HttpSession::KeyValue headerOut;
|
||||
//你可以自定义header,如果跟默认header重名,则会覆盖之
|
||||
//默认header有:Server,Connection,Date,Content-Type,Content-Length
|
||||
//请勿覆盖Connection、Content-Length键
|
||||
//键名覆盖时不区分大小写
|
||||
// 你可以自定义header,如果跟默认header重名,则会覆盖之 [AUTO-TRANSLATED:07b1ecfe]
|
||||
// You can customize the header; if it has the same name as the default header, it will override it
|
||||
// 默认header有:Server,Connection,Date,Content-Type,Content-Length [AUTO-TRANSLATED:ca0c35d2]
|
||||
// Default headers include: Server, Connection, Date, Content-Type, Content-Length
|
||||
// 请勿覆盖Connection、Content-Length键 [AUTO-TRANSLATED:ef188768]
|
||||
// Please do not override the Connection and Content-Length keys
|
||||
// 键名覆盖时不区分大小写 [AUTO-TRANSLATED:32147753]
|
||||
// Key name overrides are case-insensitive
|
||||
headerOut["TestHeader"] = "HeaderValue";
|
||||
invoker(200,headerOut,contentOut);
|
||||
});
|
||||
@@ -85,31 +92,39 @@ void initEventListener(){
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[]){
|
||||
//设置退出信号处理函数
|
||||
// 设置退出信号处理函数 [AUTO-TRANSLATED:4f047770]
|
||||
// Set the exit signal processing function
|
||||
static semaphore sem;
|
||||
signal(SIGINT, [](int) { sem.post(); });// 设置退出信号
|
||||
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set the log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
//加载配置文件,如果配置文件不存在就创建一个
|
||||
// 加载配置文件,如果配置文件不存在就创建一个 [AUTO-TRANSLATED:761e7479]
|
||||
// Load the configuration file; if it does not exist, create one
|
||||
loadIniConfig();
|
||||
initEventListener();
|
||||
|
||||
//加载证书,证书包含公钥和私钥
|
||||
// 加载证书,证书包含公钥和私钥 [AUTO-TRANSLATED:fce78641]
|
||||
// Load the certificate, which includes the public and private keys
|
||||
SSL_Initor::Instance().loadCertificate((exeDir() + "ssl.p12").data());
|
||||
//信任某个自签名证书
|
||||
// 信任某个自签名证书 [AUTO-TRANSLATED:6815fc55]
|
||||
// Trust a self-signed certificate
|
||||
SSL_Initor::Instance().trustCertificate((exeDir() + "ssl.p12").data());
|
||||
//不忽略无效证书证书(例如自签名或过期证书)
|
||||
// 不忽略无效证书证书(例如自签名或过期证书) [AUTO-TRANSLATED:ee4a34c4]
|
||||
// Do not ignore invalid certificates (e.g., self-signed or expired certificates)
|
||||
SSL_Initor::Instance().ignoreInvalidCertificate(false);
|
||||
|
||||
|
||||
//开启http服务器
|
||||
// 开启http服务器 [AUTO-TRANSLATED:ffab30d4]
|
||||
// Start the HTTP server
|
||||
TcpServer::Ptr httpSrv(new TcpServer());
|
||||
httpSrv->start<HttpSession>(mINI::Instance()[Http::kPort]);//默认80
|
||||
|
||||
//如果支持ssl,还可以开启https服务器
|
||||
// 如果支持ssl,还可以开启https服务器 [AUTO-TRANSLATED:8ef29f9c]
|
||||
// If SSL is supported, you can also start the HTTPS server
|
||||
TcpServer::Ptr httpsSrv(new TcpServer());
|
||||
httpsSrv->start<HttpsSession>(mINI::Instance()[Http::kSSLPort]);//默认443
|
||||
|
||||
|
||||
@@ -23,65 +23,84 @@ using namespace toolkit;
|
||||
using namespace mediakit;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
//设置退出信号处理函数
|
||||
// 设置退出信号处理函数 [AUTO-TRANSLATED:4f047770]
|
||||
// Set the exit signal processing function
|
||||
static semaphore sem;
|
||||
signal(SIGINT, [](int) { sem.post(); });// 设置退出信号
|
||||
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set the log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
//加载证书,证书包含公钥和私钥
|
||||
// 加载证书,证书包含公钥和私钥 [AUTO-TRANSLATED:fce78641]
|
||||
// Load the certificate, the certificate contains the public key and private key
|
||||
SSL_Initor::Instance().loadCertificate((exeDir() + "ssl.p12").data());
|
||||
//信任某个自签名证书
|
||||
// 信任某个自签名证书 [AUTO-TRANSLATED:6815fc55]
|
||||
// Trust a self-signed certificate
|
||||
SSL_Initor::Instance().trustCertificate((exeDir() + "ssl.p12").data());
|
||||
//不忽略无效证书证书(例如自签名或过期证书)
|
||||
// 不忽略无效证书证书(例如自签名或过期证书) [AUTO-TRANSLATED:ee4a34c4]
|
||||
// Do not ignore invalid certificates (such as self-signed or expired certificates)
|
||||
SSL_Initor::Instance().ignoreInvalidCertificate(false);
|
||||
|
||||
///////////////////////////////http downloader///////////////////////
|
||||
//下载器map
|
||||
// 下载器map [AUTO-TRANSLATED:d8583648]
|
||||
// Downloader map
|
||||
map<string, HttpDownloader::Ptr> downloaderMap;
|
||||
//下载两个文件,一个是http下载,一个https下载
|
||||
// 下载两个文件,一个是http下载,一个https下载 [AUTO-TRANSLATED:d6108dc2]
|
||||
// Download two files, one is HTTP download, and the other is HTTPS download
|
||||
auto urlList = {"http://www.baidu.com/img/baidu_resultlogo@2.png",
|
||||
"https://www.baidu.com/img/baidu_resultlogo@2.png"};
|
||||
|
||||
for (auto &url : urlList) {
|
||||
//创建下载器
|
||||
// 创建下载器 [AUTO-TRANSLATED:e67aa738]
|
||||
// Create a downloader
|
||||
HttpDownloader::Ptr downloader(new HttpDownloader());
|
||||
downloader->setOnResult([](const SockException &ex, const string &filePath) {
|
||||
DebugL << "=====================HttpDownloader result=======================";
|
||||
//下载结果回调
|
||||
// 下载结果回调 [AUTO-TRANSLATED:a7f68894]
|
||||
// Download result callback
|
||||
if (!ex) {
|
||||
//文件下载成功
|
||||
// 文件下载成功 [AUTO-TRANSLATED:d753c6d3]
|
||||
// File download successful
|
||||
InfoL << "download file success:" << filePath;
|
||||
} else {
|
||||
//下载失败
|
||||
// 下载失败 [AUTO-TRANSLATED:b5ee74cc]
|
||||
// Download failed
|
||||
WarnL << "code:" << ex.getErrCode() << " msg:" << ex.what();
|
||||
}
|
||||
});
|
||||
//断点续传功能,开启后可能会遇到416的错误(因为上次文件已经下载完全)
|
||||
// 断点续传功能,开启后可能会遇到416的错误(因为上次文件已经下载完全) [AUTO-TRANSLATED:d4feaecb]
|
||||
// Resume function, enabling it may encounter a 416 error (because the file was downloaded completely last time)
|
||||
downloader->startDownload(url, exeDir() + MD5(url).hexdigest() + ".jpg", true);
|
||||
//下载器必须被强引用,否则作用域一失效就会导致对象销毁
|
||||
// 下载器必须被强引用,否则作用域一失效就会导致对象销毁 [AUTO-TRANSLATED:16e93227]
|
||||
// The downloader must be strongly referenced, otherwise, it will be destroyed when the scope is invalid
|
||||
downloaderMap.emplace(url, downloader);
|
||||
}
|
||||
|
||||
///////////////////////////////http get///////////////////////
|
||||
//创建一个Http请求器
|
||||
// 创建一个Http请求器 [AUTO-TRANSLATED:0d451bc1]
|
||||
// Create an HTTP requestor
|
||||
HttpRequester::Ptr requesterGet(new HttpRequester());
|
||||
//使用GET方式请求
|
||||
// 使用GET方式请求 [AUTO-TRANSLATED:3f701c92]
|
||||
// Use the GET method to request
|
||||
requesterGet->setMethod("GET");
|
||||
//设置http请求头,我们假设设置cookie,当然你也可以设置其他http头
|
||||
// 设置http请求头,我们假设设置cookie,当然你也可以设置其他http头 [AUTO-TRANSLATED:233d2c3f]
|
||||
// Set the HTTP request header, we assume setting the cookie, of course, you can also set other HTTP headers
|
||||
requesterGet->addHeader("Cookie", "SESSIONID=e1aa89b3-f79f-4ac6-8ae2-0cea9ae8e2d7");
|
||||
//开启请求,该api会返回当前主机外网ip等信息
|
||||
// 开启请求,该api会返回当前主机外网ip等信息 [AUTO-TRANSLATED:efebf262]
|
||||
// Start the request, this API will return the current host's external network IP and other information
|
||||
requesterGet->startRequester("http://pv.sohu.com/cityjson?ie=utf-8",//url地址
|
||||
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
|
||||
const Parser &parser) { //http回复body
|
||||
DebugL << "=====================HttpRequester GET===========================";
|
||||
if (ex) {
|
||||
//网络相关的错误
|
||||
// 网络相关的错误 [AUTO-TRANSLATED:ae96dbe9]
|
||||
// Network-related errors
|
||||
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
|
||||
} else {
|
||||
//打印http回复信息
|
||||
// 打印http回复信息 [AUTO-TRANSLATED:d4611ce2]
|
||||
// Print HTTP response information
|
||||
_StrPrinter printer;
|
||||
for (auto &pr: parser.getHeader()) {
|
||||
printer << pr.first << ":" << pr.second << "\r\n";
|
||||
@@ -93,14 +112,18 @@ int main(int argc, char *argv[]) {
|
||||
});
|
||||
|
||||
///////////////////////////////http post///////////////////////
|
||||
//创建一个Http请求器
|
||||
// 创建一个Http请求器 [AUTO-TRANSLATED:0d451bc1]
|
||||
// Create an HTTP requestor
|
||||
HttpRequester::Ptr requesterPost(new HttpRequester());
|
||||
//使用POST方式请求
|
||||
// 使用POST方式请求 [AUTO-TRANSLATED:dc6266f1]
|
||||
// Use the POST method to request
|
||||
requesterPost->setMethod("POST");
|
||||
//设置http请求头
|
||||
// 设置http请求头 [AUTO-TRANSLATED:d934a806]
|
||||
// Set the HTTP request header
|
||||
requesterPost->addHeader("X-Requested-With", "XMLHttpRequest");
|
||||
requesterPost->addHeader("Origin", "http://fanyi.baidu.com");
|
||||
//设置POST参数列表
|
||||
// 设置POST参数列表 [AUTO-TRANSLATED:5378230d]
|
||||
// Set the POST parameter list
|
||||
HttpArgs args;
|
||||
args["query"] = "test";
|
||||
args["from"] = "en";
|
||||
@@ -108,16 +131,19 @@ int main(int argc, char *argv[]) {
|
||||
args["transtype"] = "translang";
|
||||
args["simple_means_flag"] = "3";
|
||||
requesterPost->setBody(args.make());
|
||||
//开启请求
|
||||
// 开启请求 [AUTO-TRANSLATED:ccb4bc7f]
|
||||
// Start the request
|
||||
requesterPost->startRequester("http://fanyi.baidu.com/langdetect",//url地址
|
||||
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
|
||||
const Parser &parser) { //http回复body
|
||||
DebugL << "=====================HttpRequester POST==========================";
|
||||
if (ex) {
|
||||
//网络相关的错误
|
||||
// 网络相关的错误 [AUTO-TRANSLATED:ae96dbe9]
|
||||
// Network-related errors
|
||||
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
|
||||
} else {
|
||||
//打印http回复信息
|
||||
// 打印http回复信息 [AUTO-TRANSLATED:d4611ce2]
|
||||
// Print HTTP response information
|
||||
_StrPrinter printer;
|
||||
for (auto &pr: parser.getHeader()) {
|
||||
printer << pr.first << ":" << pr.second << "\r\n";
|
||||
@@ -129,11 +155,14 @@ int main(int argc, char *argv[]) {
|
||||
});
|
||||
|
||||
///////////////////////////////http upload///////////////////////
|
||||
//创建一个Http请求器
|
||||
// 创建一个Http请求器 [AUTO-TRANSLATED:0d451bc1]
|
||||
// Create an HTTP requestor
|
||||
HttpRequester::Ptr requesterUploader(new HttpRequester());
|
||||
//使用POST方式请求
|
||||
// 使用POST方式请求 [AUTO-TRANSLATED:dc6266f1]
|
||||
// Use the POST method to request
|
||||
requesterUploader->setMethod("POST");
|
||||
//设置http请求头
|
||||
// 设置http请求头 [AUTO-TRANSLATED:d934a806]
|
||||
// Set the HTTP request header
|
||||
HttpArgs argsUploader;
|
||||
argsUploader["query"] = "test";
|
||||
argsUploader["from"] = "en";
|
||||
@@ -145,16 +174,19 @@ int main(int argc, char *argv[]) {
|
||||
HttpMultiFormBody::Ptr body(new HttpMultiFormBody(argsUploader, exePath(), boundary));
|
||||
requesterUploader->setBody(body);
|
||||
requesterUploader->addHeader("Content-Type", HttpMultiFormBody::multiFormContentType(boundary));
|
||||
//开启请求
|
||||
// 开启请求 [AUTO-TRANSLATED:ccb4bc7f]
|
||||
// Start the request
|
||||
requesterUploader->startRequester("http://fanyi.baidu.com/langdetect",//url地址
|
||||
[](const SockException &ex, //网络相关的失败信息,如果为空就代表成功
|
||||
const Parser &parser) { //http回复body
|
||||
DebugL << "=====================HttpRequester Uploader==========================";
|
||||
if (ex) {
|
||||
//网络相关的错误
|
||||
// 网络相关的错误 [AUTO-TRANSLATED:ae96dbe9]
|
||||
// Network-related errors
|
||||
WarnL << "network err:" << ex.getErrCode() << " " << ex.what();
|
||||
} else {
|
||||
//打印http回复信息
|
||||
// 打印http回复信息 [AUTO-TRANSLATED:d4611ce2]
|
||||
// Print HTTP response information
|
||||
_StrPrinter printer;
|
||||
for (auto &pr: parser.getHeader()) {
|
||||
printer << pr.first << ":" << pr.second << "\r\n";
|
||||
|
||||
@@ -22,30 +22,39 @@ using namespace std;
|
||||
using namespace toolkit;
|
||||
using namespace mediakit;
|
||||
|
||||
//推流器,保持强引用
|
||||
// 推流器,保持强引用 [AUTO-TRANSLATED:b2287a61]
|
||||
// Streamer, keep a strong reference
|
||||
MediaPusher::Ptr pusher;
|
||||
Timer::Ptr g_timer;
|
||||
|
||||
//声明函数
|
||||
// 声明函数 [AUTO-TRANSLATED:f3911a32]
|
||||
// Declare function
|
||||
void rePushDelay(const EventPoller::Ptr &poller,const string &schema,const string &vhost,const string &app, const string &stream, const string &url);
|
||||
|
||||
//创建推流器并开始推流
|
||||
// 创建推流器并开始推流 [AUTO-TRANSLATED:583100b5]
|
||||
// Create a streamer and start streaming
|
||||
void createPusher(const EventPoller::Ptr &poller, const string &schema,const string &vhost,const string &app, const string &stream, const string &url) {
|
||||
//创建推流器并绑定一个MediaSource
|
||||
// 创建推流器并绑定一个MediaSource [AUTO-TRANSLATED:b0721d46]
|
||||
// Create a streamer and bind a MediaSource
|
||||
pusher.reset(new MediaPusher(schema,vhost, app, stream,poller));
|
||||
//可以指定rtsp推流方式,支持tcp和udp方式,默认tcp
|
||||
// 可以指定rtsp推流方式,支持tcp和udp方式,默认tcp [AUTO-TRANSLATED:bb0be012]
|
||||
// You can specify the RTSP streaming method, supporting both TCP and UDP methods, defaulting to TCP
|
||||
// (*pusher)[Client::kRtpType] = Rtsp::RTP_UDP;
|
||||
//设置推流中断处理逻辑
|
||||
// 设置推流中断处理逻辑 [AUTO-TRANSLATED:aa6c0405]
|
||||
// Set the streaming interruption handling logic
|
||||
pusher->setOnShutdown([poller,schema,vhost, app, stream, url](const SockException &ex) {
|
||||
WarnL << "Server connection is closed:" << ex.getErrCode() << " " << ex.what();
|
||||
//重试
|
||||
// 重试 [AUTO-TRANSLATED:d96b4814]
|
||||
// Retry
|
||||
rePushDelay(poller,schema,vhost,app, stream, url);
|
||||
});
|
||||
//设置发布结果处理逻辑
|
||||
// 设置发布结果处理逻辑 [AUTO-TRANSLATED:0ee98a13]
|
||||
// Set the publishing result handling logic
|
||||
pusher->setOnPublished([poller,schema,vhost, app, stream, url](const SockException &ex) {
|
||||
if (ex) {
|
||||
WarnL << "Publish fail:" << ex.getErrCode() << " " << ex.what();
|
||||
//如果发布失败,就重试
|
||||
// 如果发布失败,就重试 [AUTO-TRANSLATED:67aff5bd]
|
||||
// If publishing fails, retry
|
||||
rePushDelay(poller,schema,vhost,app, stream, url);
|
||||
} else {
|
||||
InfoL << "Publish success,Please play with player:" << url;
|
||||
@@ -54,26 +63,33 @@ void createPusher(const EventPoller::Ptr &poller, const string &schema,const str
|
||||
pusher->publish(url);
|
||||
}
|
||||
|
||||
//推流失败或断开延迟2秒后重试推流
|
||||
// 推流失败或断开延迟2秒后重试推流 [AUTO-TRANSLATED:bc496634]
|
||||
// If streaming fails or is disconnected, retry streaming after a 2-second delay
|
||||
void rePushDelay(const EventPoller::Ptr &poller,const string &schema,const string &vhost,const string &app, const string &stream, const string &url) {
|
||||
g_timer = std::make_shared<Timer>(2.0f,[poller,schema,vhost,app, stream, url]() {
|
||||
InfoL << "Re-Publishing...";
|
||||
//重新推流
|
||||
// 重新推流 [AUTO-TRANSLATED:edb1e699]
|
||||
// Re-stream
|
||||
createPusher(poller,schema,vhost,app, stream, url);
|
||||
//此任务不重复
|
||||
// 此任务不重复 [AUTO-TRANSLATED:84deec34]
|
||||
// This task is not repeated
|
||||
return false;
|
||||
}, poller);
|
||||
}
|
||||
|
||||
//这里才是真正执行main函数,你可以把函数名(domain)改成main,然后就可以输入自定义url了
|
||||
// 这里才是真正执行main函数,你可以把函数名(domain)改成main,然后就可以输入自定义url了 [AUTO-TRANSLATED:a441f1a2]
|
||||
// This is where the main function is actually executed, you can change the function name (domain) to main, and then you can enter a custom URL
|
||||
int domain(const string &playUrl, const string &pushUrl) {
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set the log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
auto poller = EventPollerPool::Instance().getPoller();
|
||||
|
||||
//拉一个流,生成一个RtmpMediaSource,源的名称是"app/stream"
|
||||
//你也可以以其他方式生成RtmpMediaSource,比如说MP4文件(请查看test_rtmpPusherMp4.cpp代码)
|
||||
// 拉一个流,生成一个RtmpMediaSource,源的名称是"app/stream" [AUTO-TRANSLATED:38b8ab6f]
|
||||
// Pull a stream and generate an RtmpMediaSource, the source name is "app/stream"
|
||||
// 你也可以以其他方式生成RtmpMediaSource,比如说MP4文件(请查看test_rtmpPusherMp4.cpp代码) [AUTO-TRANSLATED:c94c5914]
|
||||
// You can also generate RtmpMediaSource in other ways, such as an MP4 file (please refer to the test_rtmpPusherMp4.cpp code)
|
||||
MediaInfo info(pushUrl);
|
||||
|
||||
ProtocolOption option;
|
||||
@@ -81,21 +97,25 @@ int domain(const string &playUrl, const string &pushUrl) {
|
||||
option.enable_mp4 = false;
|
||||
auto tuple = MediaTuple{DEFAULT_VHOST, "app", "stream", ""};
|
||||
PlayerProxy::Ptr player(new PlayerProxy(tuple, option, -1, poller));
|
||||
//可以指定rtsp拉流方式,支持tcp和udp方式,默认tcp
|
||||
// 可以指定rtsp拉流方式,支持tcp和udp方式,默认tcp [AUTO-TRANSLATED:5169e341]
|
||||
// You can specify the RTSP streaming method, supporting both TCP and UDP methods, defaulting to TCP
|
||||
// (*player)[Client::kRtpType] = Rtsp::RTP_UDP;
|
||||
player->play(playUrl.data());
|
||||
|
||||
//监听RtmpMediaSource注册事件,在PlayerProxy播放成功后触发
|
||||
// 监听RtmpMediaSource注册事件,在PlayerProxy播放成功后触发 [AUTO-TRANSLATED:da417dbe]
|
||||
// Listen for RtmpMediaSource registration events, triggered after PlayerProxy playback is successful
|
||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastMediaChanged,
|
||||
[pushUrl,poller](BroadcastMediaChangedArgs) {
|
||||
//媒体源"app/stream"已经注册,这时方可新建一个RtmpPusher对象并绑定该媒体源
|
||||
// 媒体源"app/stream"已经注册,这时方可新建一个RtmpPusher对象并绑定该媒体源 [AUTO-TRANSLATED:3670cbfd]
|
||||
// The media source "app/stream" has been registered, at this point you can create a new RtmpPusher object and bind it to the media source
|
||||
if (bRegist && pushUrl.find(sender.getSchema()) == 0) {
|
||||
auto tuple = sender.getMediaTuple();
|
||||
createPusher(poller, sender.getSchema(), tuple.vhost, tuple.app, tuple.stream, pushUrl);
|
||||
}
|
||||
});
|
||||
|
||||
//设置退出信号处理函数
|
||||
// 设置退出信号处理函数 [AUTO-TRANSLATED:4f047770]
|
||||
// Set the exit signal processing function
|
||||
static semaphore sem;
|
||||
signal(SIGINT, [](int) { sem.post(); });// 设置退出信号
|
||||
sem.wait();
|
||||
|
||||
@@ -21,13 +21,16 @@ using namespace std;
|
||||
using namespace toolkit;
|
||||
using namespace mediakit;
|
||||
|
||||
// 这里才是真正执行main函数,你可以把函数名(domain)改成main,然后就可以输入自定义url了
|
||||
// 这里才是真正执行main函数,你可以把函数名(domain)改成main,然后就可以输入自定义url了 [AUTO-TRANSLATED:8438b572]
|
||||
// This is where the main function is actually executed, you can change the function name (domain) to main, and then you can enter a custom URL
|
||||
int domain(const string &file, const string &url) {
|
||||
// 设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50ba02ba]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
// 关闭所有转协议
|
||||
// 关闭所有转协议 [AUTO-TRANSLATED:2a58bc8f]
|
||||
// Close all protocol conversions
|
||||
mINI::Instance()[Protocol::kEnableMP4] = 0;
|
||||
mINI::Instance()[Protocol::kEnableFMP4] = 0;
|
||||
mINI::Instance()[Protocol::kEnableHls] = 0;
|
||||
@@ -36,47 +39,59 @@ int domain(const string &file, const string &url) {
|
||||
mINI::Instance()[Protocol::kEnableRtsp] = 0;
|
||||
mINI::Instance()[Protocol::kEnableRtmp] = 0;
|
||||
|
||||
// 根据url获取媒体协议类型,注意大小写
|
||||
// 根据url获取媒体协议类型,注意大小写 [AUTO-TRANSLATED:3cd6622a]
|
||||
// Get the media protocol type based on the URL, note the case
|
||||
auto schema = strToLower(findSubString(url.data(), nullptr, "://").substr(0, 4));
|
||||
|
||||
// 只开启推流协议对应的转协议
|
||||
// 只开启推流协议对应的转协议 [AUTO-TRANSLATED:1c4975ae]
|
||||
// Only enable the protocol conversion corresponding to the push protocol
|
||||
mINI::Instance()["protocol.enable_" + schema] = 1;
|
||||
|
||||
// 从mp4文件加载生成MediaSource对象
|
||||
// 从mp4文件加载生成MediaSource对象 [AUTO-TRANSLATED:5e5b04ca]
|
||||
// Load the MediaSource object from the mp4 file
|
||||
auto tuple = MediaTuple {DEFAULT_VHOST, "live", "stream", ""};
|
||||
auto reader = std::make_shared<MP4Reader>(tuple, file);
|
||||
// 开始加载mp4,ref_self设置为false,这样reader对象设置为nullptr就能注销了,file_repeat可以设置为空,这样文件读完了就停止推流了
|
||||
// 开始加载mp4,ref_self设置为false,这样reader对象设置为nullptr就能注销了,file_repeat可以设置为空,这样文件读完了就停止推流了 [AUTO-TRANSLATED:88a5c8ae]
|
||||
// Start loading the mp4, set ref_self to false, so that the reader object can be set to nullptr to cancel, file_repeat can be set to empty, so that the file is read and the push stream is stopped
|
||||
reader->startReadMP4(100, false, true);
|
||||
auto src = MediaSource::find(schema, DEFAULT_VHOST, "live", "stream", false);
|
||||
|
||||
if (!src) {
|
||||
// 文件不存在
|
||||
// 文件不存在 [AUTO-TRANSLATED:f97c8ce8]
|
||||
// File does not exist
|
||||
WarnL << "File not existed: " << file;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 选择一个poller线程绑定
|
||||
// 选择一个poller线程绑定 [AUTO-TRANSLATED:82d4a318]
|
||||
// Select a poller thread to bind
|
||||
auto poller = EventPollerPool::Instance().getPoller();
|
||||
// 创建推流器并绑定一个MediaSource
|
||||
// 创建推流器并绑定一个MediaSource [AUTO-TRANSLATED:c1ab71ca]
|
||||
// Create a pusher and bind a MediaSource
|
||||
auto pusher = std::make_shared<MediaPusher>(src, poller);
|
||||
|
||||
std::weak_ptr<MediaSource> weak_src = src;
|
||||
// src用完了,可以直接置空,防止main函数持有它(MP4Reader持有它即可)
|
||||
// src用完了,可以直接置空,防止main函数持有它(MP4Reader持有它即可) [AUTO-TRANSLATED:52e6393a]
|
||||
// src is used up, can be set to empty directly, to prevent the main function from holding it (MP4Reader holds it)
|
||||
src = nullptr;
|
||||
|
||||
// 可以指定rtsp推流方式,支持tcp和udp方式,默认tcp
|
||||
// 可以指定rtsp推流方式,支持tcp和udp方式,默认tcp [AUTO-TRANSLATED:235480a7]
|
||||
// You can specify the rtsp push method, support tcp and udp methods, default tcp
|
||||
//(*pusher)[Client::kRtpType] = Rtsp::RTP_UDP;
|
||||
|
||||
// 设置推流中断处理逻辑
|
||||
// 设置推流中断处理逻辑 [AUTO-TRANSLATED:76774d30]
|
||||
// Set the interrupt handling logic during pushing
|
||||
std::weak_ptr<MediaPusher> weak_pusher = pusher;
|
||||
pusher->setOnShutdown([poller, url, weak_pusher, weak_src](const SockException &ex) {
|
||||
if (!weak_src.lock()) {
|
||||
// 媒体注销导致的推流中断,不在重试推流
|
||||
// 媒体注销导致的推流中断,不在重试推流 [AUTO-TRANSLATED:625b3e1a]
|
||||
// Media cancellation causes push interruption, no retry push
|
||||
WarnL << "MediaSource released:" << ex << ", publish stopped";
|
||||
return;
|
||||
}
|
||||
WarnL << "Server connection is closed:" << ex << ", republish after 2 seconds";
|
||||
// 重新推流, 2秒后重试
|
||||
// 重新推流, 2秒后重试 [AUTO-TRANSLATED:f8a261a3]
|
||||
// Repush, retry after 2 seconds
|
||||
poller->doDelayTask(2 * 1000, [weak_pusher, url]() {
|
||||
if (auto strong_push = weak_pusher.lock()) {
|
||||
strong_push->publish(url);
|
||||
@@ -85,7 +100,8 @@ int domain(const string &file, const string &url) {
|
||||
});
|
||||
});
|
||||
|
||||
// 设置发布结果处理逻辑
|
||||
// 设置发布结果处理逻辑 [AUTO-TRANSLATED:ce9de055]
|
||||
// Set the publish result handling logic
|
||||
pusher->setOnPublished([poller, weak_pusher, url](const SockException &ex) {
|
||||
if (!ex) {
|
||||
InfoL << "Publish success, please play with player:" << url;
|
||||
@@ -93,7 +109,8 @@ int domain(const string &file, const string &url) {
|
||||
}
|
||||
|
||||
WarnL << "Publish fail:" << ex << ", republish after 2 seconds";
|
||||
// 如果发布失败,就重试
|
||||
// 如果发布失败,就重试 [AUTO-TRANSLATED:b37fd4aa]
|
||||
// If the publish fails, retry
|
||||
poller->doDelayTask(2 * 1000, [weak_pusher, url]() {
|
||||
if (auto strong_push = weak_pusher.lock()) {
|
||||
strong_push->publish(url);
|
||||
@@ -104,10 +121,12 @@ int domain(const string &file, const string &url) {
|
||||
pusher->publish(url);
|
||||
|
||||
// sleep(5);
|
||||
// reader 置空可以终止推流相关资源
|
||||
// reader 置空可以终止推流相关资源 [AUTO-TRANSLATED:02442070]
|
||||
// reader set to empty can terminate the push-related resources
|
||||
// reader = nullptr;
|
||||
|
||||
// 设置退出信号处理函数
|
||||
// 设置退出信号处理函数 [AUTO-TRANSLATED:69e8f733]
|
||||
// Set the exit signal processing function
|
||||
static semaphore sem;
|
||||
signal(SIGINT, [](int) { sem.post(); }); // 设置退出信号
|
||||
sem.wait();
|
||||
@@ -115,8 +134,10 @@ int domain(const string &file, const string &url) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// 可以使用test_server生成的mp4文件
|
||||
// 文件使用绝对路径,推流url支持rtsp和rtmp
|
||||
// 可以使用test_server生成的mp4文件 [AUTO-TRANSLATED:a9552282]
|
||||
// You can use the mp4 file generated by test_server
|
||||
// 文件使用绝对路径,推流url支持rtsp和rtmp [AUTO-TRANSLATED:efc8c3b5]
|
||||
// File uses absolute path, push URL supports rtsp and rtmp
|
||||
// return domain("/Users/xiongziliang/Downloads/mp4/Quantum.mp4", "rtsp://127.0.0.1/live/rtsp_push");
|
||||
return domain(argv[1], argv[2]);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,8 @@ static bool loadFile(const char *path, const EventPoller::Ptr &poller) {
|
||||
while (true) {
|
||||
if (2 != fread(&len, 1, 2, fp.get())) {
|
||||
WarnL << "Read rtp size failed";
|
||||
// 重新播放
|
||||
// 重新播放 [AUTO-TRANSLATED:9f678d55]
|
||||
// Replay
|
||||
fseek(fp.get(), 0, SEEK_SET);
|
||||
return 1;
|
||||
}
|
||||
@@ -98,10 +99,12 @@ static bool loadFile(const char *path, const EventPoller::Ptr &poller) {
|
||||
#endif // #if defined(ENABLE_RTPPROXY)
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// 设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50ba02ba]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>("ConsoleChannel"));
|
||||
#if defined(ENABLE_RTPPROXY)
|
||||
// 启动异步日志线程
|
||||
// 启动异步日志线程 [AUTO-TRANSLATED:8340d047]
|
||||
// Start asynchronous log thread
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
loadIniConfig((exeDir() + "config.ini").data());
|
||||
TcpServer::Ptr rtspSrv(new TcpServer());
|
||||
@@ -110,7 +113,8 @@ int main(int argc, char *argv[]) {
|
||||
rtspSrv->start<RtspSession>(554); // 默认554
|
||||
rtmpSrv->start<RtmpSession>(1935); // 默认1935
|
||||
httpSrv->start<HttpSession>(80); // 默认80
|
||||
// 此处选择是否导出调试文件
|
||||
// 此处选择是否导出调试文件 [AUTO-TRANSLATED:b147c25b]
|
||||
// Choose whether to export debug file here
|
||||
// mINI::Instance()[RtpProxy::kDumpDir] = "/Users/xzl/Desktop/";
|
||||
|
||||
if (argc == 2) {
|
||||
|
||||
@@ -33,7 +33,8 @@ using namespace toolkit;
|
||||
using namespace mediakit;
|
||||
|
||||
namespace mediakit {
|
||||
////////////HTTP配置///////////
|
||||
// //////////HTTP配置/////////// [AUTO-TRANSLATED:a281d694]
|
||||
// //////////HTTP Configuration///////////
|
||||
namespace Http {
|
||||
#define HTTP_FIELD "http."
|
||||
#define HTTP_PORT 80
|
||||
@@ -46,7 +47,8 @@ onceToken token1([](){
|
||||
},nullptr);
|
||||
}//namespace Http
|
||||
|
||||
////////////SHELL配置///////////
|
||||
// //////////SHELL配置/////////// [AUTO-TRANSLATED:f023ec45]
|
||||
// //////////SHELL Configuration///////////
|
||||
namespace Shell {
|
||||
#define SHELL_FIELD "shell."
|
||||
#define SHELL_PORT 9000
|
||||
@@ -56,7 +58,8 @@ onceToken token1([](){
|
||||
},nullptr);
|
||||
} //namespace Shell
|
||||
|
||||
////////////RTSP服务器配置///////////
|
||||
// //////////RTSP服务器配置/////////// [AUTO-TRANSLATED:950e1981]
|
||||
// //////////RTSP Server Configuration///////////
|
||||
namespace Rtsp {
|
||||
#define RTSP_FIELD "rtsp."
|
||||
#define RTSP_PORT 554
|
||||
@@ -70,7 +73,8 @@ onceToken token1([](){
|
||||
|
||||
} //namespace Rtsp
|
||||
|
||||
////////////RTMP服务器配置///////////
|
||||
// //////////RTMP服务器配置/////////// [AUTO-TRANSLATED:8de6f41f]
|
||||
// //////////RTMP Server Configuration///////////
|
||||
namespace Rtmp {
|
||||
#define RTMP_FIELD "rtmp."
|
||||
#define RTMP_PORT 1935
|
||||
@@ -88,72 +92,91 @@ static mutex s_mtxFlvRecorder;
|
||||
|
||||
void initEventListener() {
|
||||
static onceToken s_token([]() {
|
||||
//监听kBroadcastOnGetRtspRealm事件决定rtsp链接是否需要鉴权(传统的rtsp鉴权方案)才能访问
|
||||
// 监听kBroadcastOnGetRtspRealm事件决定rtsp链接是否需要鉴权(传统的rtsp鉴权方案)才能访问 [AUTO-TRANSLATED:cf05f5a1]
|
||||
// Listen for kBroadcastOnGetRtspRealm event to decide if rtsp link needs authentication (traditional rtsp authentication scheme) to access
|
||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastOnGetRtspRealm, [](BroadcastOnGetRtspRealmArgs) {
|
||||
DebugL << "RTSP是否需要鉴权事件:" << args.getUrl() << " " << args.params;
|
||||
if (string("1") == args.stream) {
|
||||
// live/1需要认证
|
||||
//该流需要认证,并且设置realm
|
||||
// live/1需要认证 [AUTO-TRANSLATED:c3885602]
|
||||
// live/1 needs authentication
|
||||
// 该流需要认证,并且设置realm [AUTO-TRANSLATED:624f8df5]
|
||||
// This stream needs authentication and sets realm
|
||||
invoker(REALM);
|
||||
} else {
|
||||
//有时我们要查询redis或数据库来判断该流是否需要认证,通过invoker的方式可以做到完全异步
|
||||
//该流我们不需要认证
|
||||
// 有时我们要查询redis或数据库来判断该流是否需要认证,通过invoker的方式可以做到完全异步 [AUTO-TRANSLATED:41d2819d]
|
||||
// Sometimes we need to query redis or database to determine if the stream needs authentication, which can be done asynchronously through invoker
|
||||
// 该流我们不需要认证 [AUTO-TRANSLATED:67866699]
|
||||
// This stream does not need authentication
|
||||
invoker("");
|
||||
}
|
||||
});
|
||||
|
||||
//监听kBroadcastOnRtspAuth事件返回正确的rtsp鉴权用户密码
|
||||
// 监听kBroadcastOnRtspAuth事件返回正确的rtsp鉴权用户密码 [AUTO-TRANSLATED:3d135a03]
|
||||
// Listen for kBroadcastOnRtspAuth event to return the correct rtsp authentication username and password
|
||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastOnRtspAuth, [](BroadcastOnRtspAuthArgs) {
|
||||
DebugL << "RTSP播放鉴权:" << args.getUrl() << " " << args.params;
|
||||
DebugL << "RTSP用户:" << user_name << (must_no_encrypt ? " Base64" : " MD5") << " 方式登录";
|
||||
string user = user_name;
|
||||
//假设我们异步读取数据库
|
||||
// 假设我们异步读取数据库 [AUTO-TRANSLATED:38545bdf]
|
||||
// Assuming we read the database asynchronously
|
||||
if (user == "test0") {
|
||||
//假设数据库保存的是明文
|
||||
// 假设数据库保存的是明文 [AUTO-TRANSLATED:731d594a]
|
||||
// Assuming the database stores plaintext
|
||||
invoker(false, "pwd0");
|
||||
return;
|
||||
}
|
||||
|
||||
if (user == "test1") {
|
||||
//假设数据库保存的是密文
|
||||
// 假设数据库保存的是密文 [AUTO-TRANSLATED:293ae3d5]
|
||||
// Assuming the database stores ciphertext
|
||||
auto encrypted_pwd = MD5(user + ":" + REALM + ":" + "pwd1").hexdigest();
|
||||
invoker(true, encrypted_pwd);
|
||||
return;
|
||||
}
|
||||
if (user == "test2" && must_no_encrypt) {
|
||||
//假设登录的是test2,并且以base64方式登录,此时我们提供加密密码,那么会导致认证失败
|
||||
//可以通过这个方式屏蔽base64这种不安全的加密方式
|
||||
// 假设登录的是test2,并且以base64方式登录,此时我们提供加密密码,那么会导致认证失败 [AUTO-TRANSLATED:e2b29961]
|
||||
// Assuming login is test2 and login in base64 format, in this case we provide encrypted password, which will cause authentication failure
|
||||
// 可以通过这个方式屏蔽base64这种不安全的加密方式 [AUTO-TRANSLATED:f303f620]
|
||||
// You can shield this insecure encryption method in this way
|
||||
invoker(true, "pwd2");
|
||||
return;
|
||||
}
|
||||
|
||||
//其他用户密码跟用户名一致
|
||||
// 其他用户密码跟用户名一致 [AUTO-TRANSLATED:53aa89d9]
|
||||
// Other user passwords are the same as usernames
|
||||
invoker(false, user);
|
||||
});
|
||||
|
||||
|
||||
//监听rtsp/rtmp推流事件,返回结果告知是否有推流权限
|
||||
// 监听rtsp/rtmp推流事件,返回结果告知是否有推流权限 [AUTO-TRANSLATED:6c16b087]
|
||||
// Listen for rtsp/rtmp push stream event, return result to inform whether there is push stream permission
|
||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastMediaPublish, [](BroadcastMediaPublishArgs) {
|
||||
DebugL << "推流鉴权:" << args.getUrl() << " " << args.params;
|
||||
invoker("", ProtocolOption());//鉴权成功
|
||||
//invoker("this is auth failed message");//鉴权失败
|
||||
// invoker("this is auth failed message");//鉴权失败 [AUTO-TRANSLATED:4131434d]
|
||||
// invoker("this is auth failed message");//Authentication failed
|
||||
});
|
||||
|
||||
//监听rtsp/rtsps/rtmp/http-flv播放事件,返回结果告知是否有播放权限(rtsp通过kBroadcastOnRtspAuth或此事件都可以实现鉴权)
|
||||
// 监听rtsp/rtsps/rtmp/http-flv播放事件,返回结果告知是否有播放权限(rtsp通过kBroadcastOnRtspAuth或此事件都可以实现鉴权) [AUTO-TRANSLATED:94fed0b4]
|
||||
// Listen for rtsp/rtsps/rtmp/http-flv playback event, return result to inform whether there is playback permission (rtsp can implement authentication through kBroadcastOnRtspAuth or this event)
|
||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastMediaPlayed, [](BroadcastMediaPlayedArgs) {
|
||||
DebugL << "播放鉴权:" << args.getUrl() << " " << args.params;
|
||||
invoker("");//鉴权成功
|
||||
//invoker("this is auth failed message");//鉴权失败
|
||||
// invoker("this is auth failed message");//鉴权失败 [AUTO-TRANSLATED:4131434d]
|
||||
// invoker("this is auth failed message");//Authentication failed
|
||||
});
|
||||
|
||||
//shell登录事件,通过shell可以登录进服务器执行一些命令
|
||||
// shell登录事件,通过shell可以登录进服务器执行一些命令 [AUTO-TRANSLATED:a60f6d9f]
|
||||
// Shell login event, you can log in to the server through shell to execute some commands
|
||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastShellLogin, [](BroadcastShellLoginArgs) {
|
||||
DebugL << "shell login:" << user_name << " " << passwd;
|
||||
invoker("");//鉴权成功
|
||||
//invoker("this is auth failed message");//鉴权失败
|
||||
// invoker("this is auth failed message");//鉴权失败 [AUTO-TRANSLATED:4131434d]
|
||||
// invoker("this is auth failed message");//Authentication failed
|
||||
});
|
||||
|
||||
//监听rtsp、rtmp源注册或注销事件;此处用于测试rtmp保存为flv录像,保存在http根目录下
|
||||
// 监听rtsp、rtmp源注册或注销事件;此处用于测试rtmp保存为flv录像,保存在http根目录下 [AUTO-TRANSLATED:c572252d]
|
||||
// Listen for rtsp/rtmp source registration or cancellation event; this is used to test rtmp saving as flv recording, saved in the http root directory
|
||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastMediaChanged, [](BroadcastMediaChangedArgs) {
|
||||
auto tuple = sender.getMediaTuple();
|
||||
if (sender.getSchema() == RTMP_SCHEMA && tuple.app == "live") {
|
||||
@@ -177,17 +200,23 @@ void initEventListener() {
|
||||
}
|
||||
});
|
||||
|
||||
//监听播放失败(未找到特定的流)事件
|
||||
// 监听播放失败(未找到特定的流)事件 [AUTO-TRANSLATED:eeac767c]
|
||||
// Listen for playback failure (stream not found) event
|
||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastNotFoundStream, [](BroadcastNotFoundStreamArgs) {
|
||||
/**
|
||||
* 你可以在这个事件触发时再去拉流,这样就可以实现按需拉流
|
||||
* 拉流成功后,ZLMediaKit会把其立即转发给播放器(最大等待时间约为5秒,如果5秒都未拉流成功,播放器会播放失败)
|
||||
* You can pull the stream again when this event is triggered, which can implement on-demand pulling
|
||||
* After pulling the stream successfully, ZLMediaKit will immediately forward it to the player (the maximum waiting time is about 5 seconds, if it still fails to pull the stream within 5 seconds, the player will play failure)
|
||||
|
||||
* [AUTO-TRANSLATED:5a01351c]
|
||||
*/
|
||||
DebugL << "未找到流事件:" << args.getUrl() << " " << args.params;
|
||||
});
|
||||
|
||||
|
||||
//监听播放或推流结束时消耗流量事件
|
||||
// 监听播放或推流结束时消耗流量事件 [AUTO-TRANSLATED:f87ac02d]
|
||||
// Listen for playback or push stream end event to consume traffic
|
||||
NoticeCenter::Instance().addListener(nullptr, Broadcast::kBroadcastFlowReport, [](BroadcastFlowReportArgs) {
|
||||
DebugL << "播放器(推流器)断开连接事件:" << args.getUrl() << " " << args.params << "\r\n使用流量:" << totalBytes << " bytes,连接时长:" << totalDuration << "秒";
|
||||
|
||||
@@ -202,41 +231,56 @@ void initEventListener() {
|
||||
#endif
|
||||
|
||||
int main(int argc,char *argv[]) {
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||
Logger::Instance().add(std::make_shared<FileChannel>());
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
//加载配置文件,如果配置文件不存在就创建一个
|
||||
// 加载配置文件,如果配置文件不存在就创建一个 [AUTO-TRANSLATED:761e7479]
|
||||
// Load configuration file, if the configuration file does not exist, create one
|
||||
loadIniConfig();
|
||||
initEventListener();
|
||||
|
||||
//这里是拉流地址,支持rtmp/rtsp协议,负载必须是H264+AAC
|
||||
//如果是其他不识别的音视频将会被忽略(譬如说h264+adpcm转发后会去除音频)
|
||||
// 这里是拉流地址,支持rtmp/rtsp协议,负载必须是H264+AAC [AUTO-TRANSLATED:3f92b7aa]
|
||||
// This is the pull stream address, supports rtmp/rtsp protocol, and the payload must be H264+AAC
|
||||
// 如果是其他不识别的音视频将会被忽略(譬如说h264+adpcm转发后会去除音频) [AUTO-TRANSLATED:ad4be3b6]
|
||||
// If it is other unrecognized audio and video, it will be ignored (for example, h264+adpcm will remove audio after forwarding)
|
||||
auto urlList = {"rtsp://admin:admin123@192.168.1.64:554/cam/realmonitor?channel=1&subtype=1"
|
||||
//rtsp链接支持输入用户名密码
|
||||
// rtsp链接支持输入用户名密码 [AUTO-TRANSLATED:a0e2ebfa]
|
||||
// rtsp link supports inputting username and password
|
||||
/*"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,那么直播地址为:
|
||||
// PlayerProxy构造函数前两个参数分别为应用名(app),流id(streamId) [AUTO-TRANSLATED:5b793e17]
|
||||
// PlayerProxy constructor's first two parameters are application name (app) and stream id (streamId)
|
||||
// 比如说应用为live,流id为0,那么直播地址为: [AUTO-TRANSLATED:d1f0844c]
|
||||
// For example, if the application is live and the stream id is 0, the live address is:
|
||||
|
||||
//hls地址 : http://127.0.0.1/live/0/hls.m3u8
|
||||
//http-flv地址 : http://127.0.0.1/live/0.flv
|
||||
//rtsp地址 : rtsp://127.0.0.1/live/0
|
||||
//rtmp地址 : rtmp://127.0.0.1/live/0
|
||||
// hls地址 : http://127.0.0.1/live/0/hls.m3u8 [AUTO-TRANSLATED:0a684e23]
|
||||
// hls address: http://127.0.0.1/live/0/hls.m3u8
|
||||
// http-flv地址 : http://127.0.0.1/live/0.flv [AUTO-TRANSLATED:ffdf3994]
|
||||
// http-flv address: http://127.0.0.1/live/0.flv
|
||||
// rtsp地址 : rtsp://127.0.0.1/live/0 [AUTO-TRANSLATED:784f37f6]
|
||||
// rtsp address: rtsp://127.0.0.1/live/0
|
||||
// rtmp地址 : rtmp://127.0.0.1/live/0 [AUTO-TRANSLATED:6f377de8]
|
||||
// rtmp address: rtmp://127.0.0.1/live/0
|
||||
|
||||
//录像地址为(当然vlc不支持这么多级的rtmp url,可以用test_player测试rtmp点播):
|
||||
// 录像地址为(当然vlc不支持这么多级的rtmp url,可以用test_player测试rtmp点播): [AUTO-TRANSLATED:2e45d9a5]
|
||||
// The recorded address is (of course, vlc does not support so many levels of rtmp url, you can use test_player to test rtmp on-demand):
|
||||
//http://127.0.0.1/record/live/0/2017-04-11/11-09-38.mp4
|
||||
//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
|
||||
auto tuple = MediaTuple{DEFAULT_VHOST, "live", std::string("chn") + to_string(i).data(), ""};
|
||||
PlayerProxy::Ptr player(new PlayerProxy(tuple, ProtocolOption()));
|
||||
//指定RTP over TCP(播放rtsp时有效)
|
||||
// 指定RTP over TCP(播放rtsp时有效) [AUTO-TRANSLATED:1a062656]
|
||||
// Specify RTP over TCP (effective when playing rtsp)
|
||||
(*player)[Client::kRtpType] = Rtsp::RTP_TCP;
|
||||
//开始播放,如果播放失败或者播放中止,将会自动重试若干次,重试次数在配置文件中配置,默认一直重试
|
||||
// 开始播放,如果播放失败或者播放中止,将会自动重试若干次,重试次数在配置文件中配置,默认一直重试 [AUTO-TRANSLATED:c9ad670c]
|
||||
// Start playing. If playback fails or is interrupted, it will automatically retry several times. The number of retries is configured in the configuration file, and the default is to retry indefinitely
|
||||
player->play(url);
|
||||
//需要保存PlayerProxy,否则作用域结束就会销毁该对象
|
||||
// 需要保存PlayerProxy,否则作用域结束就会销毁该对象 [AUTO-TRANSLATED:939a84c9]
|
||||
// You need to save PlayerProxy, otherwise the object will be destroyed when the scope ends
|
||||
proxyMap.emplace(to_string(i), player);
|
||||
++i;
|
||||
}
|
||||
@@ -249,11 +293,14 @@ int main(int argc,char *argv[]) {
|
||||
" rtsp地址 : rtsp://127.0.0.1/live/0\n"
|
||||
" rtmp地址 : rtmp://127.0.0.1/live/0";
|
||||
|
||||
//加载证书,证书包含公钥和私钥
|
||||
// 加载证书,证书包含公钥和私钥 [AUTO-TRANSLATED:fce78641]
|
||||
// Load the certificate, which contains the public key and private key
|
||||
SSL_Initor::Instance().loadCertificate((exeDir() + "ssl.p12").data());
|
||||
//信任某个自签名证书
|
||||
// 信任某个自签名证书 [AUTO-TRANSLATED:6815fc55]
|
||||
// Trust a self-signed certificate
|
||||
SSL_Initor::Instance().trustCertificate((exeDir() + "ssl.p12").data());
|
||||
//不忽略无效证书证书(例如自签名或过期证书)
|
||||
// 不忽略无效证书证书(例如自签名或过期证书) [AUTO-TRANSLATED:ee4a34c4]
|
||||
// Do not ignore invalid certificates (such as self-signed or expired certificates)
|
||||
SSL_Initor::Instance().ignoreInvalidCertificate(false);
|
||||
|
||||
uint16_t shellPort = mINI::Instance()[Shell::kPort];
|
||||
@@ -263,8 +310,10 @@ int main(int argc,char *argv[]) {
|
||||
uint16_t httpPort = mINI::Instance()[Http::kPort];
|
||||
uint16_t httpsPort = mINI::Instance()[Http::kSSLPort];
|
||||
|
||||
//简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象
|
||||
//测试方法:telnet 127.0.0.1 9000
|
||||
// 简单的telnet服务器,可用于服务器调试,但是不能使用23端口,否则telnet上了莫名其妙的现象 [AUTO-TRANSLATED:f9324c6e]
|
||||
// A simple telnet server, which can be used for server debugging, but cannot use port 23, otherwise telnet will have inexplicable phenomena
|
||||
// 测试方法:telnet 127.0.0.1 9000 [AUTO-TRANSLATED:de0ac883]
|
||||
// Test method: telnet 127.0.0.1 9000
|
||||
TcpServer::Ptr shellSrv(new TcpServer());
|
||||
TcpServer::Ptr rtspSrv(new TcpServer());
|
||||
TcpServer::Ptr rtmpSrv(new TcpServer());
|
||||
@@ -273,21 +322,27 @@ int main(int argc,char *argv[]) {
|
||||
shellSrv->start<ShellSession>(shellPort);
|
||||
rtspSrv->start<RtspSession>(rtspPort);//默认554
|
||||
rtmpSrv->start<RtmpSession>(rtmpPort);//默认1935
|
||||
//http服务器
|
||||
// http服务器 [AUTO-TRANSLATED:10d47f45]
|
||||
// http server
|
||||
httpSrv->start<HttpSession>(httpPort);//默认80
|
||||
|
||||
//如果支持ssl,还可以开启https服务器
|
||||
// 如果支持ssl,还可以开启https服务器 [AUTO-TRANSLATED:8ef29f9c]
|
||||
// If ssl is supported, you can also enable the https server
|
||||
TcpServer::Ptr httpsSrv(new TcpServer());
|
||||
//https服务器
|
||||
// https服务器 [AUTO-TRANSLATED:a2bb64bd]
|
||||
// https server
|
||||
httpsSrv->start<HttpsSession>(httpsPort);//默认443
|
||||
|
||||
//支持ssl加密的rtsp服务器,可用于诸如亚马逊echo show这样的设备访问
|
||||
// 支持ssl加密的rtsp服务器,可用于诸如亚马逊echo show这样的设备访问 [AUTO-TRANSLATED:ded79b73]
|
||||
// rtsp server that supports ssl encryption, which can be used for devices such as Amazon Echo Show to access
|
||||
TcpServer::Ptr rtspSSLSrv(new TcpServer());
|
||||
rtspSSLSrv->start<RtspSessionWithSSL>(rtspsPort);//默认322
|
||||
|
||||
//服务器支持动态切换端口(不影响现有连接)
|
||||
// 服务器支持动态切换端口(不影响现有连接) [AUTO-TRANSLATED:28949b78]
|
||||
// The server supports dynamic port switching (without affecting existing connections)
|
||||
NoticeCenter::Instance().addListener(ReloadConfigTag,Broadcast::kBroadcastReloadConfig,[&](BroadcastReloadConfigArgs){
|
||||
//重新创建服务器
|
||||
// 重新创建服务器 [AUTO-TRANSLATED:4e192357]
|
||||
// Recreate the server
|
||||
if(shellPort != mINI::Instance()[Shell::kPort].as<uint16_t>()){
|
||||
shellPort = mINI::Instance()[Shell::kPort];
|
||||
shellSrv->start<ShellSession>(shellPort);
|
||||
@@ -321,7 +376,8 @@ int main(int argc,char *argv[]) {
|
||||
}
|
||||
});
|
||||
|
||||
//设置退出信号处理函数
|
||||
// 设置退出信号处理函数 [AUTO-TRANSLATED:4f047770]
|
||||
// Set the exit signal processing function
|
||||
static semaphore sem;
|
||||
signal(SIGINT, [](int) { sem.post(); });// 设置退出信号
|
||||
signal(SIGHUP, [](int) { loadIniConfig(); });
|
||||
|
||||
@@ -18,7 +18,8 @@ using namespace std;
|
||||
using namespace mediakit;
|
||||
|
||||
void test_real() {
|
||||
//这个是一次真实的rtp seq记录
|
||||
// 这个是一次真实的rtp seq记录 [AUTO-TRANSLATED:a0cbaeff]
|
||||
// This is a real rtp seq record
|
||||
list<uint16_t> input_list = {15125, 15126, 15127, 15128, 15129, 15130, 15131, 15132, 15133, 15134, 15135, 15136,
|
||||
15137, 15138, 15139, 15140, 15141, 15142, 15143, 15144, 15145, 15146, 15147, 15148,
|
||||
15149, 15150, 15151, 15152, 15153, 15154, 15155, 15156, 15157, 15158, 15159, 15160,
|
||||
@@ -113,7 +114,8 @@ void test_real() {
|
||||
cout << "输入数据个数:" << input_list.size()
|
||||
<< " 抖动缓冲区大小:" << sortor.getJitterSize();
|
||||
|
||||
//清空缓存
|
||||
// 清空缓存 [AUTO-TRANSLATED:a7d8287a]
|
||||
// Clear cache
|
||||
sortor.flush();
|
||||
|
||||
cout << " 输出数据个数:" << sorted_list.size() << endl;
|
||||
@@ -156,12 +158,14 @@ void test_rand(){
|
||||
});
|
||||
|
||||
for (int i = 0; i < 1000;) {
|
||||
//模拟乱序,count是连续倒序次数,最多连续乱序8次
|
||||
// 模拟乱序,count是连续倒序次数,最多连续乱序8次 [AUTO-TRANSLATED:76bd8e43]
|
||||
// Simulate out-of-order, count is the number of consecutive reverse orders, up to 8 consecutive out-of-orders
|
||||
int count = 1 + rand() % 10;
|
||||
for (int j = i + count; j >= i; --j) {
|
||||
|
||||
#if 1
|
||||
//模拟回环
|
||||
// 模拟回环 [AUTO-TRANSLATED:c865877b]
|
||||
// Simulate loopback
|
||||
uint16_t seq = 0xFFFF - 500 + j;
|
||||
#else
|
||||
uint16_t seq = j;
|
||||
@@ -170,29 +174,35 @@ void test_rand(){
|
||||
#if 1
|
||||
int input = 0;
|
||||
if (seq != 0xFFFF && seq != 0) {
|
||||
//模拟回环时丢包
|
||||
// 模拟回环时丢包 [AUTO-TRANSLATED:b7a709cd]
|
||||
// Simulate packet loss during loopback
|
||||
if (seq % (1 + rand() % 100) == 0) {
|
||||
//模拟重复,概率5%左右
|
||||
// 模拟重复,概率5%左右 [AUTO-TRANSLATED:f096bdf1]
|
||||
// Simulate duplication, about 5% probability
|
||||
sortor.sortPacket(seq, seq);
|
||||
input_list.push_back(seq);
|
||||
++input;
|
||||
}
|
||||
if (seq % (1 + rand() % 100) != 0) {
|
||||
//模拟丢包,概率5%左右
|
||||
// 模拟丢包,概率5%左右 [AUTO-TRANSLATED:91a54869]
|
||||
// Simulate packet loss, about 5% probability
|
||||
sortor.sortPacket(seq, seq);
|
||||
input_list.push_back(seq);
|
||||
++input;
|
||||
}
|
||||
}
|
||||
switch (input) {
|
||||
//输入0次,丢包
|
||||
// 输入0次,丢包 [AUTO-TRANSLATED:fb462a30]
|
||||
// Input 0 times, packet loss
|
||||
case 0 :
|
||||
drop_list.push_back(seq);
|
||||
break;
|
||||
//输入1次,正常
|
||||
// 输入1次,正常 [AUTO-TRANSLATED:ec648d0a]
|
||||
// Input 1 time, normal
|
||||
case 1 :
|
||||
break;
|
||||
//输入2+次,重复包
|
||||
// 输入2+次,重复包 [AUTO-TRANSLATED:fbc6549f]
|
||||
// Input 2+ times, duplicate packets
|
||||
default:
|
||||
repeat_list.push_back(seq);
|
||||
break;
|
||||
@@ -209,7 +219,8 @@ void test_rand(){
|
||||
<< " 丢包个数:" << drop_list.size()
|
||||
<< " 重复包个数:" << repeat_list.size();
|
||||
|
||||
//清空缓存
|
||||
// 清空缓存 [AUTO-TRANSLATED:a7d8287a]
|
||||
// Clear cache
|
||||
sortor.flush();
|
||||
|
||||
cout << " 输出数据个数:" << sorted_list.size() << endl;
|
||||
@@ -269,13 +280,16 @@ void test_rand(){
|
||||
#endif
|
||||
}
|
||||
|
||||
//该测试程序用于检验rtp排序算法的正确性
|
||||
// 该测试程序用于检验rtp排序算法的正确性 [AUTO-TRANSLATED:251b9c45]
|
||||
// This test program is used to verify the correctness of the rtp sorting algorithm
|
||||
int main(int argc, char *argv[]) {
|
||||
//测试真实的rtp seq
|
||||
// 测试真实的rtp seq [AUTO-TRANSLATED:d87b1d7a]
|
||||
// Test real rtp seq
|
||||
cout << "###### 真实的rtp seq #####" << endl;
|
||||
test_real();
|
||||
|
||||
//模拟rtp乱序、回环、丢包、重复情况
|
||||
// 模拟rtp乱序、回环、丢包、重复情况 [AUTO-TRANSLATED:cc92ba9d]
|
||||
// Simulate rtp out-of-order, loopback, packet loss, and duplication scenarios
|
||||
cout << "###### 模拟的rtp seq #####" << endl;
|
||||
test_rand();
|
||||
return 0;
|
||||
|
||||
@@ -31,32 +31,38 @@ protected:
|
||||
void onRecv(const Buffer::Ptr &pBuf) override {
|
||||
DebugL << pBuf->toString();
|
||||
}
|
||||
//被动断开连接回调
|
||||
// 被动断开连接回调 [AUTO-TRANSLATED:037fc69f]
|
||||
// Passive disconnection callback
|
||||
void onError(const SockException &ex) override {
|
||||
WarnL << ex;
|
||||
}
|
||||
//tcp连接成功后每2秒触发一次该事件
|
||||
// tcp连接成功后每2秒触发一次该事件 [AUTO-TRANSLATED:4bcf65bf]
|
||||
// Triggered every 2 seconds after a successful TCP connection
|
||||
void onManager() override {
|
||||
SockSender::send("echo test!");
|
||||
DebugL << "send echo test";
|
||||
}
|
||||
//连接服务器结果回调
|
||||
// 连接服务器结果回调 [AUTO-TRANSLATED:b8306897]
|
||||
// Server connection result callback
|
||||
void onConnect(const SockException &ex) override{
|
||||
DebugL << ex;
|
||||
}
|
||||
|
||||
//数据全部发送完毕后回调
|
||||
// 数据全部发送完毕后回调 [AUTO-TRANSLATED:f927c4c9]
|
||||
// Callback after all data has been sent
|
||||
void onFlush() override{
|
||||
DebugL;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
//设置退出信号处理函数
|
||||
// 设置退出信号处理函数 [AUTO-TRANSLATED:4f047770]
|
||||
// Set exit signal processing function
|
||||
static semaphore sem;
|
||||
signal(SIGINT, [](int) { sem.post(); });// 设置退出信号
|
||||
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ using namespace mediakit;
|
||||
|
||||
/**
|
||||
* 回显会话
|
||||
* Echo Session
|
||||
|
||||
* [AUTO-TRANSLATED:bc2a4e9e]
|
||||
*/
|
||||
class EchoSession : public Session {
|
||||
public:
|
||||
@@ -35,14 +38,16 @@ public:
|
||||
DebugL << getIdentifier() << " " << Session::getIdentifier();
|
||||
}
|
||||
void onRecv(const Buffer::Ptr &buffer) override {
|
||||
//回显数据
|
||||
// 回显数据 [AUTO-TRANSLATED:36769402]
|
||||
// Echo Data
|
||||
SockSender::send("from EchoSession:");
|
||||
send(buffer);
|
||||
}
|
||||
void onError(const SockException &err) override{
|
||||
WarnL << err.what();
|
||||
}
|
||||
//每隔一段时间触发,用来做超时管理
|
||||
// 每隔一段时间触发,用来做超时管理 [AUTO-TRANSLATED:823ffe1f]
|
||||
// Triggered at regular intervals, used for timeout management
|
||||
void onManager() override{
|
||||
DebugL;
|
||||
}
|
||||
@@ -62,14 +67,16 @@ public:
|
||||
DebugL << getIdentifier() << " " << Session::getIdentifier();
|
||||
}
|
||||
void onRecv(const Buffer::Ptr &buffer) override {
|
||||
//回显数据
|
||||
// 回显数据 [AUTO-TRANSLATED:36769402]
|
||||
// Echo Data
|
||||
SockSender::send("from EchoSessionWithUrl:");
|
||||
send(buffer);
|
||||
}
|
||||
void onError(const SockException &err) override{
|
||||
WarnL << err.what();
|
||||
}
|
||||
//每隔一段时间触发,用来做超时管理
|
||||
// 每隔一段时间触发,用来做超时管理 [AUTO-TRANSLATED:823ffe1f]
|
||||
// Triggered at regular intervals, used for timeout management
|
||||
void onManager() override{
|
||||
DebugL;
|
||||
}
|
||||
@@ -78,13 +85,18 @@ public:
|
||||
|
||||
/**
|
||||
* 此对象可以根据websocket 客户端访问的url选择创建不同的对象
|
||||
* This object can create different objects based on the URL accessed by the WebSocket client
|
||||
|
||||
* [AUTO-TRANSLATED:57f51c96]
|
||||
*/
|
||||
struct EchoSessionCreator {
|
||||
//返回的Session必须派生于SendInterceptor,可以返回null(拒绝连接)
|
||||
// 返回的Session必须派生于SendInterceptor,可以返回null(拒绝连接) [AUTO-TRANSLATED:014d6a8a]
|
||||
// The returned Session must inherit from SendInterceptor, can return null (refuse connection)
|
||||
Session::Ptr operator()(const Parser &header, const HttpSession &parent, const Socket::Ptr &pSock, mediakit::WebSocketHeader::Type &type) {
|
||||
// return nullptr;
|
||||
if (header.url() == "/") {
|
||||
// 可以指定传输方式
|
||||
// 可以指定传输方式 [AUTO-TRANSLATED:81ddc417]
|
||||
// Transport method can be specified
|
||||
// type = mediakit::WebSocketHeader::BINARY;
|
||||
return std::make_shared<SessionTypeImp<EchoSession> >(header, parent, pSock);
|
||||
}
|
||||
@@ -93,7 +105,8 @@ struct EchoSessionCreator {
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
//设置日志
|
||||
// 设置日志 [AUTO-TRANSLATED:50372045]
|
||||
// Set log
|
||||
Logger::Instance().add(std::make_shared<ConsoleChannel>());
|
||||
Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
|
||||
|
||||
@@ -101,21 +114,25 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
{
|
||||
TcpServer::Ptr httpSrv(new TcpServer());
|
||||
//http服务器,支持websocket
|
||||
// http服务器,支持websocket [AUTO-TRANSLATED:74a2bdb0]
|
||||
// HTTP server, supports WebSocket
|
||||
httpSrv->start<WebSocketSessionBase<EchoSessionCreator, HttpSession> >(80);//默认80
|
||||
|
||||
TcpServer::Ptr httpsSrv(new TcpServer());
|
||||
//https服务器,支持websocket
|
||||
// https服务器,支持websocket [AUTO-TRANSLATED:bc268bb9]
|
||||
// HTTPS server, supports WebSocket
|
||||
httpsSrv->start<WebSocketSessionBase<EchoSessionCreator, HttpsSession> >(443);//默认443
|
||||
|
||||
TcpServer::Ptr httpSrvOld(new TcpServer());
|
||||
//兼容之前的代码(但是不支持根据url选择生成Session类型)
|
||||
// 兼容之前的代码(但是不支持根据url选择生成Session类型) [AUTO-TRANSLATED:d14395bd]
|
||||
// Compatible with previous code (but does not support generating Session type based on URL)
|
||||
httpSrvOld->start<WebSocketSession<EchoSession, HttpSession> >(8080);
|
||||
|
||||
DebugL << "请打开网页:http://www.websocket-test.com/,进行测试";
|
||||
DebugL << "连接 ws://127.0.0.1/xxxx,ws://127.0.0.1/ 测试的效果将不同,支持根据url选择不同的处理逻辑";
|
||||
|
||||
//设置退出信号处理函数
|
||||
// 设置退出信号处理函数 [AUTO-TRANSLATED:4f047770]
|
||||
// Set exit signal processing function
|
||||
static semaphore sem;
|
||||
signal(SIGINT, [](int) { sem.post(); });// 设置退出信号
|
||||
sem.wait();
|
||||
|
||||
Reference in New Issue
Block a user