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
7f3f47ab
Commit
7f3f47ab
authored
Oct 15, 2021
by
ziyue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
提取webrtc推流、播放代码为单独的派生类
parent
8531b5e1
显示空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
375 行增加
和
223 行删除
+375
-223
server/WebApi.cpp
+4
-5
webrtc/WebRtcPlayer.cpp
+101
-0
webrtc/WebRtcPlayer.h
+44
-0
webrtc/WebRtcPusher.cpp
+132
-0
webrtc/WebRtcPusher.h
+55
-0
webrtc/WebRtcTransport.cpp
+19
-174
webrtc/WebRtcTransport.h
+20
-44
没有找到文件。
server/WebApi.cpp
查看文件 @
7f3f47ab
...
@@ -38,7 +38,8 @@
...
@@ -38,7 +38,8 @@
#include "Rtp/RtpServer.h"
#include "Rtp/RtpServer.h"
#endif
#endif
#ifdef ENABLE_WEBRTC
#ifdef ENABLE_WEBRTC
#include "../webrtc/WebRtcTransport.h"
#include "../webrtc/WebRtcPlayer.h"
#include "../webrtc/WebRtcPusher.h"
#endif
#endif
using
namespace
toolkit
;
using
namespace
toolkit
;
...
@@ -1219,8 +1220,7 @@ void installWebApi() {
...
@@ -1219,8 +1220,7 @@ void installWebApi() {
}
}
//还原成rtc,目的是为了hook时识别哪种播放协议
//还原成rtc,目的是为了hook时识别哪种播放协议
info
.
_schema
=
"rtc"
;
info
.
_schema
=
"rtc"
;
auto
rtc
=
WebRtcTransportImp
::
create
(
EventPollerPool
::
Instance
().
getPoller
());
auto
rtc
=
WebRtcPlayer
::
create
(
EventPollerPool
::
Instance
().
getPoller
(),
src
,
info
);
rtc
->
attach
(
src
,
info
,
true
);
val
[
"sdp"
]
=
rtc
->
getAnswerSdp
(
offer_sdp
);
val
[
"sdp"
]
=
rtc
->
getAnswerSdp
(
offer_sdp
);
val
[
"type"
]
=
"answer"
;
val
[
"type"
]
=
"answer"
;
invoker
(
200
,
headerOut
,
val
.
toStyledString
());
invoker
(
200
,
headerOut
,
val
.
toStyledString
());
...
@@ -1248,9 +1248,8 @@ void installWebApi() {
...
@@ -1248,9 +1248,8 @@ void installWebApi() {
}
}
auto
push_src
=
std
::
make_shared
<
RtspMediaSourceImp
>
(
info
.
_vhost
,
info
.
_app
,
info
.
_streamid
);
auto
push_src
=
std
::
make_shared
<
RtspMediaSourceImp
>
(
info
.
_vhost
,
info
.
_app
,
info
.
_streamid
);
push_src
->
setProtocolTranslation
(
enableHls
,
enableMP4
);
push_src
->
setProtocolTranslation
(
enableHls
,
enableMP4
);
auto
rtc
=
WebRtc
TransportImp
::
create
(
EventPollerPool
::
Instance
().
getPoller
()
);
auto
rtc
=
WebRtc
Pusher
::
create
(
EventPollerPool
::
Instance
().
getPoller
(),
push_src
,
info
);
push_src
->
setListener
(
rtc
);
push_src
->
setListener
(
rtc
);
rtc
->
attach
(
push_src
,
info
,
false
);
val
[
"sdp"
]
=
rtc
->
getAnswerSdp
(
offer_sdp
);
val
[
"sdp"
]
=
rtc
->
getAnswerSdp
(
offer_sdp
);
val
[
"type"
]
=
"answer"
;
val
[
"type"
]
=
"answer"
;
invoker
(
200
,
headerOut
,
val
.
toStyledString
());
invoker
(
200
,
headerOut
,
val
.
toStyledString
());
...
...
webrtc/WebRtcPlayer.cpp
0 → 100644
查看文件 @
7f3f47ab
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#include "WebRtcPlayer.h"
WebRtcPlayer
::
Ptr
WebRtcPlayer
::
create
(
const
EventPoller
::
Ptr
&
poller
,
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
)
{
WebRtcPlayer
::
Ptr
ret
(
new
WebRtcPlayer
(
poller
,
src
,
info
),
[](
WebRtcPlayer
*
ptr
)
{
ptr
->
onDestory
();
delete
ptr
;
});
ret
->
onCreate
();
return
ret
;
}
WebRtcPlayer
::
WebRtcPlayer
(
const
EventPoller
::
Ptr
&
poller
,
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
)
:
WebRtcTransportImp
(
poller
)
{
InfoL
<<
this
;
_media_info
=
info
;
_play_src
=
src
;
CHECK
(
_play_src
);
}
void
WebRtcPlayer
::
onStartWebRTC
()
{
CHECK
(
_play_src
);
WebRtcTransportImp
::
onStartWebRTC
();
if
(
canSendRtp
())
{
_play_src
->
pause
(
false
);
_reader
=
_play_src
->
getRing
()
->
attach
(
getPoller
(),
true
);
weak_ptr
<
WebRtcPlayer
>
weak_self
=
static_pointer_cast
<
WebRtcPlayer
>
(
shared_from_this
());
_reader
->
setReadCB
([
weak_self
](
const
RtspMediaSource
::
RingDataType
&
pkt
)
{
auto
strongSelf
=
weak_self
.
lock
();
if
(
!
strongSelf
)
{
return
;
}
size_t
i
=
0
;
pkt
->
for_each
([
&
](
const
RtpPacket
::
Ptr
&
rtp
)
{
strongSelf
->
beforeSendRtp
(
rtp
,
++
i
==
pkt
->
size
());
});
});
_reader
->
setDetachCB
([
weak_self
]()
{
auto
strongSelf
=
weak_self
.
lock
();
if
(
!
strongSelf
)
{
return
;
}
strongSelf
->
onShutdown
(
SockException
(
Err_shutdown
,
"rtsp ring buffer detached"
));
});
//确保该rtp codec类型对方支持
memset
(
_can_send_rtp
,
0
,
sizeof
(
_can_send_rtp
));
for
(
auto
&
m
:
_answer_sdp
->
media
)
{
_can_send_rtp
[
m
.
type
]
=
m
.
direction
==
RtpDirection
::
sendonly
||
m
.
direction
==
RtpDirection
::
sendrecv
;
}
}
//使用完毕后,释放强引用,这样确保推流器断开后能及时注销媒体
_play_src
=
nullptr
;
}
void
WebRtcPlayer
::
onDestory
()
{
WebRtcTransportImp
::
onDestory
();
auto
duration
=
getDuration
();
auto
bytes_usage
=
getBytesUsage
();
//流量统计事件广播
GET_CONFIG
(
uint32_t
,
iFlowThreshold
,
General
::
kFlowThreshold
);
if
(
_reader
&&
getSession
())
{
WarnL
<<
"RTC播放器("
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
")结束播放,耗时(s):"
<<
duration
;
if
(
bytes_usage
>=
iFlowThreshold
*
1024
)
{
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastFlowReport
,
_media_info
,
bytes_usage
,
duration
,
true
,
static_cast
<
SockInfo
&>
(
*
getSession
()));
}
}
}
void
WebRtcPlayer
::
onRtcConfigure
(
RtcConfigure
&
configure
)
const
{
CHECK
(
_play_src
);
WebRtcTransportImp
::
onRtcConfigure
(
configure
);
//这是播放
configure
.
audio
.
direction
=
configure
.
video
.
direction
=
RtpDirection
::
sendonly
;
configure
.
setPlayRtspInfo
(
_play_src
->
getSdp
());
}
void
WebRtcPlayer
::
beforeSendRtp
(
const
RtpPacket
::
Ptr
&
rtp
,
bool
flush
,
bool
rtx
)
{
if
(
!
_can_send_rtp
[
rtp
->
type
])
{
return
;
}
onSendRtp
(
rtp
,
flush
,
rtx
);
}
webrtc/WebRtcPlayer.h
0 → 100644
查看文件 @
7f3f47ab
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ZLMEDIAKIT_WEBRTCPLAYER_H
#define ZLMEDIAKIT_WEBRTCPLAYER_H
#include "WebRtcTransport.h"
class
WebRtcPlayer
:
public
WebRtcTransportImp
{
public
:
using
Ptr
=
std
::
shared_ptr
<
WebRtcPlayer
>
;
~
WebRtcPlayer
()
override
=
default
;
static
Ptr
create
(
const
EventPoller
::
Ptr
&
poller
,
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
);
protected
:
///////WebRtcTransportImp override///////
void
onStartWebRTC
()
override
;
void
onDestory
()
override
;
void
onRtcConfigure
(
RtcConfigure
&
configure
)
const
override
;
void
onRecvRtp
(
MediaTrack
&
track
,
const
string
&
rid
,
RtpPacket
::
Ptr
rtp
)
{};
private
:
WebRtcPlayer
(
const
EventPoller
::
Ptr
&
poller
,
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
);
void
beforeSendRtp
(
const
RtpPacket
::
Ptr
&
rtp
,
bool
flush
,
bool
rtx
=
false
);
private
:
bool
_can_send_rtp
[
TrackMax
];
//媒体相关元数据
MediaInfo
_media_info
;
//播放的rtsp源
RtspMediaSource
::
Ptr
_play_src
;
//播放rtsp源的reader对象
RtspMediaSource
::
RingType
::
RingReader
::
Ptr
_reader
;
};
#endif //ZLMEDIAKIT_WEBRTCPLAYER_H
webrtc/WebRtcPusher.cpp
0 → 100644
查看文件 @
7f3f47ab
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#include "WebRtcPusher.h"
WebRtcPusher
::
Ptr
WebRtcPusher
::
create
(
const
EventPoller
::
Ptr
&
poller
,
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
)
{
WebRtcPusher
::
Ptr
ret
(
new
WebRtcPusher
(
poller
,
src
,
info
),
[](
WebRtcPusher
*
ptr
)
{
ptr
->
onDestory
();
delete
ptr
;
});
ret
->
onCreate
();
return
ret
;
}
WebRtcPusher
::
WebRtcPusher
(
const
EventPoller
::
Ptr
&
poller
,
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
)
:
WebRtcTransportImp
(
poller
)
{
InfoL
<<
this
;
_media_info
=
info
;
_push_src
=
src
;
CHECK
(
_push_src
);
}
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
;
weak_ptr
<
WebRtcPusher
>
weak_self
=
static_pointer_cast
<
WebRtcPusher
>
(
shared_from_this
());
getPoller
()
->
async
([
weak_self
,
err
]()
{
auto
strong_self
=
weak_self
.
lock
();
if
(
strong_self
)
{
strong_self
->
onShutdown
(
SockException
(
Err_shutdown
,
err
));
}
});
return
true
;
}
int
WebRtcPusher
::
totalReaderCount
(
MediaSource
&
sender
)
{
auto
total_count
=
0
;
for
(
auto
&
src
:
_push_src_simulcast
)
{
total_count
+=
src
.
second
->
totalReaderCount
();
}
return
total_count
+
_push_src
->
totalReaderCount
();
}
MediaOriginType
WebRtcPusher
::
getOriginType
(
MediaSource
&
sender
)
const
{
return
MediaOriginType
::
rtc_push
;
}
string
WebRtcPusher
::
getOriginUrl
(
MediaSource
&
sender
)
const
{
return
_media_info
.
_full_url
;
}
std
::
shared_ptr
<
SockInfo
>
WebRtcPusher
::
getOriginSock
(
MediaSource
&
sender
)
const
{
return
static_pointer_cast
<
SockInfo
>
(
getSession
());
}
void
WebRtcPusher
::
onRecvRtp
(
MediaTrack
&
track
,
const
string
&
rid
,
RtpPacket
::
Ptr
rtp
)
{
if
(
!
_simulcast
)
{
assert
(
_push_src
);
_push_src
->
onWrite
(
rtp
,
false
);
return
;
}
if
(
rtp
->
type
==
TrackAudio
)
{
//音频
for
(
auto
&
pr
:
_push_src_simulcast
)
{
pr
.
second
->
onWrite
(
rtp
,
false
);
}
}
else
{
//视频
auto
&
src
=
_push_src_simulcast
[
rid
];
if
(
!
src
)
{
auto
stream_id
=
rid
.
empty
()
?
_push_src
->
getId
()
:
_push_src
->
getId
()
+
"_"
+
rid
;
auto
src_imp
=
std
::
make_shared
<
RtspMediaSourceImp
>
(
_push_src
->
getVhost
(),
_push_src
->
getApp
(),
stream_id
);
src_imp
->
setSdp
(
_push_src
->
getSdp
());
src_imp
->
setProtocolTranslation
(
_push_src
->
isRecording
(
Recorder
::
type_hls
),
_push_src
->
isRecording
(
Recorder
::
type_mp4
));
src_imp
->
setListener
(
static_pointer_cast
<
WebRtcPusher
>
(
shared_from_this
()));
src
=
src_imp
;
}
src
->
onWrite
(
std
::
move
(
rtp
),
false
);
}
}
void
WebRtcPusher
::
onStartWebRTC
()
{
WebRtcTransportImp
::
onStartWebRTC
();
_simulcast
=
_answer_sdp
->
supportSimulcast
();
if
(
canRecvRtp
())
{
_push_src
->
setSdp
(
_answer_sdp
->
toRtspSdp
());
}
}
void
WebRtcPusher
::
onDestory
()
{
WebRtcTransportImp
::
onDestory
();
auto
duration
=
getDuration
();
auto
bytes_usage
=
getBytesUsage
();
//流量统计事件广播
GET_CONFIG
(
uint32_t
,
iFlowThreshold
,
General
::
kFlowThreshold
);
if
(
getSession
())
{
WarnL
<<
"RTC推流器("
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
")结束推流,耗时(s):"
<<
duration
;
if
(
bytes_usage
>=
iFlowThreshold
*
1024
)
{
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastFlowReport
,
_media_info
,
bytes_usage
,
duration
,
false
,
static_cast
<
SockInfo
&>
(
*
getSession
()));
}
}
}
void
WebRtcPusher
::
onRtcConfigure
(
RtcConfigure
&
configure
)
const
{
WebRtcTransportImp
::
onRtcConfigure
(
configure
);
//这只是推流
configure
.
audio
.
direction
=
configure
.
video
.
direction
=
RtpDirection
::
recvonly
;
}
\ No newline at end of file
webrtc/WebRtcPusher.h
0 → 100644
查看文件 @
7f3f47ab
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ZLMEDIAKIT_WEBRTCPUSHER_H
#define ZLMEDIAKIT_WEBRTCPUSHER_H
#include "WebRtcTransport.h"
class
WebRtcPusher
:
public
WebRtcTransportImp
,
public
MediaSourceEvent
{
public
:
using
Ptr
=
std
::
shared_ptr
<
WebRtcPusher
>
;
~
WebRtcPusher
()
override
=
default
;
static
Ptr
create
(
const
EventPoller
::
Ptr
&
poller
,
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
);
protected
:
///////WebRtcTransportImp override///////
void
onStartWebRTC
()
override
;
void
onDestory
()
override
;
void
onRtcConfigure
(
RtcConfigure
&
configure
)
const
override
;
void
onRecvRtp
(
MediaTrack
&
track
,
const
string
&
rid
,
RtpPacket
::
Ptr
rtp
)
override
;
protected
:
///////MediaSourceEvent override///////
// 关闭
bool
close
(
MediaSource
&
sender
,
bool
force
)
override
;
// 播放总人数
int
totalReaderCount
(
MediaSource
&
sender
)
override
;
// 获取媒体源类型
MediaOriginType
getOriginType
(
MediaSource
&
sender
)
const
override
;
// 获取媒体源url或者文件路径
string
getOriginUrl
(
MediaSource
&
sender
)
const
override
;
// 获取媒体源客户端相关信息
std
::
shared_ptr
<
SockInfo
>
getOriginSock
(
MediaSource
&
sender
)
const
override
;
private
:
WebRtcPusher
(
const
EventPoller
::
Ptr
&
poller
,
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
);
private
:
bool
_simulcast
=
false
;
//媒体相关元数据
MediaInfo
_media_info
;
//推流的rtsp源
RtspMediaSource
::
Ptr
_push_src
;
//推流的rtsp源,支持simulcast
unordered_map
<
string
/*rid*/
,
RtspMediaSource
::
Ptr
>
_push_src_simulcast
;
};
#endif //ZLMEDIAKIT_WEBRTCPUSHER_H
webrtc/WebRtcTransport.cpp
查看文件 @
7f3f47ab
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
#include "Rtcp/RtcpFCI.h"
#include "Rtcp/RtcpFCI.h"
#include "Rtsp/RtpReceiver.h"
#include "Rtsp/RtpReceiver.h"
#define RTP_SSRC_OFFSET 1
#define RTX_SSRC_OFFSET 2
#define RTX_SSRC_OFFSET 2
#define RTP_CNAME "zlmediakit-rtp"
#define RTP_CNAME "zlmediakit-rtp"
#define RTP_LABEL "zlmediakit-label"
#define RTP_LABEL "zlmediakit-label"
...
@@ -207,16 +208,16 @@ std::string WebRtcTransport::getAnswerSdp(const string &offer){
...
@@ -207,16 +208,16 @@ std::string WebRtcTransport::getAnswerSdp(const string &offer){
}
}
}
}
bool
is_dtls
(
char
*
buf
)
{
static
bool
is_dtls
(
char
*
buf
)
{
return
((
*
buf
>
19
)
&&
(
*
buf
<
64
));
return
((
*
buf
>
19
)
&&
(
*
buf
<
64
));
}
}
bool
is_rtp
(
char
*
buf
)
{
static
bool
is_rtp
(
char
*
buf
)
{
RtpHeader
*
header
=
(
RtpHeader
*
)
buf
;
RtpHeader
*
header
=
(
RtpHeader
*
)
buf
;
return
((
header
->
pt
<
64
)
||
(
header
->
pt
>=
96
));
return
((
header
->
pt
<
64
)
||
(
header
->
pt
>=
96
));
}
}
bool
is_rtcp
(
char
*
buf
)
{
static
bool
is_rtcp
(
char
*
buf
)
{
RtpHeader
*
header
=
(
RtpHeader
*
)
buf
;
RtpHeader
*
header
=
(
RtpHeader
*
)
buf
;
return
((
header
->
pt
>=
64
)
&&
(
header
->
pt
<
96
));
return
((
header
->
pt
>=
64
)
&&
(
header
->
pt
<
96
));
}
}
...
@@ -285,14 +286,6 @@ void WebRtcTransport::sendRtcpPacket(const char *buf, int len, bool flush, void
...
@@ -285,14 +286,6 @@ void WebRtcTransport::sendRtcpPacket(const char *buf, int len, bool flush, void
}
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
WebRtcTransportImp
::
Ptr
WebRtcTransportImp
::
create
(
const
EventPoller
::
Ptr
&
poller
){
WebRtcTransportImp
::
Ptr
ret
(
new
WebRtcTransportImp
(
poller
),
[](
WebRtcTransportImp
*
ptr
){
ptr
->
onDestory
();
delete
ptr
;
});
ret
->
onCreate
();
return
ret
;
}
void
WebRtcTransportImp
::
onCreate
(){
void
WebRtcTransportImp
::
onCreate
(){
WebRtcTransport
::
onCreate
();
WebRtcTransport
::
onCreate
();
...
@@ -327,46 +320,6 @@ WebRtcTransportImp::~WebRtcTransportImp() {
...
@@ -327,46 +320,6 @@ WebRtcTransportImp::~WebRtcTransportImp() {
void
WebRtcTransportImp
::
onDestory
()
{
void
WebRtcTransportImp
::
onDestory
()
{
WebRtcTransport
::
onDestory
();
WebRtcTransport
::
onDestory
();
unregisterSelf
();
unregisterSelf
();
if
(
!
_session
)
{
return
;
}
uint64_t
duration
=
_alive_ticker
.
createdTime
()
/
1000
;
//流量统计事件广播
GET_CONFIG
(
uint32_t
,
iFlowThreshold
,
General
::
kFlowThreshold
);
if
(
_reader
)
{
WarnL
<<
"RTC播放器("
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
")结束播放,耗时(s):"
<<
duration
;
if
(
_bytes_usage
>=
iFlowThreshold
*
1024
)
{
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastFlowReport
,
_media_info
,
_bytes_usage
,
duration
,
true
,
static_cast
<
SockInfo
&>
(
*
_session
));
}
}
if
(
_push_src
)
{
WarnL
<<
"RTC推流器("
<<
_media_info
.
_vhost
<<
"/"
<<
_media_info
.
_app
<<
"/"
<<
_media_info
.
_streamid
<<
")结束推流,耗时(s):"
<<
duration
;
if
(
_bytes_usage
>=
iFlowThreshold
*
1024
)
{
NoticeCenter
::
Instance
().
emitEvent
(
Broadcast
::
kBroadcastFlowReport
,
_media_info
,
_bytes_usage
,
duration
,
false
,
static_cast
<
SockInfo
&>
(
*
_session
));
}
}
}
void
WebRtcTransportImp
::
attach
(
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
,
bool
is_play
)
{
assert
(
src
);
_media_info
=
info
;
if
(
is_play
)
{
_play_src
=
src
;
}
else
{
_push_src
=
src
;
}
}
}
void
WebRtcTransportImp
::
onSendSockData
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
,
bool
flush
)
{
void
WebRtcTransportImp
::
onSendSockData
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
,
bool
flush
)
{
...
@@ -384,9 +337,6 @@ void WebRtcTransportImp::onSendSockData(const char *buf, size_t len, struct sock
...
@@ -384,9 +337,6 @@ void WebRtcTransportImp::onSendSockData(const char *buf, size_t len, struct sock
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
bool
WebRtcTransportImp
::
canSendRtp
()
const
{
bool
WebRtcTransportImp
::
canSendRtp
()
const
{
if
(
!
_play_src
)
{
return
false
;
}
for
(
auto
&
m
:
_answer_sdp
->
media
)
{
for
(
auto
&
m
:
_answer_sdp
->
media
)
{
if
(
m
.
direction
==
RtpDirection
::
sendrecv
||
m
.
direction
==
RtpDirection
::
sendonly
)
{
if
(
m
.
direction
==
RtpDirection
::
sendrecv
||
m
.
direction
==
RtpDirection
::
sendonly
)
{
return
true
;
return
true
;
...
@@ -396,9 +346,6 @@ bool WebRtcTransportImp::canSendRtp() const{
...
@@ -396,9 +346,6 @@ bool WebRtcTransportImp::canSendRtp() const{
}
}
bool
WebRtcTransportImp
::
canRecvRtp
()
const
{
bool
WebRtcTransportImp
::
canRecvRtp
()
const
{
if
(
!
_push_src
)
{
return
false
;
}
for
(
auto
&
m
:
_answer_sdp
->
media
)
{
for
(
auto
&
m
:
_answer_sdp
->
media
)
{
if
(
m
.
direction
==
RtpDirection
::
sendrecv
||
m
.
direction
==
RtpDirection
::
recvonly
)
{
if
(
m
.
direction
==
RtpDirection
::
sendrecv
||
m
.
direction
==
RtpDirection
::
recvonly
)
{
return
true
;
return
true
;
...
@@ -422,6 +369,8 @@ void WebRtcTransportImp::onStartWebRTC() {
...
@@ -422,6 +369,8 @@ void WebRtcTransportImp::onStartWebRTC() {
track
->
plan_rtx
=
m_answer
.
getRelatedRtxPlan
(
track
->
plan_rtp
->
pt
);
track
->
plan_rtx
=
m_answer
.
getRelatedRtxPlan
(
track
->
plan_rtp
->
pt
);
track
->
rtcp_context_send
=
std
::
make_shared
<
RtcpContextForSend
>
();
track
->
rtcp_context_send
=
std
::
make_shared
<
RtcpContextForSend
>
();
//rtp track type --> MediaTrack
_type_to_track
[
m_answer
.
type
]
=
track
;
//send ssrc --> MediaTrack
//send ssrc --> MediaTrack
_ssrc_to_track
[
track
->
answer_ssrc_rtp
]
=
track
;
_ssrc_to_track
[
track
->
answer_ssrc_rtp
]
=
track
;
_ssrc_to_track
[
track
->
answer_ssrc_rtx
]
=
track
;
_ssrc_to_track
[
track
->
answer_ssrc_rtx
]
=
track
;
...
@@ -460,50 +409,6 @@ void WebRtcTransportImp::onStartWebRTC() {
...
@@ -460,50 +409,6 @@ void WebRtcTransportImp::onStartWebRTC() {
}
}
}
}
}
}
if
(
canRecvRtp
())
{
_push_src
->
setSdp
(
_answer_sdp
->
toRtspSdp
());
_simulcast
=
_answer_sdp
->
supportSimulcast
();
}
if
(
canSendRtp
())
{
RtcSession
rtsp_send_sdp
;
rtsp_send_sdp
.
loadFrom
(
_play_src
->
getSdp
(),
false
);
for
(
auto
&
m
:
_answer_sdp
->
media
)
{
if
(
m
.
type
==
TrackApplication
)
{
continue
;
}
auto
rtsp_media
=
rtsp_send_sdp
.
getMedia
(
m
.
type
);
if
(
rtsp_media
&&
getCodecId
(
rtsp_media
->
plan
[
0
].
codec
)
==
getCodecId
(
m
.
plan
[
0
].
codec
))
{
auto
it
=
_pt_to_track
.
find
(
m
.
plan
[
0
].
pt
);
CHECK
(
it
!=
_pt_to_track
.
end
());
//记录发送rtp时约定的信息,届时发送rtp时需要修改pt和ssrc
_type_to_track
[
m
.
type
]
=
it
->
second
.
second
;
}
}
_play_src
->
pause
(
false
);
_reader
=
_play_src
->
getRing
()
->
attach
(
getPoller
(),
true
);
weak_ptr
<
WebRtcTransportImp
>
weak_self
=
static_pointer_cast
<
WebRtcTransportImp
>
(
shared_from_this
());
_reader
->
setReadCB
([
weak_self
](
const
RtspMediaSource
::
RingDataType
&
pkt
)
{
auto
strongSelf
=
weak_self
.
lock
();
if
(
!
strongSelf
)
{
return
;
}
size_t
i
=
0
;
pkt
->
for_each
([
&
](
const
RtpPacket
::
Ptr
&
rtp
)
{
strongSelf
->
onSendRtp
(
rtp
,
++
i
==
pkt
->
size
());
});
});
_reader
->
setDetachCB
([
weak_self
](){
auto
strongSelf
=
weak_self
.
lock
();
if
(
!
strongSelf
)
{
return
;
}
strongSelf
->
onShutdown
(
SockException
(
Err_shutdown
,
"rtsp ring buffer detached"
));
});
}
//使用完毕后,释放强引用,这样确保推流器断开后能及时注销媒体
_play_src
=
nullptr
;
}
}
void
WebRtcTransportImp
::
onCheckAnswer
(
RtcSession
&
sdp
)
{
void
WebRtcTransportImp
::
onCheckAnswer
(
RtcSession
&
sdp
)
{
...
@@ -533,7 +438,8 @@ void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) {
...
@@ -533,7 +438,8 @@ void WebRtcTransportImp::onCheckAnswer(RtcSession &sdp) {
//添加answer sdp的ssrc信息
//添加answer sdp的ssrc信息
m
.
rtp_rtx_ssrc
.
emplace_back
();
m
.
rtp_rtx_ssrc
.
emplace_back
();
auto
&
ssrc
=
m
.
rtp_rtx_ssrc
.
back
();
auto
&
ssrc
=
m
.
rtp_rtx_ssrc
.
back
();
ssrc
.
ssrc
=
_play_src
->
getSsrc
(
m
.
type
);
//发送的ssrc我们随便定义,因为在发送rtp时会修改为此值
ssrc
.
ssrc
=
m
.
type
+
RTP_SSRC_OFFSET
;
ssrc
.
cname
=
RTP_CNAME
;
ssrc
.
cname
=
RTP_CNAME
;
ssrc
.
label
=
RTP_LABEL
;
ssrc
.
label
=
RTP_LABEL
;
ssrc
.
mslabel
=
RTP_MSLABEL
;
ssrc
.
mslabel
=
RTP_MSLABEL
;
...
@@ -557,20 +463,6 @@ void WebRtcTransportImp::onCheckSdp(SdpType type, RtcSession &sdp) {
...
@@ -557,20 +463,6 @@ void WebRtcTransportImp::onCheckSdp(SdpType type, RtcSession &sdp) {
void
WebRtcTransportImp
::
onRtcConfigure
(
RtcConfigure
&
configure
)
const
{
void
WebRtcTransportImp
::
onRtcConfigure
(
RtcConfigure
&
configure
)
const
{
WebRtcTransport
::
onRtcConfigure
(
configure
);
WebRtcTransport
::
onRtcConfigure
(
configure
);
if
(
_play_src
)
{
//这是播放,同时也可能有推流
configure
.
video
.
direction
=
_push_src
?
RtpDirection
::
sendrecv
:
RtpDirection
::
sendonly
;
configure
.
audio
.
direction
=
configure
.
video
.
direction
;
configure
.
setPlayRtspInfo
(
_play_src
->
getSdp
());
}
else
if
(
_push_src
)
{
//这只是推流
configure
.
video
.
direction
=
RtpDirection
::
recvonly
;
configure
.
audio
.
direction
=
RtpDirection
::
recvonly
;
}
else
{
throw
std
::
invalid_argument
(
"未设置播放或推流的媒体源"
);
}
//添加接收端口candidate信息
//添加接收端口candidate信息
configure
.
addCandidate
(
*
getIceCandidate
());
configure
.
addCandidate
(
*
getIceCandidate
());
}
}
...
@@ -872,35 +764,12 @@ void WebRtcTransportImp::onSortedRtp(MediaTrack &track, const string &rid, RtpPa
...
@@ -872,35 +764,12 @@ void WebRtcTransportImp::onSortedRtp(MediaTrack &track, const string &rid, RtpPa
}
}
}
}
if
(
!
_simulcast
)
{
onRecvRtp
(
track
,
rid
,
std
::
move
(
rtp
));
assert
(
_push_src
);
_push_src
->
onWrite
(
rtp
,
false
);
return
;
}
if
(
rtp
->
type
==
TrackAudio
)
{
//音频
for
(
auto
&
pr
:
_push_src_simulcast
)
{
pr
.
second
->
onWrite
(
rtp
,
false
);
}
}
else
{
//视频
auto
&
src
=
_push_src_simulcast
[
rid
];
if
(
!
src
)
{
auto
stream_id
=
rid
.
empty
()
?
_push_src
->
getId
()
:
_push_src
->
getId
()
+
"_"
+
rid
;
auto
src_imp
=
std
::
make_shared
<
RtspMediaSourceImp
>
(
_push_src
->
getVhost
(),
_push_src
->
getApp
(),
stream_id
);
src_imp
->
setSdp
(
_push_src
->
getSdp
());
src_imp
->
setProtocolTranslation
(
_push_src
->
isRecording
(
Recorder
::
type_hls
),
_push_src
->
isRecording
(
Recorder
::
type_mp4
));
src_imp
->
setListener
(
static_pointer_cast
<
WebRtcTransportImp
>
(
shared_from_this
()));
src
=
src_imp
;
}
src
->
onWrite
(
std
::
move
(
rtp
),
false
);
}
}
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
void
WebRtcTransportImp
::
onSendRtp
(
const
RtpPacket
::
Ptr
&
rtp
,
bool
flush
,
bool
rtx
){
void
WebRtcTransportImp
::
onSendRtp
(
const
RtpPacket
::
Ptr
&
rtp
,
bool
flush
,
bool
rtx
)
{
auto
&
track
=
_type_to_track
[
rtp
->
type
];
auto
&
track
=
_type_to_track
[
rtp
->
type
];
if
(
!
track
)
{
if
(
!
track
)
{
//忽略,对方不支持该编码类型
//忽略,对方不支持该编码类型
...
@@ -969,47 +838,23 @@ void WebRtcTransportImp::onShutdown(const SockException &ex){
...
@@ -969,47 +838,23 @@ void WebRtcTransportImp::onShutdown(const SockException &ex){
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
void
WebRtcTransportImp
::
setSession
(
Session
::
Ptr
session
)
{
_session
=
std
::
move
(
session
);
bool
WebRtcTransportImp
::
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
;
weak_ptr
<
WebRtcTransportImp
>
weak_self
=
static_pointer_cast
<
WebRtcTransportImp
>
(
shared_from_this
());
getPoller
()
->
async
([
weak_self
,
err
]()
{
auto
strong_self
=
weak_self
.
lock
();
if
(
strong_self
)
{
strong_self
->
onShutdown
(
SockException
(
Err_shutdown
,
err
));
}
});
return
true
;
}
int
WebRtcTransportImp
::
totalReaderCount
(
MediaSource
&
sender
)
{
auto
total_count
=
0
;
for
(
auto
&
src
:
_push_src_simulcast
)
{
total_count
+=
src
.
second
->
totalReaderCount
();
}
return
total_count
+
_push_src
->
totalReaderCount
();
}
}
MediaOriginType
WebRtcTransportImp
::
getOriginType
(
MediaSource
&
sender
)
const
{
const
Session
::
Ptr
&
WebRtcTransportImp
::
getSession
(
)
const
{
return
MediaOriginType
::
rtc_push
;
return
_session
;
}
}
string
WebRtcTransportImp
::
getOriginUrl
(
MediaSource
&
sender
)
const
{
uint64_t
WebRtcTransportImp
::
getBytesUsage
()
const
{
return
_
media_info
.
_full_url
;
return
_
bytes_usage
;
}
}
std
::
shared_ptr
<
SockInfo
>
WebRtcTransportImp
::
getOriginSock
(
MediaSource
&
sender
)
const
{
uint64_t
WebRtcTransportImp
::
getDuration
()
const
{
return
static_pointer_cast
<
SockInfo
>
(
_session
)
;
return
_alive_ticker
.
createdTime
()
/
1000
;
}
}
void
WebRtcTransportImp
::
setSession
(
Session
::
Ptr
session
)
{
/////////////////////////////////////////////////////////////////////////////////////////////
_session
=
std
::
move
(
session
);
}
class
WebRtcTransportManager
{
class
WebRtcTransportManager
{
mutable
mutex
_mtx
;
mutable
mutex
_mtx
;
...
...
webrtc/WebRtcTransport.h
查看文件 @
7f3f47ab
...
@@ -116,8 +116,6 @@ protected:
...
@@ -116,8 +116,6 @@ protected:
virtual
void
onBeforeEncryptRtcp
(
const
char
*
buf
,
int
&
len
,
void
*
ctx
)
=
0
;
virtual
void
onBeforeEncryptRtcp
(
const
char
*
buf
,
int
&
len
,
void
*
ctx
)
=
0
;
protected
:
protected
:
RtcSession
::
Ptr
_offer_sdp
;
RtcSession
::
Ptr
_answer_sdp
;
RTC
::
TransportTuple
*
getSelectedTuple
()
const
;
RTC
::
TransportTuple
*
getSelectedTuple
()
const
;
void
sendRtcpRemb
(
uint32_t
ssrc
,
size_t
bit_rate
);
void
sendRtcpRemb
(
uint32_t
ssrc
,
size_t
bit_rate
);
void
sendRtcpPli
(
uint32_t
ssrc
);
void
sendRtcpPli
(
uint32_t
ssrc
);
...
@@ -126,6 +124,10 @@ private:
...
@@ -126,6 +124,10 @@ private:
void
onSendSockData
(
const
char
*
buf
,
size_t
len
,
bool
flush
=
true
);
void
onSendSockData
(
const
char
*
buf
,
size_t
len
,
bool
flush
=
true
);
void
setRemoteDtlsFingerprint
(
const
RtcSession
&
remote
);
void
setRemoteDtlsFingerprint
(
const
RtcSession
&
remote
);
protected
:
RtcSession
::
Ptr
_offer_sdp
;
RtcSession
::
Ptr
_answer_sdp
;
private
:
private
:
uint8_t
_srtp_buf
[
2000
];
uint8_t
_srtp_buf
[
2000
];
string
_key
;
string
_key
;
...
@@ -159,7 +161,7 @@ public:
...
@@ -159,7 +161,7 @@ public:
std
::
shared_ptr
<
RtpChannel
>
getRtpChannel
(
uint32_t
ssrc
)
const
;
std
::
shared_ptr
<
RtpChannel
>
getRtpChannel
(
uint32_t
ssrc
)
const
;
};
};
class
WebRtcTransportImp
:
public
WebRtcTransport
,
public
MediaSourceEvent
{
class
WebRtcTransportImp
:
public
WebRtcTransport
{
public
:
public
:
using
Ptr
=
std
::
shared_ptr
<
WebRtcTransportImp
>
;
using
Ptr
=
std
::
shared_ptr
<
WebRtcTransportImp
>
;
~
WebRtcTransportImp
()
override
;
~
WebRtcTransportImp
()
override
;
...
@@ -169,20 +171,19 @@ public:
...
@@ -169,20 +171,19 @@ public:
* @param poller 改对象需要绑定的线程
* @param poller 改对象需要绑定的线程
* @return 对象
* @return 对象
*/
*/
static
Ptr
create
(
const
EventPoller
::
Ptr
&
poller
);
static
Ptr
get
(
const
string
&
key
);
// 借用
static
Ptr
get
(
const
string
&
key
);
// 借用
static
Ptr
move
(
const
string
&
key
);
// 所有权转移
static
Ptr
move
(
const
string
&
key
);
// 所有权转移
void
setSession
(
Session
::
Ptr
session
);
void
setSession
(
Session
::
Ptr
session
);
const
Session
::
Ptr
&
getSession
()
const
;
/**
uint64_t
getBytesUsage
()
const
;
* 绑定rtsp媒体源
uint64_t
getDuration
()
const
;
* @param src 媒体源
bool
canSendRtp
()
const
;
* @param is_play 是播放还是推流
bool
canRecvRtp
()
const
;
*/
void
onSendRtp
(
const
RtpPacket
::
Ptr
&
rtp
,
bool
flush
,
bool
rtx
=
false
);
void
attach
(
const
RtspMediaSource
::
Ptr
&
src
,
const
MediaInfo
&
info
,
bool
is_play
=
true
);
protected
:
protected
:
WebRtcTransportImp
(
const
EventPoller
::
Ptr
&
poller
);
void
onStartWebRTC
()
override
;
void
onStartWebRTC
()
override
;
void
onSendSockData
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
,
bool
flush
=
true
)
override
;
void
onSendSockData
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
,
bool
flush
=
true
)
override
;
void
onCheckSdp
(
SdpType
type
,
RtcSession
&
sdp
)
override
;
void
onCheckSdp
(
SdpType
type
,
RtcSession
&
sdp
)
override
;
...
@@ -192,30 +193,13 @@ protected:
...
@@ -192,30 +193,13 @@ protected:
void
onRtcp
(
const
char
*
buf
,
size_t
len
)
override
;
void
onRtcp
(
const
char
*
buf
,
size_t
len
)
override
;
void
onBeforeEncryptRtp
(
const
char
*
buf
,
int
&
len
,
void
*
ctx
)
override
;
void
onBeforeEncryptRtp
(
const
char
*
buf
,
int
&
len
,
void
*
ctx
)
override
;
void
onBeforeEncryptRtcp
(
const
char
*
buf
,
int
&
len
,
void
*
ctx
)
override
{};
void
onBeforeEncryptRtcp
(
const
char
*
buf
,
int
&
len
,
void
*
ctx
)
override
{};
void
onCreate
()
override
;
void
onDestory
()
override
;
void
onShutdown
(
const
SockException
&
ex
)
override
;
void
onShutdown
(
const
SockException
&
ex
)
override
;
virtual
void
onRecvRtp
(
MediaTrack
&
track
,
const
string
&
rid
,
RtpPacket
::
Ptr
rtp
)
=
0
;
///////MediaSourceEvent override///////
// 关闭
bool
close
(
MediaSource
&
sender
,
bool
force
)
override
;
// 播放总人数
int
totalReaderCount
(
MediaSource
&
sender
)
override
;
// 获取媒体源类型
MediaOriginType
getOriginType
(
MediaSource
&
sender
)
const
override
;
// 获取媒体源url或者文件路径
string
getOriginUrl
(
MediaSource
&
sender
)
const
override
;
// 获取媒体源客户端相关信息
std
::
shared_ptr
<
SockInfo
>
getOriginSock
(
MediaSource
&
sender
)
const
override
;
private
:
private
:
WebRtcTransportImp
(
const
EventPoller
::
Ptr
&
poller
);
void
onCreate
()
override
;
void
onDestory
()
override
;
void
onSendRtp
(
const
RtpPacket
::
Ptr
&
rtp
,
bool
flush
,
bool
rtx
=
false
);
SdpAttrCandidate
::
Ptr
getIceCandidate
()
const
;
SdpAttrCandidate
::
Ptr
getIceCandidate
()
const
;
bool
canSendRtp
()
const
;
bool
canRecvRtp
()
const
;
void
onSortedRtp
(
MediaTrack
&
track
,
const
string
&
rid
,
RtpPacket
::
Ptr
rtp
);
void
onSortedRtp
(
MediaTrack
&
track
,
const
string
&
rid
,
RtpPacket
::
Ptr
rtp
);
void
onSendNack
(
MediaTrack
&
track
,
const
FCI_NACK
&
nack
,
uint32_t
ssrc
);
void
onSendNack
(
MediaTrack
&
track
,
const
FCI_NACK
&
nack
,
uint32_t
ssrc
);
void
onSendTwcc
(
uint32_t
ssrc
,
const
string
&
twcc_fci
);
void
onSendTwcc
(
uint32_t
ssrc
,
const
string
&
twcc_fci
);
...
@@ -226,14 +210,11 @@ private:
...
@@ -226,14 +210,11 @@ private:
void
onCheckAnswer
(
RtcSession
&
sdp
);
void
onCheckAnswer
(
RtcSession
&
sdp
);
private
:
private
:
bool
_simulcast
=
false
;
uint16_t
_rtx_seq
[
2
]
=
{
0
,
0
};
uint16_t
_rtx_seq
[
2
]
=
{
0
,
0
};
//用掉的总流量
//用掉的总流量
uint64_t
_bytes_usage
=
0
;
uint64_t
_bytes_usage
=
0
;
//保持自我强引用
//保持自我强引用
Ptr
_self
;
Ptr
_self
;
//媒体相关元数据
MediaInfo
_media_info
;
//检测超时的定时器
//检测超时的定时器
Timer
::
Ptr
_timer
;
Timer
::
Ptr
_timer
;
//刷新计时器
//刷新计时器
...
@@ -242,18 +223,12 @@ private:
...
@@ -242,18 +223,12 @@ private:
Ticker
_pli_ticker
;
Ticker
_pli_ticker
;
//udp session
//udp session
Session
::
Ptr
_session
;
Session
::
Ptr
_session
;
//推流的rtsp源
//twcc rtcp发送上下文对象
RtspMediaSource
::
Ptr
_push_src
;
TwccContext
_twcc_ctx
;
unordered_map
<
string
/*rid*/
,
RtspMediaSource
::
Ptr
>
_push_src_simulcast
;
//播放的rtsp源
RtspMediaSource
::
Ptr
_play_src
;
//播放rtsp源的reader对象
RtspMediaSource
::
RingType
::
RingReader
::
Ptr
_reader
;
//根据发送rtp的track类型获取相关信息
//根据发送rtp的track类型获取相关信息
MediaTrack
::
Ptr
_type_to_track
[
2
];
MediaTrack
::
Ptr
_type_to_track
[
2
];
//根据接收rtp的pt获取相关信息
unordered_map
<
uint8_t
/*pt*/
,
std
::
pair
<
bool
/*is rtx*/
,
MediaTrack
::
Ptr
>
>
_pt_to_track
;
//根据rtcp的ssrc获取相关信息,收发rtp和rtx的ssrc都会记录
//根据rtcp的ssrc获取相关信息,收发rtp和rtx的ssrc都会记录
unordered_map
<
uint32_t
/*ssrc*/
,
MediaTrack
::
Ptr
>
_ssrc_to_track
;
unordered_map
<
uint32_t
/*ssrc*/
,
MediaTrack
::
Ptr
>
_ssrc_to_track
;
TwccContext
_twcc_ctx
;
//根据接收rtp的pt获取相关信息
unordered_map
<
uint8_t
/*pt*/
,
std
::
pair
<
bool
/*is rtx*/
,
MediaTrack
::
Ptr
>
>
_pt_to_track
;
};
};
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论