Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
Z
ZLMediaKit
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
张翔宇
ZLMediaKit
Commits
999e0b27
Commit
999e0b27
authored
Sep 07, 2022
by
cqm
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
简化代码:
- MediaSource引入shortUrl和getUrl来简化日志输出 - WebApi引入fillSockInfo
parent
4f47b7a5
隐藏空白字符变更
内嵌
并排
正在显示
19 个修改的文件
包含
114 行增加
和
165 行删除
+114
-165
api/source/mk_media.cpp
+1
-1
server/WebApi.cpp
+12
-16
src/Common/MediaSource.cpp
+26
-34
src/Common/MediaSource.h
+21
-14
src/Http/HttpSession.cpp
+1
-3
src/Player/PlayerProxy.cpp
+1
-1
src/Record/HlsMediaSource.cpp
+1
-2
src/Record/MP4Reader.cpp
+1
-1
src/Record/MP4Recorder.cpp
+1
-0
src/Rtmp/RtmpSession.cpp
+4
-9
src/Rtp/RtpProcess.cpp
+2
-4
src/Rtp/RtpSelector.cpp
+1
-1
src/Rtp/RtpSession.cpp
+1
-1
src/Rtsp/RtspSession.cpp
+4
-8
src/Shell/ShellCMD.h
+3
-18
srt/SrtTransportImp.cpp
+3
-6
tests/test_server.cpp
+28
-38
webrtc/WebRtcPlayer.cpp
+1
-3
webrtc/WebRtcPusher.cpp
+2
-5
没有找到文件。
api/source/mk_media.cpp
查看文件 @
999e0b27
...
...
@@ -72,7 +72,7 @@ protected:
}
//请在回调中调用mk_media_release函数释放资源,否则MediaSource::close()操作不会生效
_on_close
(
_on_close_data
);
WarnL
<<
"close media:"
<<
sender
.
get
Schema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
WarnL
<<
"close media:"
<<
sender
.
get
Url
()
<<
" "
<<
force
;
return
true
;
}
...
...
server/WebApi.cpp
查看文件 @
999e0b27
...
...
@@ -312,6 +312,14 @@ static inline string getPusherKey(const string &schema, const string &vhost, con
return
schema
+
"/"
+
vhost
+
"/"
+
app
+
"/"
+
stream
+
"/"
+
MD5
(
dst_url
).
hexdigest
();
}
static
void
fillSockInfo
(
Value
&
val
,
SockInfo
*
info
)
{
val
[
"peer_ip"
]
=
info
->
get_peer_ip
();
val
[
"peer_port"
]
=
info
->
get_peer_port
();
val
[
"local_port"
]
=
info
->
get_local_port
();
val
[
"local_ip"
]
=
info
->
get_local_ip
();
val
[
"identifier"
]
=
info
->
getIdentifier
();
}
Value
makeMediaSourceJson
(
MediaSource
&
media
){
Value
item
;
item
[
"schema"
]
=
media
.
getSchema
();
...
...
@@ -330,11 +338,7 @@ Value makeMediaSourceJson(MediaSource &media){
item
[
"isRecordingHLS"
]
=
media
.
isRecording
(
Recorder
::
type_hls
);
auto
originSock
=
media
.
getOriginSock
();
if
(
originSock
)
{
item
[
"originSock"
][
"local_ip"
]
=
originSock
->
get_local_ip
();
item
[
"originSock"
][
"local_port"
]
=
originSock
->
get_local_port
();
item
[
"originSock"
][
"peer_ip"
]
=
originSock
->
get_peer_ip
();
item
[
"originSock"
][
"peer_port"
]
=
originSock
->
get_peer_port
();
item
[
"originSock"
][
"identifier"
]
=
originSock
->
getIdentifier
();
fillSockInfo
(
item
[
"originSock"
],
originSock
.
get
());
}
else
{
item
[
"originSock"
]
=
Json
::
nullValue
;
}
...
...
@@ -772,9 +776,7 @@ void installWebApi() {
[](
std
::
shared_ptr
<
void
>
&&
info
)
->
std
::
shared_ptr
<
void
>
{
auto
obj
=
std
::
make_shared
<
Value
>
();
auto
session
=
static_pointer_cast
<
Session
>
(
info
);
(
*
obj
)[
"peer_ip"
]
=
session
->
get_peer_ip
();
(
*
obj
)[
"peer_port"
]
=
session
->
get_peer_port
();
(
*
obj
)[
"id"
]
=
session
->
getIdentifier
();
fillSockInfo
(
*
obj
,
session
.
get
());
(
*
obj
)[
"typeid"
]
=
toolkit
::
demangle
(
typeid
(
*
session
).
name
());
return
obj
;
});
...
...
@@ -858,10 +860,7 @@ void installWebApi() {
if
(
!
peer_ip
.
empty
()
&&
peer_ip
!=
session
->
get_peer_ip
()){
return
;
}
jsession
[
"peer_ip"
]
=
session
->
get_peer_ip
();
jsession
[
"peer_port"
]
=
session
->
get_peer_port
();
jsession
[
"local_ip"
]
=
session
->
get_local_ip
();
jsession
[
"local_port"
]
=
session
->
get_local_port
();
fillSockInfo
(
jsession
,
session
.
get
());
jsession
[
"id"
]
=
id
;
jsession
[
"typeid"
]
=
toolkit
::
demangle
(
typeid
(
*
session
).
name
());
val
[
"data"
].
append
(
jsession
);
...
...
@@ -1127,10 +1126,7 @@ void installWebApi() {
return
;
}
val
[
"exist"
]
=
true
;
val
[
"peer_ip"
]
=
process
->
get_peer_ip
();
val
[
"peer_port"
]
=
process
->
get_peer_port
();
val
[
"local_port"
]
=
process
->
get_local_port
();
val
[
"local_ip"
]
=
process
->
get_local_ip
();
fillSockInfo
(
val
,
process
.
get
());
});
api_regist
(
"/index/api/openRtpServer"
,[](
API_ARGS_MAP
){
...
...
src/Common/MediaSource.cpp
查看文件 @
999e0b27
...
...
@@ -13,6 +13,7 @@
#include "Util/util.h"
#include "Network/sockutil.h"
#include "Network/TcpSession.h"
#include "Util/NoticeCenter.h"
using
namespace
std
;
using
namespace
toolkit
;
...
...
@@ -24,7 +25,11 @@ namespace toolkit {
namespace
mediakit
{
static
recursive_mutex
s_media_source_mtx
;
static
MediaSource
::
SchemaVhostAppStreamMap
s_media_source_map
;
using
StreamMap
=
unordered_map
<
string
/*strema_id*/
,
weak_ptr
<
MediaSource
>
>
;
using
AppStreamMap
=
unordered_map
<
string
/*app*/
,
StreamMap
>
;
using
VhostAppStreamMap
=
unordered_map
<
string
/*vhost*/
,
AppStreamMap
>
;
using
SchemaVhostAppStreamMap
=
unordered_map
<
string
/*schema*/
,
VhostAppStreamMap
>
;
static
SchemaVhostAppStreamMap
s_media_source_map
;
string
getOriginTypeString
(
MediaOriginType
type
){
#define SWITCH_CASE(type) case MediaOriginType::type : return #type
...
...
@@ -43,10 +48,6 @@ string getOriginTypeString(MediaOriginType type){
}
}
static
string
getOriginUrl_l
(
const
MediaSource
*
thiz
)
{
return
thiz
->
getSchema
()
+
"://"
+
thiz
->
getVhost
()
+
"/"
+
thiz
->
getApp
()
+
"/"
+
thiz
->
getId
();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct
MediaSourceNull
:
public
MediaSource
{
MediaSourceNull
()
:
MediaSource
(
"schema"
,
"vhost"
,
"app"
,
"stream"
)
{};
...
...
@@ -109,16 +110,12 @@ std::shared_ptr<void> MediaSource::getOwnership() {
}
int
MediaSource
::
getBytesSpeed
(
TrackType
type
){
if
(
type
==
TrackInvalid
){
if
(
type
==
TrackInvalid
||
type
==
TrackMax
){
return
_speed
[
TrackVideo
].
getSpeed
()
+
_speed
[
TrackAudio
].
getSpeed
();
}
return
_speed
[
type
].
getSpeed
();
}
uint64_t
MediaSource
::
getCreateStamp
()
const
{
return
_create_stamp
;
}
uint64_t
MediaSource
::
getAliveSecond
()
const
{
//使用Ticker对象获取存活时间的目的是防止修改系统时间导致回退
return
_ticker
.
createdTime
()
/
1000
;
...
...
@@ -140,6 +137,7 @@ std::weak_ptr<MediaSourceEvent> MediaSource::getListener(bool next) const{
if
(
!
next
)
{
return
_listener
;
}
auto
listener
=
dynamic_pointer_cast
<
MediaSourceEventInterceptor
>
(
_listener
.
lock
());
if
(
!
listener
)
{
//不是MediaSourceEventInterceptor对象或者对象已经销毁
...
...
@@ -170,13 +168,13 @@ MediaOriginType MediaSource::getOriginType() const {
string
MediaSource
::
getOriginUrl
()
const
{
auto
listener
=
_listener
.
lock
();
if
(
!
listener
)
{
return
get
OriginUrl_l
(
this
);
return
get
Url
(
);
}
auto
ret
=
listener
->
getOriginUrl
(
const_cast
<
MediaSource
&>
(
*
this
));
if
(
!
ret
.
empty
())
{
return
ret
;
}
return
get
OriginUrl_l
(
this
);
return
get
Url
(
);
}
std
::
shared_ptr
<
SockInfo
>
MediaSource
::
getOriginSock
()
const
{
...
...
@@ -253,7 +251,7 @@ void MediaSource::onReaderChanged(int size) {
bool
MediaSource
::
setupRecord
(
Recorder
::
type
type
,
bool
start
,
const
string
&
custom_path
,
size_t
max_second
){
auto
listener
=
_listener
.
lock
();
if
(
!
listener
)
{
WarnL
<<
"未设置MediaSource的事件监听者,setupRecord失败:"
<<
get
Schema
()
<<
"/"
<<
getVhost
()
<<
"/"
<<
getApp
()
<<
"/"
<<
getId
();
WarnL
<<
"未设置MediaSource的事件监听者,setupRecord失败:"
<<
get
Url
();
return
false
;
}
return
listener
->
setupRecord
(
*
this
,
type
,
start
,
custom_path
,
max_second
);
...
...
@@ -337,7 +335,7 @@ void MediaSource::for_each_media(const function<void(const Ptr &src)> &cb,
static
MediaSource
::
Ptr
find_l
(
const
string
&
schema
,
const
string
&
vhost_in
,
const
string
&
app
,
const
string
&
id
,
bool
from_mp4
)
{
string
vhost
=
vhost_in
;
GET_CONFIG
(
bool
,
enableVhost
,
General
::
kEnableVhost
);
GET_CONFIG
(
bool
,
enableVhost
,
General
::
kEnableVhost
);
if
(
vhost
.
empty
()
||
!
enableVhost
){
vhost
=
DEFAULT_VHOST
;
}
...
...
@@ -351,7 +349,7 @@ static MediaSource::Ptr find_l(const string &schema, const string &vhost_in, con
MediaSource
::
for_each_media
([
&
](
const
MediaSource
::
Ptr
&
src
)
{
ret
=
std
::
move
(
const_cast
<
MediaSource
::
Ptr
&>
(
src
));
},
schema
,
vhost
,
app
,
id
);
if
(
!
ret
&&
from_mp4
&&
schema
!=
HLS_SCHEMA
){
//未
查找
媒体源,则读取mp4创建一个
//未
找到
媒体源,则读取mp4创建一个
//播放hls不触发mp4点播(因为HLS也可以用于录像,不是纯粹的直播)
ret
=
MediaSource
::
createFromMP4
(
schema
,
vhost
,
app
,
id
);
}
...
...
@@ -379,7 +377,7 @@ static void findAsync_l(const MediaInfo &info, const std::shared_ptr<Session> &s
};
auto
on_timeout
=
poller
->
doDelayTask
(
maxWaitMS
,
[
cb_once
,
listener_tag
]()
{
//
最多等待一定时间,如果这个时间内,流未注册上,那么返回未找到流
//
最多等待一定时间,如在这个时间内,流还未注册上,则返回空
NoticeCenter
::
Instance
().
delListener
(
listener_tag
,
Broadcast
::
kBroadcastMediaChanged
);
cb_once
(
nullptr
);
return
0
;
...
...
@@ -402,17 +400,15 @@ static void findAsync_l(const MediaInfo &info, const std::shared_ptr<Session> &s
//不是自己感兴趣的事件,忽略之
return
;
}
poller
->
async
([
weak_session
,
cancel_all
,
info
,
cb_once
]()
{
cancel_all
();
auto
strong_session
=
weak_session
.
lock
();
if
(
!
strong_session
)
{
//自己已经销毁
return
;
if
(
auto
strong_session
=
weak_session
.
lock
())
{
//播发器请求的流终于注册上了,切换到自己的线程再回复
DebugL
<<
"收到媒体注册事件,回复播放器:"
<<
info
.
getUrl
();
//再找一遍媒体源,一般能找到
findAsync_l
(
info
,
strong_session
,
false
,
cb_once
);
}
//播发器请求的流终于注册上了,切换到自己的线程再回复
DebugL
<<
"收到媒体注册事件,回复播放器:"
<<
info
.
_schema
<<
"/"
<<
info
.
_vhost
<<
"/"
<<
info
.
_app
<<
"/"
<<
info
.
_streamid
;
//再找一遍媒体源,一般能找到
findAsync_l
(
info
,
strong_session
,
false
,
cb_once
);
},
false
);
};
...
...
@@ -458,7 +454,7 @@ void MediaSource::emitEvent(bool regist){
}
//触发广播
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastMediaChanged
,
regist
,
*
this
);
InfoL
<<
(
regist
?
"媒体注册:"
:
"媒体注销:"
)
<<
_schema
<<
" "
<<
_vhost
<<
" "
<<
_app
<<
" "
<<
_stream_id
;
InfoL
<<
(
regist
?
"媒体注册:"
:
"媒体注销:"
)
<<
getUrl
()
;
}
void
MediaSource
::
regist
()
{
...
...
@@ -472,7 +468,7 @@ void MediaSource::regist() {
return
;
}
//增加判断, 防止当前流已注册时再次注册
throw
std
::
invalid_argument
(
"media source already existed:"
+
_schema
+
"/"
+
_vhost
+
"/"
+
_app
+
"/"
+
_stream_id
);
throw
std
::
invalid_argument
(
"media source already existed:"
+
getUrl
()
);
}
ref
=
shared_from_this
();
}
...
...
@@ -519,9 +515,9 @@ bool MediaSource::unregist() {
/////////////////////////////////////MediaInfo//////////////////////////////////////
void
MediaInfo
::
parse
(
const
string
&
url_in
){
void
MediaInfo
::
parse
(
const
st
d
::
st
ring
&
url_in
){
_full_url
=
url_in
;
string
url
=
url_in
;
auto
url
=
url_in
;
auto
pos
=
url
.
find
(
"?"
);
if
(
pos
!=
string
::
npos
)
{
_param_strs
=
url
.
substr
(
pos
+
1
);
...
...
@@ -621,11 +617,7 @@ void MediaSourceEvent::onReaderChanged(MediaSource &sender, int size){
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastStreamNoneReader
,
*
strong_sender
);
}
else
{
//这个是mp4点播,我们自动关闭
WarnL
<<
"MP4点播无人观看,自动关闭:"
<<
strong_sender
->
getSchema
()
<<
"/"
<<
strong_sender
->
getVhost
()
<<
"/"
<<
strong_sender
->
getApp
()
<<
"/"
<<
strong_sender
->
getId
();
WarnL
<<
"MP4点播无人观看,自动关闭:"
<<
strong_sender
->
getUrl
();
strong_sender
->
close
(
false
);
}
return
false
;
...
...
@@ -633,7 +625,7 @@ void MediaSourceEvent::onReaderChanged(MediaSource &sender, int size){
}
string
MediaSourceEvent
::
getOriginUrl
(
MediaSource
&
sender
)
const
{
return
getOriginUrl_l
(
&
sender
);
return
sender
.
getUrl
(
);
}
MediaOriginType
MediaSourceEventInterceptor
::
getOriginType
(
MediaSource
&
sender
)
const
{
...
...
src/Common/MediaSource.h
查看文件 @
999e0b27
...
...
@@ -19,13 +19,8 @@
#include <unordered_map>
#include "Common/config.h"
#include "Common/Parser.h"
#include "Util/logger.h"
#include "Util/TimeTicker.h"
#include "Util/NoticeCenter.h"
#include "Util/List.h"
#include "Network/Socket.h"
#include "Rtsp/Rtsp.h"
#include "Rtmp/Rtmp.h"
#include "Extension/Track.h"
#include "Record/Recorder.h"
...
...
@@ -85,7 +80,7 @@ public:
// 通知观看人数变化
virtual
void
onReaderChanged
(
MediaSource
&
sender
,
int
size
);
//流注册或注销事件
virtual
void
onRegist
(
MediaSource
&
sender
,
bool
regist
)
{}
;
virtual
void
onRegist
(
MediaSource
&
sender
,
bool
regist
)
{}
// 获取丢包率
virtual
float
getLossRate
(
MediaSource
&
sender
,
TrackType
type
)
{
return
-
1
;
}
// 获取所在线程, 此函数一般强制重载
...
...
@@ -95,7 +90,7 @@ public:
// 开启或关闭录制
virtual
bool
setupRecord
(
MediaSource
&
sender
,
Recorder
::
type
type
,
bool
start
,
const
std
::
string
&
custom_path
,
size_t
max_second
)
{
return
false
;
};
// 获取录制状态
virtual
bool
isRecording
(
MediaSource
&
sender
,
Recorder
::
type
type
)
{
return
false
;
}
;
virtual
bool
isRecording
(
MediaSource
&
sender
,
Recorder
::
type
type
)
{
return
false
;
}
// 获取所有track相关信息
virtual
std
::
vector
<
Track
::
Ptr
>
getMediaTracks
(
MediaSource
&
sender
,
bool
trackReady
=
true
)
const
{
return
std
::
vector
<
Track
::
Ptr
>
();
};
...
...
@@ -180,7 +175,12 @@ public:
MediaInfo
()
{}
MediaInfo
(
const
std
::
string
&
url
)
{
parse
(
url
);
}
void
parse
(
const
std
::
string
&
url
);
std
::
string
shortUrl
()
const
{
return
_vhost
+
"/"
+
_app
+
"/"
+
_streamid
;
}
std
::
string
getUrl
()
const
{
return
_schema
+
"://"
+
shortUrl
();
}
public
:
std
::
string
_full_url
;
std
::
string
_schema
;
...
...
@@ -199,10 +199,6 @@ class MediaSource: public TrackSource, public std::enable_shared_from_this<Media
public
:
static
MediaSource
&
NullMediaSource
();
using
Ptr
=
std
::
shared_ptr
<
MediaSource
>
;
using
StreamMap
=
std
::
unordered_map
<
std
::
string
/*stream_id*/
,
std
::
weak_ptr
<
MediaSource
>
>
;
using
AppStreamMap
=
std
::
unordered_map
<
std
::
string
/*app*/
,
StreamMap
>
;
using
VhostAppStreamMap
=
std
::
unordered_map
<
std
::
string
/*vhost*/
,
AppStreamMap
>
;
using
SchemaVhostAppStreamMap
=
std
::
unordered_map
<
std
::
string
/*schema*/
,
VhostAppStreamMap
>
;
MediaSource
(
const
std
::
string
&
schema
,
const
std
::
string
&
vhost
,
const
std
::
string
&
app
,
const
std
::
string
&
stream_id
)
;
virtual
~
MediaSource
();
...
...
@@ -218,6 +214,13 @@ public:
// 流id
const
std
::
string
&
getId
()
const
;
std
::
string
shortUrl
()
const
{
return
_vhost
+
"/"
+
_app
+
"/"
+
_stream_id
;
}
std
::
string
getUrl
()
const
{
return
_schema
+
"://"
+
shortUrl
();
}
//获取对象所有权
std
::
shared_ptr
<
void
>
getOwnership
();
...
...
@@ -232,7 +235,7 @@ public:
// 获取数据速率,单位bytes/s
int
getBytesSpeed
(
TrackType
type
=
TrackInvalid
);
// 获取流创建GMT unix时间戳,单位秒
uint64_t
getCreateStamp
()
const
;
uint64_t
getCreateStamp
()
const
{
return
_create_stamp
;}
// 获取流上线时间,单位秒
uint64_t
getAliveSecond
()
const
;
...
...
@@ -288,8 +291,11 @@ public:
// 同步查找流
static
Ptr
find
(
const
std
::
string
&
schema
,
const
std
::
string
&
vhost
,
const
std
::
string
&
app
,
const
std
::
string
&
id
,
bool
from_mp4
=
false
);
static
Ptr
find
(
const
MediaInfo
&
info
,
bool
from_mp4
=
false
)
{
return
find
(
info
.
_schema
,
info
.
_vhost
,
info
.
_app
,
info
.
_streamid
,
from_mp4
);
}
// 忽略
类型
,同步查找流,可能返回rtmp/rtsp/hls类型
// 忽略
schema
,同步查找流,可能返回rtmp/rtsp/hls类型
static
Ptr
find
(
const
std
::
string
&
vhost
,
const
std
::
string
&
app
,
const
std
::
string
&
stream_id
,
bool
from_mp4
=
false
);
// 异步查找流
...
...
@@ -335,6 +341,7 @@ public:
bool
isFlushAble
(
bool
is_video
,
bool
is_key
,
uint64_t
new_stamp
,
size_t
cache_size
);
private
:
// 音视频的最后时间戳
uint64_t
_last_stamp
[
2
]
=
{
0
,
0
};
};
...
...
src/Http/HttpSession.cpp
查看文件 @
999e0b27
...
...
@@ -103,9 +103,7 @@ void HttpSession::onError(const SockException& err) {
//flv/ts播放器
uint64_t
duration
=
_ticker
.
createdTime
()
/
1000
;
WarnP
(
this
)
<<
"FLV/TS/FMP4播放器("
<<
_mediaInfo
.
_vhost
<<
"/"
<<
_mediaInfo
.
_app
<<
"/"
<<
_mediaInfo
.
_streamid
<<
_mediaInfo
.
shortUrl
()
<<
")断开:"
<<
err
.
what
()
<<
",耗时(s):"
<<
duration
;
...
...
src/Player/PlayerProxy.cpp
查看文件 @
999e0b27
...
...
@@ -160,7 +160,7 @@ bool PlayerProxy::close(MediaSource &sender, bool force) {
strongSelf
->
teardown
();
});
_on_close
(
SockException
(
Err_shutdown
,
"closed by user"
));
WarnL
<<
sender
.
get
Schema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
WarnL
<<
sender
.
get
Url
()
<<
" "
<<
force
;
return
true
;
}
...
...
src/Record/HlsMediaSource.cpp
查看文件 @
999e0b27
...
...
@@ -40,8 +40,7 @@ HlsCookieData::~HlsCookieData() {
if
(
*
_added
)
{
uint64_t
duration
=
(
_ticker
.
createdTime
()
-
_ticker
.
elapsedTime
())
/
1000
;
WarnL
<<
_sock_info
->
getIdentifier
()
<<
"("
<<
_sock_info
->
get_peer_ip
()
<<
":"
<<
_sock_info
->
get_peer_port
()
<<
") "
<<
"HLS播放器("
<<
_info
.
_vhost
<<
"/"
<<
_info
.
_app
<<
"/"
<<
_info
.
_streamid
<<
")断开,耗时(s):"
<<
duration
;
<<
") "
<<
"HLS播放器("
<<
_info
.
shortUrl
()
<<
")断开,耗时(s):"
<<
duration
;
GET_CONFIG
(
uint32_t
,
iFlowThreshold
,
General
::
kFlowThreshold
);
uint64_t
bytes
=
_bytes
.
load
();
...
...
src/Record/MP4Reader.cpp
查看文件 @
999e0b27
...
...
@@ -235,7 +235,7 @@ bool MP4Reader::close(MediaSource &sender, bool force) {
return
false
;
}
_timer
.
reset
();
WarnL
<<
sender
.
get
Schema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
WarnL
<<
sender
.
get
Url
()
<<
" "
<<
force
;
return
true
;
}
...
...
src/Record/MP4Recorder.cpp
查看文件 @
999e0b27
...
...
@@ -63,6 +63,7 @@ void MP4Recorder::createFile() {
WarnL
<<
ex
.
what
();
}
}
void
MP4Recorder
::
asyncClose
()
{
auto
muxer
=
_muxer
;
auto
full_path_tmp
=
_full_path_tmp
;
...
...
src/Rtmp/RtmpSession.cpp
查看文件 @
999e0b27
...
...
@@ -31,9 +31,7 @@ void RtmpSession::onError(const SockException& err) {
bool
is_player
=
!
_push_src_ownership
;
uint64_t
duration
=
_ticker
.
createdTime
()
/
1000
;
WarnP
(
this
)
<<
(
is_player
?
"RTMP播放器("
:
"RTMP推流器("
)
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
_media_info
.
shortUrl
()
<<
")断开:"
<<
err
.
what
()
<<
",耗时(s):"
<<
duration
;
...
...
@@ -256,10 +254,7 @@ void RtmpSession::sendPlayResponse(const string &err, const RtmpMediaSource::Ptr
"clientid"
,
"0"
});
if
(
!
ok
)
{
string
err_msg
=
StrPrinter
<<
(
auth_success
?
"no such stream:"
:
err
.
data
())
<<
" "
<<
_media_info
.
_vhost
<<
" "
<<
_media_info
.
_app
<<
" "
<<
_media_info
.
_streamid
;
string
err_msg
=
StrPrinter
<<
(
auth_success
?
"no such stream:"
:
err
.
data
())
<<
" "
<<
_media_info
.
shortUrl
();
shutdown
(
SockException
(
Err_shutdown
,
err_msg
));
return
;
}
...
...
@@ -579,7 +574,7 @@ bool RtmpSession::close(MediaSource &sender,bool force) {
if
(
!
_push_src
||
(
!
force
&&
_push_src
->
totalReaderCount
())){
return
false
;
}
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
get
Schema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
get
Url
()
<<
" "
<<
force
;
safeShutdown
(
SockException
(
Err_shutdown
,
err
));
return
true
;
}
...
...
@@ -619,6 +614,6 @@ void RtmpSession::dumpMetadata(const AMFValue &metadata) {
metadata
.
object_for_each
([
&
](
const
string
&
key
,
const
AMFValue
&
val
)
{
printer
<<
"
\r\n
"
<<
key
<<
"
\t
:"
<<
val
.
to_string
();
});
InfoL
<<
_media_info
.
_vhost
<<
" "
<<
_media_info
.
_app
<<
" "
<<
_media_info
.
_streamid
<<
(
string
)
printer
;
InfoL
<<
_media_info
.
shortUrl
()
<<
(
string
)
printer
;
}
}
/* namespace mediakit */
src/Rtp/RtpProcess.cpp
查看文件 @
999e0b27
...
...
@@ -52,9 +52,7 @@ RtpProcess::RtpProcess(const string &stream_id) {
RtpProcess
::~
RtpProcess
()
{
uint64_t
duration
=
(
_last_frame_time
.
createdTime
()
-
_last_frame_time
.
elapsedTime
())
/
1000
;
WarnP
(
this
)
<<
"RTP推流器("
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
_media_info
.
shortUrl
()
<<
")断开,耗时(s):"
<<
duration
;
//流量统计事件广播
...
...
@@ -272,7 +270,7 @@ MediaOriginType RtpProcess::getOriginType(MediaSource &sender) const{
}
string
RtpProcess
::
getOriginUrl
(
MediaSource
&
sender
)
const
{
return
_media_info
.
_schema
+
"://"
+
_media_info
.
_vhost
+
"/"
+
_media_info
.
_app
+
"/"
+
_media_info
.
_streamid
;
return
_media_info
.
getUrl
()
;
}
std
::
shared_ptr
<
SockInfo
>
RtpProcess
::
getOriginSock
(
MediaSource
&
sender
)
const
{
...
...
src/Rtp/RtpSelector.cpp
查看文件 @
999e0b27
...
...
@@ -144,7 +144,7 @@ bool RtpProcessHelper::close(MediaSource &sender, bool force) {
return
false
;
}
parent
->
delProcess
(
_stream_id
,
_process
.
get
());
WarnL
<<
"close media:"
<<
sender
.
get
Schema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
WarnL
<<
"close media:"
<<
sender
.
get
Url
()
<<
" "
<<
force
;
return
true
;
}
...
...
src/Rtp/RtpSession.cpp
查看文件 @
999e0b27
...
...
@@ -129,7 +129,7 @@ bool RtpSession::close(MediaSource &sender, bool force) {
if
(
!
_process
||
(
!
force
&&
static_pointer_cast
<
MediaSourceEvent
>
(
_process
)
->
totalReaderCount
(
sender
))){
return
false
;
}
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
get
Schema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
get
Url
()
<<
" "
<<
force
;
safeShutdown
(
SockException
(
Err_shutdown
,
err
));
return
true
;
}
...
...
src/Rtsp/RtspSession.cpp
查看文件 @
999e0b27
...
...
@@ -63,9 +63,7 @@ void RtspSession::onError(const SockException &err) {
bool
is_player
=
!
_push_src_ownership
;
uint64_t
duration
=
_alive_ticker
.
createdTime
()
/
1000
;
WarnP
(
this
)
<<
(
is_player
?
"RTSP播放器("
:
"RTSP推流器("
)
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
_media_info
.
shortUrl
()
<<
")断开:"
<<
err
.
what
()
<<
",耗时(s):"
<<
duration
;
...
...
@@ -249,9 +247,7 @@ void RtspSession::handleReq_ANNOUNCE(const Parser &parser) {
if
(
push_failed
)
{
sendRtspResponse
(
"406 Not Acceptable"
,
{
"Content-Type"
,
"text/plain"
},
"Already publishing."
);
string
err
=
StrPrinter
<<
"ANNOUNCE:"
<<
"Already publishing:"
<<
_media_info
.
_vhost
<<
" "
<<
_media_info
.
_app
<<
" "
<<
_media_info
.
_streamid
<<
endl
;
string
err
=
StrPrinter
<<
"ANNOUNCE: Already publishing:"
<<
_media_info
.
shortUrl
()
<<
endl
;
throw
SockException
(
Err_shutdown
,
err
);
}
...
...
@@ -417,7 +413,7 @@ void RtspSession::onAuthSuccess() {
auto
rtsp_src
=
dynamic_pointer_cast
<
RtspMediaSource
>
(
src
);
if
(
!
rtsp_src
)
{
//未找到相应的MediaSource
string
err
=
StrPrinter
<<
"no such stream:"
<<
strong_self
->
_media_info
.
_vhost
<<
" "
<<
strong_self
->
_media_info
.
_app
<<
" "
<<
strong_self
->
_media_info
.
_streamid
;
string
err
=
StrPrinter
<<
"no such stream:"
<<
strong_self
->
_media_info
.
shortUrl
()
;
strong_self
->
send_StreamNotFound
();
strong_self
->
shutdown
(
SockException
(
Err_shutdown
,
err
));
return
;
...
...
@@ -1134,7 +1130,7 @@ bool RtspSession::close(MediaSource &sender, bool force) {
if
(
!
_push_src
||
(
!
force
&&
_push_src
->
totalReaderCount
())){
return
false
;
}
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
get
Schema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
get
Url
()
<<
" "
<<
force
;
safeShutdown
(
SockException
(
Err_shutdown
,
err
));
return
true
;
}
...
...
src/Shell/ShellCMD.h
查看文件 @
999e0b27
...
...
@@ -23,12 +23,7 @@ public:
MediaSource
::
for_each_media
([
&
](
const
MediaSource
::
Ptr
&
media
)
{
if
(
ini
.
find
(
"list"
)
!=
ini
.
end
())
{
//列出源
(
*
stream
)
<<
"
\t
"
<<
media
->
getSchema
()
<<
"/"
<<
media
->
getVhost
()
<<
"/"
<<
media
->
getApp
()
<<
"/"
<<
media
->
getId
()
<<
"
\r\n
"
;
(
*
stream
)
<<
"
\t
"
<<
media
->
getUrl
()
<<
"
\r\n
"
;
return
;
}
...
...
@@ -42,20 +37,10 @@ public:
if
(
!
media
->
close
(
true
))
{
break
;
}
(
*
stream
)
<<
"
\t
踢出成功:"
<<
media
->
getSchema
()
<<
"/"
<<
media
->
getVhost
()
<<
"/"
<<
media
->
getApp
()
<<
"/"
<<
media
->
getId
()
<<
"
\r\n
"
;
(
*
stream
)
<<
"
\t
踢出成功:"
<<
media
->
getUrl
()
<<
"
\r\n
"
;
return
;
}
while
(
0
);
(
*
stream
)
<<
"
\t
踢出失败:"
<<
media
->
getSchema
()
<<
"/"
<<
media
->
getVhost
()
<<
"/"
<<
media
->
getApp
()
<<
"/"
<<
media
->
getId
()
<<
"
\r\n
"
;
(
*
stream
)
<<
"
\t
踢出失败:"
<<
media
->
getUrl
()
<<
"
\r\n
"
;
}
},
false
);
...
...
srt/SrtTransportImp.cpp
查看文件 @
999e0b27
...
...
@@ -10,8 +10,7 @@ SrtTransportImp::SrtTransportImp(const EventPoller::Ptr &poller)
SrtTransportImp
::~
SrtTransportImp
()
{
InfoP
(
this
);
uint64_t
duration
=
_alive_ticker
.
createdTime
()
/
1000
;
WarnP
(
this
)
<<
(
_is_pusher
?
"srt 推流器("
:
"srt 播放器("
)
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
")断开,耗时(s):"
<<
duration
;
WarnP
(
this
)
<<
(
_is_pusher
?
"srt 推流器("
:
"srt 播放器("
)
<<
_media_info
.
shortUrl
()
<<
")断开,耗时(s):"
<<
duration
;
// 流量统计事件广播
GET_CONFIG
(
uint32_t
,
iFlowThreshold
,
General
::
kFlowThreshold
);
...
...
@@ -89,8 +88,7 @@ bool SrtTransportImp::parseStreamid(std::string &streamid) {
_media_info
.
_app
=
app
;
_media_info
.
_streamid
=
stream_name
;
TraceL
<<
" vhost="
<<
_media_info
.
_vhost
<<
" app="
<<
_media_info
.
_app
<<
" streamid="
<<
_media_info
.
_streamid
<<
" params="
<<
_media_info
.
_param_strs
;
TraceL
<<
" mediainfo="
<<
_media_info
.
shortUrl
()
<<
" params="
<<
_media_info
.
_param_strs
;
return
true
;
}
...
...
@@ -115,8 +113,7 @@ bool SrtTransportImp::close(mediakit::MediaSource &sender, bool force) {
if
(
!
force
&&
totalReaderCount
(
sender
))
{
return
false
;
}
std
::
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
getSchema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
std
::
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
getUrl
()
<<
" "
<<
force
;
weak_ptr
<
SrtTransportImp
>
weak_self
=
static_pointer_cast
<
SrtTransportImp
>
(
shared_from_this
());
getPoller
()
->
async
([
weak_self
,
err
]()
{
auto
strong_self
=
weak_self
.
lock
();
...
...
tests/test_server.cpp
查看文件 @
999e0b27
...
...
@@ -90,26 +90,22 @@ static mutex s_mtxFlvRecorder;
void
initEventListener
()
{
static
onceToken
s_token
([]()
{
//监听kBroadcastOnGetRtspRealm事件决定rtsp链接是否需要鉴权(传统的rtsp鉴权方案)才能访问
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastOnGetRtspRealm
,
[](
BroadcastOnGetRtspRealmArgs
)
{
DebugL
<<
"RTSP是否需要鉴权事件:"
<<
args
.
_schema
<<
" "
<<
args
.
_vhost
<<
" "
<<
args
.
_app
<<
" "
<<
args
.
_streamid
<<
" "
<<
args
.
_param_strs
;
if
(
string
(
"1"
)
==
args
.
_streamid
)
{
// live/1需要认证
//该流需要认证,并且设置realm
invoker
(
REALM
);
}
else
{
//有时我们要查询redis或数据库来判断该流是否需要认证,通过invoker的方式可以做到完全异步
//该流我们不需要认证
invoker
(
""
);
}
});
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastOnGetRtspRealm
,
[](
BroadcastOnGetRtspRealmArgs
)
{
DebugL
<<
"RTSP是否需要鉴权事件:"
<<
args
.
getUrl
()
<<
" "
<<
args
.
_param_strs
;
if
(
string
(
"1"
)
==
args
.
_streamid
)
{
// live/1需要认证
//该流需要认证,并且设置realm
invoker
(
REALM
);
}
else
{
//有时我们要查询redis或数据库来判断该流是否需要认证,通过invoker的方式可以做到完全异步
//该流我们不需要认证
invoker
(
""
);
}
});
//监听kBroadcastOnRtspAuth事件返回正确的rtsp鉴权用户密码
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastOnRtspAuth
,
[](
BroadcastOnRtspAuthArgs
)
{
DebugL
<<
"RTSP播放鉴权:"
<<
args
.
_schema
<<
" "
<<
args
.
_vhost
<<
" "
<<
args
.
_app
<<
" "
<<
args
.
_streamid
<<
" "
<<
args
.
_param_strs
;
DebugL
<<
"RTSP播放鉴权:"
<<
args
.
getUrl
()
<<
" "
<<
args
.
_param_strs
;
DebugL
<<
"RTSP用户:"
<<
user_name
<<
(
must_no_encrypt
?
" Base64"
:
" MD5"
)
<<
" 方式登录"
;
string
user
=
user_name
;
//假设我们异步读取数据库
...
...
@@ -139,16 +135,14 @@ void initEventListener() {
//监听rtsp/rtmp推流事件,返回结果告知是否有推流权限
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastMediaPublish
,
[](
BroadcastMediaPublishArgs
)
{
DebugL
<<
"推流鉴权:"
<<
args
.
_schema
<<
" "
<<
args
.
_vhost
<<
" "
<<
args
.
_app
<<
" "
<<
args
.
_streamid
<<
" "
<<
args
.
_param_strs
;
DebugL
<<
"推流鉴权:"
<<
args
.
getUrl
()
<<
" "
<<
args
.
_param_strs
;
invoker
(
""
,
ProtocolOption
());
//鉴权成功
//invoker("this is auth failed message");//鉴权失败
});
//监听rtsp/rtsps/rtmp/http-flv播放事件,返回结果告知是否有播放权限(rtsp通过kBroadcastOnRtspAuth或此事件都可以实现鉴权)
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastMediaPlayed
,
[](
BroadcastMediaPlayedArgs
)
{
DebugL
<<
"播放鉴权:"
<<
args
.
_schema
<<
" "
<<
args
.
_vhost
<<
" "
<<
args
.
_app
<<
" "
<<
args
.
_streamid
<<
" "
<<
args
.
_param_strs
;
DebugL
<<
"播放鉴权:"
<<
args
.
getUrl
()
<<
" "
<<
args
.
_param_strs
;
invoker
(
""
);
//鉴权成功
//invoker("this is auth failed message");//鉴权失败
});
...
...
@@ -164,42 +158,38 @@ void initEventListener() {
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastMediaChanged
,
[](
BroadcastMediaChangedArgs
)
{
if
(
sender
.
getSchema
()
==
RTMP_SCHEMA
&&
sender
.
getApp
()
==
"live"
)
{
lock_guard
<
mutex
>
lck
(
s_mtxFlvRecorder
);
auto
key
=
sender
.
shortUrl
();
if
(
bRegist
)
{
DebugL
<<
"开始录制RTMP:"
<<
sender
.
get
Schema
()
<<
" "
<<
sender
.
getVhost
()
<<
" "
<<
sender
.
getApp
()
<<
" "
<<
sender
.
getId
();
DebugL
<<
"开始录制RTMP:"
<<
sender
.
get
Url
();
GET_CONFIG
(
string
,
http_root
,
Http
::
kRootPath
);
auto
path
=
http_root
+
"/"
+
sender
.
getVhost
()
+
"/"
+
sender
.
getApp
()
+
"/"
+
sender
.
getId
()
+
"_"
+
to_string
(
time
(
NULL
))
+
".flv"
;
auto
path
=
http_root
+
"/"
+
key
+
"_"
+
to_string
(
time
(
NULL
))
+
".flv"
;
FlvRecorder
::
Ptr
recorder
(
new
FlvRecorder
);
try
{
recorder
->
startRecord
(
EventPollerPool
::
Instance
().
getPoller
(),
dynamic_pointer_cast
<
RtmpMediaSource
>
(
sender
.
shared_from_this
()),
path
);
s_mapFlvRecorder
[
sender
.
getVhost
()
+
"/"
+
sender
.
getApp
()
+
"/"
+
sender
.
getId
()
]
=
recorder
;
s_mapFlvRecorder
[
key
]
=
recorder
;
}
catch
(
std
::
exception
&
ex
)
{
WarnL
<<
ex
.
what
();
}
}
else
{
s_mapFlvRecorder
.
erase
(
sender
.
getVhost
()
+
"/"
+
sender
.
getApp
()
+
"/"
+
sender
.
getId
()
);
s_mapFlvRecorder
.
erase
(
key
);
}
}
});
//监听播放失败(未找到特定的流)事件
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastNotFoundStream
,
[](
BroadcastNotFoundStreamArgs
)
{
/**
* 你可以在这个事件触发时再去拉流,这样就可以实现按需拉流
* 拉流成功后,ZLMediaKit会把其立即转发给播放器(最大等待时间约为5秒,如果5秒都未拉流成功,播放器会播放失败)
*/
DebugL
<<
"未找到流事件:"
<<
args
.
_schema
<<
" "
<<
args
.
_vhost
<<
" "
<<
args
.
_app
<<
" "
<<
args
.
_streamid
<<
" "
<<
args
.
_param_strs
;
});
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastNotFoundStream
,
[](
BroadcastNotFoundStreamArgs
)
{
/**
* 你可以在这个事件触发时再去拉流,这样就可以实现按需拉流
* 拉流成功后,ZLMediaKit会把其立即转发给播放器(最大等待时间约为5秒,如果5秒都未拉流成功,播放器会播放失败)
*/
DebugL
<<
"未找到流事件:"
<<
args
.
getUrl
()
<<
" "
<<
args
.
_param_strs
;
});
//监听播放或推流结束时消耗流量事件
NoticeCenter
::
Instance
().
addListener
(
nullptr
,
Broadcast
::
kBroadcastFlowReport
,
[](
BroadcastFlowReportArgs
)
{
DebugL
<<
"播放器(推流器)断开连接事件:"
<<
args
.
_schema
<<
" "
<<
args
.
_vhost
<<
" "
<<
args
.
_app
<<
" "
<<
args
.
_streamid
<<
" "
<<
args
.
_param_strs
DebugL
<<
"播放器(推流器)断开连接事件:"
<<
args
.
getUrl
()
<<
" "
<<
args
.
_param_strs
<<
"
\r\n
使用流量:"
<<
totalBytes
<<
" bytes,连接时长:"
<<
totalDuration
<<
"秒"
;
});
...
...
webrtc/WebRtcPlayer.cpp
查看文件 @
999e0b27
...
...
@@ -72,9 +72,7 @@ void WebRtcPlayer::onDestory() {
GET_CONFIG
(
uint32_t
,
iFlowThreshold
,
General
::
kFlowThreshold
);
if
(
_reader
&&
getSession
())
{
WarnL
<<
"RTC播放器("
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
_media_info
.
shortUrl
()
<<
")结束播放,耗时(s):"
<<
duration
;
if
(
bytes_usage
>=
iFlowThreshold
*
1024
)
{
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastFlowReport
,
_media_info
,
bytes_usage
,
duration
,
...
...
webrtc/WebRtcPusher.cpp
查看文件 @
999e0b27
...
...
@@ -43,8 +43,7 @@ bool WebRtcPusher::close(MediaSource &sender, bool force) {
if
(
!
force
&&
totalReaderCount
(
sender
))
{
return
false
;
}
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
getSchema
()
<<
"/"
<<
sender
.
getVhost
()
<<
"/"
<<
sender
.
getApp
()
<<
"/"
<<
sender
.
getId
()
<<
" "
<<
force
;
string
err
=
StrPrinter
<<
"close media:"
<<
sender
.
getUrl
()
<<
" "
<<
force
;
weak_ptr
<
WebRtcPusher
>
weak_self
=
static_pointer_cast
<
WebRtcPusher
>
(
shared_from_this
());
getPoller
()
->
async
([
weak_self
,
err
]()
{
auto
strong_self
=
weak_self
.
lock
();
...
...
@@ -123,9 +122,7 @@ void WebRtcPusher::onDestory() {
if
(
getSession
())
{
WarnL
<<
"RTC推流器("
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
_media_info
.
shortUrl
()
<<
")结束推流,耗时(s):"
<<
duration
;
if
(
bytes_usage
>=
iFlowThreshold
*
1024
)
{
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastFlowReport
,
_media_info
,
bytes_usage
,
duration
,
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论