Merge remote-tracking branch 'remotes/upstream/master'
This commit is contained in:
commit
4dd02e2de7
|
|
@ -1,2 +1,4 @@
|
|||
release/ filter=lfs diff=lfs merge=lfs -text
|
||||
*.a filter=lfs diff=lfs merge=lfs -text
|
||||
*.h linguist-language=cpp
|
||||
*.c linguist-language=cpp
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
# These are supported funding model platforms
|
||||
custom: ['https://www.paypal.me/xiachu']
|
||||
ko_fi: xiachu
|
||||
issuehunt: xiongziliang
|
||||
liberapay: xiachu
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 665f53b6a4385e2312d3bf09aa305d7e3bf079e6
|
||||
Subproject commit 4a6029b74b4f2339e32b8c546388de51e4ec1bcb
|
||||
|
|
@ -6,12 +6,13 @@ apiDebug=1
|
|||
secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc
|
||||
|
||||
[ffmpeg]
|
||||
#FFmpeg可执行程序路径
|
||||
#FFmpeg可执行程序绝对路径
|
||||
bin=/usr/local/bin/ffmpeg
|
||||
#FFmpeg拉流再推流的命令模板,通过该模板可以设置再编码的一些参数
|
||||
cmd=%s -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s
|
||||
#FFmpeg日志的路径,如果置空则不生成FFmpeg日志
|
||||
log=/Users/xzl/git/ZLMediaKit/release/mac/Release/ffmpeg/ffmpeg.log
|
||||
#可以为相对(相对于本可执行程序目录)或绝对路径
|
||||
log=./ffmpeg/ffmpeg.log
|
||||
|
||||
[general]
|
||||
#是否启用虚拟主机
|
||||
|
|
@ -40,7 +41,8 @@ resetWhenRePlay=1
|
|||
#hls写文件的buf大小,调整参数可以提高文件io性能
|
||||
fileBufSize=65536
|
||||
#hls保存文件路径
|
||||
filePath=/Users/xzl/git/ZLMediaKit/release/mac/Release/httpRoot
|
||||
#可以为相对(相对于本可执行程序目录)或绝对路径
|
||||
filePath=./httpRoot
|
||||
#hls最大切片时间
|
||||
segDur=3
|
||||
#m3u8索引中,hls保留切片个数(实际保留切片个数大2~3个)
|
||||
|
|
@ -93,7 +95,8 @@ notFound=<html><head><title>404 Not Found</title></head><body bgcolor="white"><c
|
|||
#http服务器监听端口
|
||||
port=80
|
||||
#http文件服务器根目录
|
||||
rootPath=/Users/xzl/git/ZLMediaKit/release/mac/Release/httpRoot
|
||||
#可以为相对(相对于本可执行程序目录)或绝对路径
|
||||
rootPath=./httpRoot
|
||||
#http文件服务器读文件缓存大小,单位BYTE,调整该参数可以优化文件io性能
|
||||
sendBufSize=65536
|
||||
#https服务器监听端口
|
||||
|
|
@ -114,7 +117,8 @@ appName=record
|
|||
#mp4录制写文件缓存,单位BYTE,调整参数可以提高文件io性能
|
||||
fileBufSize=65536
|
||||
#mp4录制保存、mp4点播根路径
|
||||
filePath=/Users/xzl/git/ZLMediaKit/release/mac/Release/httpRoot
|
||||
#可以为相对(相对于本可执行程序目录)或绝对路径
|
||||
filePath=./httpRoot
|
||||
#mp4录制切片时间,单位秒
|
||||
fileSecond=3600
|
||||
#mp4点播每次流化数据量,单位毫秒,
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ const char kLog[] = FFmpeg_FIELD"log";
|
|||
onceToken token([]() {
|
||||
mINI::Instance()[kBin] = trim(System::execute("which ffmpeg"));
|
||||
mINI::Instance()[kCmd] = "%s -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s";
|
||||
mINI::Instance()[kLog] = exeDir() + "ffmpeg/ffmpeg.log";
|
||||
mINI::Instance()[kLog] = "./ffmpeg/ffmpeg.log";
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ void FFmpegSource::play(const string &src_url,const string &dst_url,int timeout_
|
|||
|
||||
char cmd[1024] = {0};
|
||||
snprintf(cmd, sizeof(cmd),ffmpeg_cmd.data(),ffmpeg_bin.data(),src_url.data(),dst_url.data());
|
||||
_process.run(cmd,ffmpeg_log);
|
||||
_process.run(cmd,File::absolutePath("",ffmpeg_log));
|
||||
InfoL << cmd;
|
||||
|
||||
if(_media_info._host == "127.0.0.1"){
|
||||
|
|
|
|||
|
|
@ -34,9 +34,8 @@
|
|||
#include "Util/File.h"
|
||||
#include "Util/logger.h"
|
||||
#include "Util/uv_errno.h"
|
||||
#include "Util/TimeTicker.h"
|
||||
#include "Thread/WorkThreadPool.h"
|
||||
#include "Process.h"
|
||||
#include "Poller/Timer.h"
|
||||
using namespace toolkit;
|
||||
|
||||
void Process::run(const string &cmd, const string &log_file_tmp) {
|
||||
|
|
@ -46,12 +45,11 @@ void Process::run(const string &cmd, const string &log_file_tmp) {
|
|||
throw std::runtime_error(StrPrinter << "fork child process falied,err:" << get_uv_errmsg());
|
||||
}
|
||||
if (_pid == 0) {
|
||||
//子进程
|
||||
|
||||
//子进程关闭core文件生成
|
||||
struct rlimit rlim = {0,0};
|
||||
setrlimit(RLIMIT_CORE, &rlim);
|
||||
|
||||
//在启动子进程时,暂时禁用SIGINT、SIGTERM信号
|
||||
// ignore the SIGINT and SIGTERM
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
|
|
@ -109,24 +107,73 @@ void Process::run(const string &cmd, const string &log_file_tmp) {
|
|||
InfoL << "start child proces " << _pid;
|
||||
}
|
||||
|
||||
void Process::kill(int max_delay) {
|
||||
|
||||
/**
|
||||
* 获取进程是否存活状态
|
||||
* @param pid 进程号
|
||||
* @param exit_code_ptr 进程返回代码
|
||||
* @param block 是否阻塞等待
|
||||
* @return 进程是否还在运行
|
||||
*/
|
||||
static bool s_wait(pid_t pid,int *exit_code_ptr,bool block) {
|
||||
if (pid <= 0) {
|
||||
return false;
|
||||
}
|
||||
int status = 0;
|
||||
pid_t p = waitpid(pid, &status, block ? 0 : WNOHANG);
|
||||
int exit_code = (status & 0xFF00) >> 8;
|
||||
if(exit_code_ptr){
|
||||
*exit_code_ptr = (status & 0xFF00) >> 8;
|
||||
}
|
||||
if (p < 0) {
|
||||
WarnL << "waitpid failed, pid=" << pid << ", err=" << get_uv_errmsg();
|
||||
return false;
|
||||
}
|
||||
if (p > 0) {
|
||||
InfoL << "process terminated, pid=" << pid << ", exit code=" << exit_code;
|
||||
return false;
|
||||
}
|
||||
//WarnL << "process is running, pid=" << _pid;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void s_kill(pid_t pid,int max_delay,bool force){
|
||||
if (pid <= 0) {
|
||||
//pid无效
|
||||
return;
|
||||
}
|
||||
|
||||
if (::kill(pid, force ? SIGKILL : SIGTERM) == -1) {
|
||||
//进程可能已经退出了
|
||||
WarnL << "kill process " << pid << " failed:" << get_uv_errmsg();
|
||||
return;
|
||||
}
|
||||
|
||||
if(force){
|
||||
//发送SIGKILL信号后,阻塞等待退出
|
||||
s_wait(pid, NULL, true);
|
||||
DebugL << "force kill " << pid << " success!";
|
||||
return;
|
||||
}
|
||||
|
||||
//发送SIGTERM信号后,2秒后检查子进程是否已经退出
|
||||
WorkThreadPool::Instance().getPoller()->doDelayTask(max_delay,[pid](){
|
||||
if (!s_wait(pid, nullptr, false)) {
|
||||
//进程已经退出了
|
||||
return 0;
|
||||
}
|
||||
//进程还在运行
|
||||
WarnL << "process still working,force kill it:" << pid;
|
||||
s_kill(pid,0, true);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
void Process::kill(int max_delay,bool force) {
|
||||
if (_pid <= 0) {
|
||||
return;
|
||||
}
|
||||
if (::kill(_pid, SIGTERM) == -1) {
|
||||
WarnL << "kill process " << _pid << " falied,err:" << get_uv_errmsg();
|
||||
} else {
|
||||
//等待子进程退出
|
||||
auto pid = _pid;
|
||||
EventPollerPool::Instance().getPoller()->doDelayTask(max_delay,[pid](){
|
||||
//最多等待2秒,2秒后强制杀掉程序
|
||||
if (waitpid(pid, NULL, WNOHANG) == 0) {
|
||||
::kill(pid, SIGKILL);
|
||||
WarnL << "force kill process " << pid;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
s_kill(_pid,max_delay,force);
|
||||
_pid = -1;
|
||||
}
|
||||
|
||||
|
|
@ -134,28 +181,10 @@ Process::~Process() {
|
|||
kill(2000);
|
||||
}
|
||||
|
||||
Process::Process() {
|
||||
}
|
||||
Process::Process() {}
|
||||
|
||||
bool Process::wait(bool block) {
|
||||
if (_pid <= 0) {
|
||||
return false;
|
||||
}
|
||||
int status = 0;
|
||||
pid_t p = waitpid(_pid, &status, block ? 0 : WNOHANG);
|
||||
|
||||
_exit_code = (status & 0xFF00) >> 8;
|
||||
if (p < 0) {
|
||||
WarnL << "waitpid failed, pid=" << _pid << ", err=" << get_uv_errmsg();
|
||||
return false;
|
||||
}
|
||||
if (p > 0) {
|
||||
InfoL << "process terminated, pid=" << _pid << ", exit code=" << _exit_code;
|
||||
return false;
|
||||
}
|
||||
|
||||
//WarnL << "process is running, pid=" << _pid;
|
||||
return true;
|
||||
return s_wait(_pid,&_exit_code,block);
|
||||
}
|
||||
|
||||
int Process::exit_code() {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public:
|
|||
Process();
|
||||
~Process();
|
||||
void run(const string &cmd,const string &log_file);
|
||||
void kill(int max_delay);
|
||||
void kill(int max_delay,bool force = false);
|
||||
bool wait(bool block = true);
|
||||
int exit_code();
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include "Util/MD5.h"
|
||||
#include "WebApi.h"
|
||||
#include "WebHook.h"
|
||||
#include "Thread/WorkThreadPool.h"
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include "FFmpegSource.h"
|
||||
|
|
@ -281,6 +282,23 @@ void installWebApi() {
|
|||
});
|
||||
});
|
||||
|
||||
//获取后台工作线程负载
|
||||
//测试url http://127.0.0.1/index/api/getWorkThreadsLoad
|
||||
API_REGIST_INVOKER(api, getWorkThreadsLoad, {
|
||||
WorkThreadPool::Instance().getExecutorDelay([invoker, headerOut](const vector<int> &vecDelay) {
|
||||
Value val;
|
||||
auto vec = WorkThreadPool::Instance().getExecutorLoad();
|
||||
int i = 0;
|
||||
for (auto load : vec) {
|
||||
Value obj(objectValue);
|
||||
obj["load"] = load;
|
||||
obj["delay"] = vecDelay[i++];
|
||||
val["data"].append(obj);
|
||||
}
|
||||
invoker("200 OK", headerOut, val.toStyledString());
|
||||
});
|
||||
});
|
||||
|
||||
//获取服务器配置
|
||||
//测试url http://127.0.0.1/index/api/getServerConfig
|
||||
API_REGIST(api, getServerConfig, {
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ const string kMaxReqCount = HTTP_FIELD"maxReqCount";
|
|||
const string kCharSet = HTTP_FIELD"charSet";
|
||||
|
||||
//http 服务器根目录
|
||||
#define HTTP_ROOT_PATH (exeDir() + "httpRoot")
|
||||
#define HTTP_ROOT_PATH "./httpRoot"
|
||||
const string kRootPath = HTTP_FIELD"rootPath";
|
||||
|
||||
//http 404错误提示内容
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
|
|||
aac_cfg_str = FindField(track->_fmtp.data(), "config=", ";");
|
||||
}
|
||||
if (aac_cfg_str.empty()) {
|
||||
//延后获取adts头
|
||||
return std::make_shared<AACTrack>();
|
||||
//如果sdp中获取不到aac config信息,那么在rtp也无法获取,那么忽略该Track
|
||||
return nullptr;
|
||||
}
|
||||
string aac_cfg;
|
||||
|
||||
|
|
|
|||
|
|
@ -169,21 +169,32 @@ void HttpSession::onRecv(const Buffer::Ptr &pBuf) {
|
|||
}
|
||||
|
||||
void HttpSession::onError(const SockException& err) {
|
||||
if(_is_flv_stream){
|
||||
//flv播放器
|
||||
WarnP(this) << "播放器("
|
||||
<< _mediaInfo._vhost << "/"
|
||||
<< _mediaInfo._app << "/"
|
||||
<< _mediaInfo._streamid
|
||||
<< ")断开:" << err.what();
|
||||
|
||||
GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold);
|
||||
if(_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
|
||||
_mediaInfo,
|
||||
_ui64TotalBytes,
|
||||
_ticker.createdTime()/1000,
|
||||
true,
|
||||
*this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//http客户端
|
||||
if(_ticker.createdTime() < 10 * 1000){
|
||||
TraceP(this) << err.what();
|
||||
}else{
|
||||
WarnP(this) << err.what();
|
||||
}
|
||||
|
||||
GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold);
|
||||
if(_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
|
||||
_mediaInfo,
|
||||
_ui64TotalBytes,
|
||||
_ticker.createdTime()/1000,
|
||||
true,
|
||||
*this);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpSession::onManager() {
|
||||
|
|
@ -291,6 +302,7 @@ bool HttpSession::checkLiveFlvStream(const function<void()> &cb){
|
|||
|
||||
try{
|
||||
start(getPoller(),rtmp_src);
|
||||
_is_flv_stream = true;
|
||||
}catch (std::exception &ex){
|
||||
//该rtmp源不存在
|
||||
shutdown(SockException(Err_shutdown,"rtmp mediasource released"));
|
||||
|
|
@ -375,10 +387,7 @@ static bool checkHls(BroadcastHttpAccessArgs){
|
|||
return NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed,args_copy,mediaAuthInvoker,sender);
|
||||
}
|
||||
|
||||
void HttpSession::canAccessPath(const string &path_in,bool is_dir,const function<void(const string &errMsg,const HttpServerCookie::Ptr &cookie)> &callback_in){
|
||||
auto path = path_in;
|
||||
replace(const_cast<string &>(path),"//","/");
|
||||
|
||||
void HttpSession::canAccessPath(const string &path,bool is_dir,const function<void(const string &errMsg,const HttpServerCookie::Ptr &cookie)> &callback_in){
|
||||
auto callback = [callback_in,this](const string &errMsg,const HttpServerCookie::Ptr &cookie){
|
||||
try {
|
||||
callback_in(errMsg,cookie);
|
||||
|
|
@ -507,7 +516,7 @@ void HttpSession::Handle_Req_GET(int64_t &content_len) {
|
|||
GET_CONFIG(uint32_t,reqCnt,Http::kMaxReqCount);
|
||||
GET_CONFIG(bool,enableVhost,General::kEnableVhost);
|
||||
GET_CONFIG(string,rootPath,Http::kRootPath);
|
||||
string strFile = enableVhost ? rootPath + "/" + _mediaInfo._vhost + _parser.Url() :rootPath + _parser.Url();
|
||||
auto strFile = File::absolutePath(enableVhost ? _mediaInfo._vhost + _parser.Url() : _parser.Url(),rootPath);
|
||||
bool bClose = (strcasecmp(_parser["Connection"].data(),"close") == 0) || ( ++_iReqCnt > reqCnt);
|
||||
|
||||
do{
|
||||
|
|
|
|||
|
|
@ -160,6 +160,7 @@ private:
|
|||
//处理content数据的callback
|
||||
function<bool (const char *data,uint64_t len) > _contentCallBack;
|
||||
bool _flv_over_websocket = false;
|
||||
bool _is_flv_stream = false;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -153,6 +153,14 @@ void MP4Recorder::onTrackReady(const Track::Ptr & track){
|
|||
}
|
||||
}
|
||||
|
||||
void MP4Recorder::resetTracks() {
|
||||
closeFile();
|
||||
_tracks.clear();
|
||||
_haveVideo = false;
|
||||
_createFileTicker.resetTime();
|
||||
MediaSink::resetTracks();
|
||||
}
|
||||
|
||||
} /* namespace mediakit */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,11 @@ public:
|
|||
const string &strApp,
|
||||
const string &strStreamId);
|
||||
virtual ~MP4Recorder();
|
||||
|
||||
/**
|
||||
* 重置所有Track
|
||||
*/
|
||||
void resetTracks() override;
|
||||
private:
|
||||
/**
|
||||
* 某Track输出frame,在onAllTrackReady触发后才会调用此方法
|
||||
|
|
|
|||
|
|
@ -44,10 +44,11 @@ MediaReader::MediaReader(const string &strVhost,const string &strApp, const stri
|
|||
GET_CONFIG(string,recordPath,Record::kFilePath);
|
||||
GET_CONFIG(bool,enableVhost,General::kEnableVhost);
|
||||
if(enableVhost){
|
||||
strFileName = recordPath + "/" + strVhost + "/" + strApp + "/" + strId;
|
||||
strFileName = strVhost + "/" + strApp + "/" + strId;
|
||||
}else{
|
||||
strFileName = recordPath + "/" + strApp + "/" + strId;
|
||||
strFileName = strApp + "/" + strId;
|
||||
}
|
||||
strFileName = File::absolutePath(strFileName,recordPath);
|
||||
}
|
||||
|
||||
_hMP4File = MP4Read(strFileName.data());
|
||||
|
|
|
|||
|
|
@ -56,13 +56,15 @@ MediaRecorder::MediaRecorder(const string &strVhost_tmp,
|
|||
#if defined(ENABLE_HLS)
|
||||
if(enableHls) {
|
||||
string m3u8FilePath;
|
||||
string params;
|
||||
if(enableVhost){
|
||||
m3u8FilePath = hlsPath + "/" + strVhost + "/" + strApp + "/" + strId + "/hls.m3u8";
|
||||
_hlsRecorder.reset(new HlsRecorder(m3u8FilePath,string(VHOST_KEY) + "=" + strVhost ,hlsBufSize, hlsDuration, hlsNum));
|
||||
m3u8FilePath = strVhost + "/" + strApp + "/" + strId + "/hls.m3u8";
|
||||
params = string(VHOST_KEY) + "=" + strVhost;
|
||||
}else{
|
||||
m3u8FilePath = hlsPath + "/" + strApp + "/" + strId + "/hls.m3u8";
|
||||
_hlsRecorder.reset(new HlsRecorder(m3u8FilePath,"",hlsBufSize, hlsDuration, hlsNum));
|
||||
m3u8FilePath = strApp + "/" + strId + "/hls.m3u8";
|
||||
}
|
||||
m3u8FilePath = File::absolutePath(m3u8FilePath,hlsPath);
|
||||
_hlsRecorder.reset(new HlsRecorder(m3u8FilePath,params,hlsBufSize, hlsDuration, hlsNum));
|
||||
}
|
||||
#endif //defined(ENABLE_HLS)
|
||||
|
||||
|
|
@ -73,10 +75,11 @@ MediaRecorder::MediaRecorder(const string &strVhost_tmp,
|
|||
if(enableMp4){
|
||||
string mp4FilePath;
|
||||
if(enableVhost){
|
||||
mp4FilePath = recordPath + "/" + strVhost + "/" + recordAppName + "/" + strApp + "/" + strId + "/";
|
||||
mp4FilePath = strVhost + "/" + recordAppName + "/" + strApp + "/" + strId + "/";
|
||||
} else {
|
||||
mp4FilePath = recordPath + "/" + recordAppName + "/" + strApp + "/" + strId + "/";
|
||||
mp4FilePath = recordAppName + "/" + strApp + "/" + strId + "/";
|
||||
}
|
||||
mp4FilePath = File::absolutePath(mp4FilePath,recordPath);
|
||||
_mp4Recorder.reset(new MP4Recorder(mp4FilePath,strVhost,strApp,strId));
|
||||
}
|
||||
#endif //defined(ENABLE_MP4RECORD)
|
||||
|
|
|
|||
|
|
@ -44,13 +44,17 @@ RtmpSession::~RtmpSession() {
|
|||
}
|
||||
|
||||
void RtmpSession::onError(const SockException& err) {
|
||||
WarnP(this) << err.what();
|
||||
bool isPlayer = !_pPublisherSrc;
|
||||
WarnP(this) << (isPlayer ? "播放器(" : "推流器(")
|
||||
<< _mediaInfo._vhost << "/"
|
||||
<< _mediaInfo._app << "/"
|
||||
<< _mediaInfo._streamid
|
||||
<< ")断开:" << err.what();
|
||||
|
||||
//流量统计事件广播
|
||||
GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold);
|
||||
|
||||
if(_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
bool isPlayer = !_pPublisherSrc;
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
|
||||
_mediaInfo,
|
||||
_ui64TotalBytes,
|
||||
|
|
|
|||
|
|
@ -85,7 +85,13 @@ RtspSession::~RtspSession() {
|
|||
}
|
||||
|
||||
void RtspSession::onError(const SockException& err) {
|
||||
WarnP(this) << err.what();
|
||||
bool isPlayer = !_pushSrc;
|
||||
WarnP(this) << (isPlayer ? "播放器(" : "推流器(")
|
||||
<< _mediaInfo._vhost << "/"
|
||||
<< _mediaInfo._app << "/"
|
||||
<< _mediaInfo._streamid
|
||||
<< ")断开:" << err.what();
|
||||
|
||||
if (_rtpType == Rtsp::RTP_MULTICAST) {
|
||||
//取消UDP端口监听
|
||||
UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this);
|
||||
|
|
@ -100,7 +106,6 @@ void RtspSession::onError(const SockException& err) {
|
|||
//流量统计事件广播
|
||||
GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold);
|
||||
if(_ui64TotalBytes > iFlowThreshold * 1024){
|
||||
bool isPlayer = !_pushSrc;
|
||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport,
|
||||
_mediaInfo,
|
||||
_ui64TotalBytes,
|
||||
|
|
|
|||
Loading…
Reference in New Issue