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
7110dc75
Commit
7110dc75
authored
Apr 02, 2021
by
ziyue
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
整理代码
parent
33d2e713
显示空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
134 行增加
和
99 行删除
+134
-99
webrtc/Sdp.cpp
+7
-0
webrtc/Sdp.h
+2
-0
webrtc/WebRtcTransport.cpp
+67
-61
webrtc/WebRtcTransport.h
+58
-38
没有找到文件。
webrtc/Sdp.cpp
查看文件 @
7110dc75
...
...
@@ -1237,6 +1237,13 @@ shared_ptr<RtcSession> RtcConfigure::createAnswer(const RtcSession &offer){
if
(
ret
->
media
.
empty
())
{
throw
std
::
invalid_argument
(
"生成的answer sdp中媒体个数为0"
);
}
//设置音视频端口复用
if
(
!
offer
.
group
.
mids
.
empty
())
{
for
(
auto
&
m
:
ret
->
media
)
{
ret
->
group
.
mids
.
emplace_back
(
m
.
mid
);
}
}
return
ret
;
}
...
...
webrtc/Sdp.h
查看文件 @
7110dc75
...
...
@@ -437,6 +437,7 @@ public:
class
SdpAttrCandidate
:
public
SdpItem
{
public
:
using
Ptr
=
std
::
shared_ptr
<
SdpAttrCandidate
>
;
//https://tools.ietf.org/html/rfc5245
//15.1. "candidate" Attribute
//a=candidate:4 1 udp 2 192.168.1.7 58107 typ host
...
...
@@ -656,6 +657,7 @@ public:
class
RtcConfigure
{
public
:
using
Ptr
=
std
::
shared_ptr
<
RtcConfigure
>
;
class
RtcTrackConfigure
{
public
:
bool
enable
;
...
...
webrtc/WebRtcTransport.cpp
查看文件 @
7110dc75
...
...
@@ -3,19 +3,19 @@
#include "Rtcp/Rtcp.h"
WebRtcTransport
::
WebRtcTransport
(
const
EventPoller
::
Ptr
&
poller
)
{
dtls_transport_
=
std
::
make_shared
<
RTC
::
DtlsTransport
>
(
poller
,
this
);
ice_server_
=
std
::
make_shared
<
RTC
::
IceServer
>
(
this
,
makeRandStr
(
4
),
makeRandStr
(
24
));
_dtls_transport
=
std
::
make_shared
<
RTC
::
DtlsTransport
>
(
poller
,
this
);
_ice_server
=
std
::
make_shared
<
RTC
::
IceServer
>
(
this
,
makeRandStr
(
4
),
makeRandStr
(
24
));
}
void
WebRtcTransport
::
onDestory
(){
dtls_transport_
=
nullptr
;
ice_server_
=
nullptr
;
_dtls_transport
=
nullptr
;
_ice_server
=
nullptr
;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
WebRtcTransport
::
OnIceServerSendStunPacket
(
const
RTC
::
IceServer
*
iceServer
,
const
RTC
::
StunPacket
*
packet
,
RTC
::
TransportTuple
*
tuple
)
{
on
Write
((
char
*
)
packet
->
GetData
(),
packet
->
GetSize
(),
(
struct
sockaddr_in
*
)
tuple
);
on
SendSockData
((
char
*
)
packet
->
GetData
(),
packet
->
GetSize
(),
(
struct
sockaddr_in
*
)
tuple
);
}
void
WebRtcTransport
::
OnIceServerSelectedTuple
(
const
RTC
::
IceServer
*
iceServer
,
RTC
::
TransportTuple
*
tuple
)
{
...
...
@@ -29,9 +29,9 @@ void WebRtcTransport::OnIceServerConnected(const RTC::IceServer *iceServer) {
void
WebRtcTransport
::
OnIceServerCompleted
(
const
RTC
::
IceServer
*
iceServer
)
{
InfoL
;
if
(
_answer_sdp
->
media
[
0
].
role
==
DtlsRole
::
passive
)
{
dtls_transport_
->
Run
(
RTC
::
DtlsTransport
::
Role
::
SERVER
);
_dtls_transport
->
Run
(
RTC
::
DtlsTransport
::
Role
::
SERVER
);
}
else
{
dtls_transport_
->
Run
(
RTC
::
DtlsTransport
::
Role
::
CLIENT
);
_dtls_transport
->
Run
(
RTC
::
DtlsTransport
::
Role
::
CLIENT
);
}
}
...
...
@@ -50,21 +50,21 @@ void WebRtcTransport::OnDtlsTransportConnected(
size_t
srtpRemoteKeyLen
,
std
::
string
&
remoteCert
)
{
InfoL
;
srtp_session_
=
std
::
make_shared
<
RTC
::
SrtpSession
>
(
RTC
::
SrtpSession
::
Type
::
OUTBOUND
,
srtpCryptoSuite
,
srtpLocalKey
,
srtpLocalKeyLen
);
srtp_session_recv_
=
std
::
make_shared
<
RTC
::
SrtpSession
>
(
RTC
::
SrtpSession
::
Type
::
OUTBOUND
,
srtpCryptoSuite
,
srtpRemoteKey
,
srtpRemoteKeyLen
);
on
DtlsConnected
();
_srtp_session_send
=
std
::
make_shared
<
RTC
::
SrtpSession
>
(
RTC
::
SrtpSession
::
Type
::
OUTBOUND
,
srtpCryptoSuite
,
srtpLocalKey
,
srtpLocalKeyLen
);
_srtp_session_recv
=
std
::
make_shared
<
RTC
::
SrtpSession
>
(
RTC
::
SrtpSession
::
Type
::
OUTBOUND
,
srtpCryptoSuite
,
srtpRemoteKey
,
srtpRemoteKeyLen
);
on
StartWebRTC
();
}
void
WebRtcTransport
::
OnDtlsTransportSendData
(
const
RTC
::
DtlsTransport
*
dtlsTransport
,
const
uint8_t
*
data
,
size_t
len
)
{
on
Write
((
char
*
)
data
,
len
);
on
SendSockData
((
char
*
)
data
,
len
);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
WebRtcTransport
::
on
Write
(
const
char
*
buf
,
size_t
len
){
auto
tuple
=
ice_server_
->
GetSelectedTuple
();
void
WebRtcTransport
::
on
SendSockData
(
const
char
*
buf
,
size_t
len
){
auto
tuple
=
_ice_server
->
GetSelectedTuple
();
assert
(
tuple
);
on
Write
(
buf
,
len
,
(
struct
sockaddr_in
*
)
tuple
);
on
SendSockData
(
buf
,
len
,
(
struct
sockaddr_in
*
)
tuple
);
}
string
getFingerprint
(
const
string
&
algorithm_str
,
const
std
::
shared_ptr
<
RTC
::
DtlsTransport
>
&
transport
){
...
...
@@ -77,46 +77,47 @@ string getFingerprint(const string &algorithm_str, const std::shared_ptr<RTC::Dt
throw
std
::
invalid_argument
(
StrPrinter
<<
"不支持的加密算法:"
<<
algorithm_str
);
}
void
WebRtcTransport
::
setRemoteDtlsFingerprint
(
const
RtcSession
&
remote
){
//设置远端dtls签名
RTC
::
DtlsTransport
::
Fingerprint
remote_fingerprint
;
remote_fingerprint
.
algorithm
=
RTC
::
DtlsTransport
::
GetFingerprintAlgorithm
(
_offer_sdp
->
media
[
0
].
fingerprint
.
algorithm
);
remote_fingerprint
.
value
=
_offer_sdp
->
media
[
0
].
fingerprint
.
hash
;
_dtls_transport
->
SetRemoteFingerprint
(
remote_fingerprint
);
}
void
WebRtcTransport
::
onCheckSdp
(
SdpType
type
,
const
RtcSession
&
sdp
)
const
{
for
(
auto
&
m
:
sdp
.
media
)
{
if
(
m
.
type
!=
TrackApplication
&&
!
m
.
rtcp_mux
)
{
throw
std
::
invalid_argument
(
"只支持rtcp-mux模式"
);
}
}
if
(
sdp
.
group
.
mids
.
empty
())
{
throw
std
::
invalid_argument
(
"只支持group BUNDLE模式"
);
}
}
std
::
string
WebRtcTransport
::
getAnswerSdp
(
const
string
&
offer
){
// InfoL << offer;
//// 解析offer sdp ////
_offer_sdp
=
std
::
make_shared
<
RtcSession
>
();
_offer_sdp
->
loadFrom
(
offer
);
onCheckSdp
(
SdpType
::
offer
,
*
_offer_sdp
);
setRemoteDtlsFingerprint
(
*
_offer_sdp
);
//// sdp 配置 ////
SdpAttrFingerprint
fingerprint
;
fingerprint
.
algorithm
=
_offer_sdp
->
media
[
0
].
fingerprint
.
algorithm
;
fingerprint
.
hash
=
getFingerprint
(
fingerprint
.
algorithm
,
dtls_transport_
);
fingerprint
.
hash
=
getFingerprint
(
fingerprint
.
algorithm
,
_dtls_transport
);
RtcConfigure
configure
;
configure
.
setDefaultSetting
(
ice_server_
->
GetUsernameFragment
(),
ice_server_
->
GetPassword
(),
RtpDirection
::
recvonly
,
fingerprint
);
SdpAttrCandidate
candidate
;
candidate
.
foundation
=
"udpcandidate"
;
candidate
.
component
=
1
;
candidate
.
transport
=
"udp"
;
candidate
.
priority
=
getSSRC
();
candidate
.
address
=
getIP
();
candidate
.
port
=
getPort
();
candidate
.
type
=
"host"
;
configure
.
addCandidate
(
candidate
);
configure
.
setDefaultSetting
(
_ice_server
->
GetUsernameFragment
(),
_ice_server
->
GetPassword
(),
RtpDirection
::
recvonly
,
fingerprint
);
configure
.
addCandidate
(
*
getIceCandidate
());
onRtcConfigure
(
configure
);
//// 生成answer sdp ////
_answer_sdp
=
configure
.
createAnswer
(
*
_offer_sdp
);
//设置远端dtls签名
RTC
::
DtlsTransport
::
Fingerprint
remote_fingerprint
;
remote_fingerprint
.
algorithm
=
RTC
::
DtlsTransport
::
GetFingerprintAlgorithm
(
_offer_sdp
->
media
[
0
].
fingerprint
.
algorithm
);
remote_fingerprint
.
value
=
_offer_sdp
->
media
[
0
].
fingerprint
.
hash
;
dtls_transport_
->
SetRemoteFingerprint
(
remote_fingerprint
);
if
(
!
_offer_sdp
->
group
.
mids
.
empty
())
{
for
(
auto
&
m
:
_answer_sdp
->
media
)
{
_answer_sdp
->
group
.
mids
.
emplace_back
(
m
.
mid
);
}
}
else
{
throw
std
::
invalid_argument
(
"支持group BUNDLE模式"
);
}
onCheckSdp
(
SdpType
::
answer
,
*
_answer_sdp
);
auto
str
=
_answer_sdp
->
toString
();
Info
L
<<
"
\r\n
"
<<
str
;
Trace
L
<<
"
\r\n
"
<<
str
;
return
str
;
}
...
...
@@ -134,18 +135,18 @@ bool is_rtcp(char *buf) {
return
((
header
->
pt
>=
64
)
&&
(
header
->
pt
<
96
));
}
void
WebRtcTransport
::
OnInputDataPacket
(
char
*
buf
,
size_t
len
,
RTC
::
TransportTuple
*
tuple
)
{
void
WebRtcTransport
::
inputSockData
(
char
*
buf
,
size_t
len
,
RTC
::
TransportTuple
*
tuple
)
{
if
(
RTC
::
StunPacket
::
IsStun
((
const
uint8_t
*
)
buf
,
len
))
{
RTC
::
StunPacket
*
packet
=
RTC
::
StunPacket
::
Parse
((
const
uint8_t
*
)
buf
,
len
);
if
(
packet
==
nullptr
)
{
WarnL
<<
"parse stun error"
<<
std
::
endl
;
return
;
}
ice_server_
->
ProcessStunPacket
(
packet
,
tuple
);
_ice_server
->
ProcessStunPacket
(
packet
,
tuple
);
return
;
}
if
(
is_dtls
(
buf
))
{
dtls_transport_
->
ProcessDtlsData
((
uint8_t
*
)
buf
,
len
);
_dtls_transport
->
ProcessDtlsData
((
uint8_t
*
)
buf
,
len
);
return
;
}
if
(
is_rtp
(
buf
))
{
...
...
@@ -158,14 +159,14 @@ void WebRtcTransport::OnInputDataPacket(char *buf, size_t len, RTC::TransportTup
}
}
void
WebRtcTransport
::
Writ
RtpPacket
(
char
*
buf
,
size_t
len
)
{
void
WebRtcTransport
::
send
RtpPacket
(
char
*
buf
,
size_t
len
)
{
const
uint8_t
*
p
=
(
uint8_t
*
)
buf
;
bool
ret
=
false
;
if
(
srtp_session_
)
{
ret
=
srtp_session_
->
EncryptRtp
(
&
p
,
&
len
);
if
(
_srtp_session_send
)
{
ret
=
_srtp_session_send
->
EncryptRtp
(
&
p
,
&
len
);
}
if
(
ret
)
{
on
Write
((
char
*
)
p
,
len
);
on
SendSockData
((
char
*
)
p
,
len
);
}
}
...
...
@@ -183,7 +184,7 @@ WebRtcTransportImp::WebRtcTransportImp(const EventPoller::Ptr &poller) : WebRtcT
//随机端口,绑定全部网卡
_socket
->
bindUdpSock
(
0
);
_socket
->
setOnRead
([
this
](
const
Buffer
::
Ptr
&
buf
,
struct
sockaddr
*
addr
,
int
addr_len
)
mutable
{
OnInputDataPacket
(
buf
->
data
(),
buf
->
size
(),
addr
);
inputSockData
(
buf
->
data
(),
buf
->
size
(),
addr
);
});
}
...
...
@@ -196,7 +197,7 @@ void WebRtcTransportImp::attach(const RtspMediaSource::Ptr &src) {
_src
=
src
;
}
void
WebRtcTransportImp
::
on
DtlsConnected
()
{
void
WebRtcTransportImp
::
on
StartWebRTC
()
{
_reader
=
_src
->
getRing
()
->
attach
(
_socket
->
getPoller
(),
true
);
weak_ptr
<
WebRtcTransportImp
>
weak_self
=
shared_from_this
();
_reader
->
setReadCB
([
weak_self
](
const
RtspMediaSource
::
RingDataType
&
pkt
){
...
...
@@ -207,14 +208,14 @@ void WebRtcTransportImp::onDtlsConnected() {
pkt
->
for_each
([
&
](
const
RtpPacket
::
Ptr
&
rtp
)
{
if
(
rtp
->
type
==
TrackVideo
)
{
//目前只支持视频
strongSelf
->
Writ
RtpPacket
(
rtp
->
data
()
+
RtpPacket
::
kRtpTcpHeaderSize
,
strongSelf
->
send
RtpPacket
(
rtp
->
data
()
+
RtpPacket
::
kRtpTcpHeaderSize
,
rtp
->
size
()
-
RtpPacket
::
kRtpTcpHeaderSize
);
}
});
});
}
void
WebRtcTransportImp
::
on
Write
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
)
{
void
WebRtcTransportImp
::
on
SendSockData
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
)
{
auto
ptr
=
BufferRaw
::
create
();
ptr
->
assign
(
buf
,
len
);
_socket
->
send
(
ptr
,
(
struct
sockaddr
*
)(
dst
),
sizeof
(
struct
sockaddr
));
...
...
@@ -224,13 +225,6 @@ uint32_t WebRtcTransportImp::getSSRC() const {
return
_src
->
getSsrc
(
TrackVideo
);
}
int
WebRtcTransportImp
::
getPayloadType
()
const
{
auto
sdp
=
SdpParser
(
_src
->
getSdp
());
auto
track
=
sdp
.
getTrack
(
TrackVideo
);
assert
(
track
);
return
track
?
track
->
_pt
:
0
;
}
uint16_t
WebRtcTransportImp
::
getPort
()
const
{
//todo udp端口号应该与外网映射端口相同
return
_socket
->
get_local_port
();
...
...
@@ -241,6 +235,18 @@ std::string WebRtcTransportImp::getIP() const {
return
SockUtil
::
get_local_ip
();
}
SdpAttrCandidate
::
Ptr
WebRtcTransportImp
::
getIceCandidate
()
const
{
auto
candidate
=
std
::
make_shared
<
SdpAttrCandidate
>
();
candidate
->
foundation
=
"udpcandidate"
;
candidate
->
component
=
1
;
candidate
->
transport
=
"udp"
;
candidate
->
priority
=
100
;
candidate
->
address
=
getIP
();
candidate
->
port
=
getPort
();
candidate
->
type
=
"host"
;
return
candidate
;
}
///////////////////////////////////////////////////////////////////
...
...
webrtc/WebRtcTransport.h
查看文件 @
7110dc75
...
...
@@ -2,12 +2,16 @@
#include <memory>
#include <string>
#include "DtlsTransport.hpp"
#include "IceServer.hpp"
#include "SrtpSession.hpp"
#include "StunPacket.hpp"
#include "Sdp.h"
#include "Poller/EventPoller.h"
#include "Network/Socket.h"
#include "Rtsp/RtspMediaSource.h"
using
namespace
toolkit
;
using
namespace
mediakit
;
class
WebRtcTransport
:
public
RTC
::
DtlsTransport
::
Listener
,
public
RTC
::
IceServer
::
Listener
{
public
:
...
...
@@ -15,27 +19,37 @@ public:
WebRtcTransport
(
const
EventPoller
::
Ptr
&
poller
);
~
WebRtcTransport
()
override
=
default
;
/// 销毁对象
/**
* 消费对象
*/
virtual
void
onDestory
();
/**
* 创建webrtc answer sdp
* @param offer offer sdp
* @return answer sdp
*/
std
::
string
getAnswerSdp
(
const
string
&
offer
);
/// 收到udp数据
/// \param buf
/// \param len
/// \param remote_address
void
OnInputDataPacket
(
char
*
buf
,
size_t
len
,
RTC
::
TransportTuple
*
tuple
);
/// 发送rtp
/// \param buf
/// \param len
void
WritRtpPacket
(
char
*
buf
,
size_t
len
);
/**
* socket收到udp数据
* @param buf 数据指针
* @param len 数据长度
* @param tuple 数据来源
*/
void
inputSockData
(
char
*
buf
,
size_t
len
,
RTC
::
TransportTuple
*
tuple
);
/**
* 发送rtp
* @param buf rtcp内容
* @param len rtcp长度
*/
void
sendRtpPacket
(
char
*
buf
,
size_t
len
);
protected
:
//
dtls相关的回调
//
// dtls相关的回调 ////
void
OnDtlsTransportConnecting
(
const
RTC
::
DtlsTransport
*
dtlsTransport
)
override
{};
void
OnDtlsTransportConnected
(
const
RTC
::
DtlsTransport
*
dtlsTransport
,
void
OnDtlsTransportConnected
(
const
RTC
::
DtlsTransport
*
dtlsTransport
,
RTC
::
SrtpSession
::
CryptoSuite
srtpCryptoSuite
,
uint8_t
*
srtpLocalKey
,
size_t
srtpLocalKeyLen
,
...
...
@@ -49,7 +63,7 @@ protected:
void
OnDtlsTransportApplicationDataReceived
(
const
RTC
::
DtlsTransport
*
dtlsTransport
,
const
uint8_t
*
data
,
size_t
len
)
override
{};
protected
:
//
ice相关的回调
//
// ice相关的回调 ///
void
OnIceServerSendStunPacket
(
const
RTC
::
IceServer
*
iceServer
,
const
RTC
::
StunPacket
*
packet
,
RTC
::
TransportTuple
*
tuple
)
override
;
void
OnIceServerSelectedTuple
(
const
RTC
::
IceServer
*
iceServer
,
RTC
::
TransportTuple
*
tuple
)
override
;
void
OnIceServerConnected
(
const
RTC
::
IceServer
*
iceServer
)
override
;
...
...
@@ -57,51 +71,57 @@ protected:
void
OnIceServerDisconnected
(
const
RTC
::
IceServer
*
iceServer
)
override
;
protected
:
/// 输出udp数据
/// \param buf
/// \param len
/// \param dst
virtual
void
onWrite
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
)
=
0
;
virtual
uint32_t
getSSRC
()
const
=
0
;
virtual
uint16_t
getPort
()
const
=
0
;
virtual
std
::
string
getIP
()
const
=
0
;
virtual
int
getPayloadType
()
const
=
0
;
virtual
void
onDtlsConnected
()
=
0
;
virtual
void
onStartWebRTC
()
=
0
;
virtual
void
onRtcConfigure
(
RtcConfigure
&
configure
)
const
{}
virtual
void
onCheckSdp
(
SdpType
type
,
const
RtcSession
&
sdp
)
const
;
virtual
SdpAttrCandidate
::
Ptr
getIceCandidate
()
const
=
0
;
virtual
void
onSendSockData
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
)
=
0
;
private
:
void
onWrite
(
const
char
*
buf
,
size_t
len
);
void
onSendSockData
(
const
char
*
buf
,
size_t
len
);
void
setRemoteDtlsFingerprint
(
const
RtcSession
&
remote
);
private
:
std
::
shared_ptr
<
RTC
::
IceServer
>
ice_server_
;
std
::
shared_ptr
<
RTC
::
DtlsTransport
>
dtls_transport_
;
std
::
shared_ptr
<
RTC
::
SrtpSession
>
srtp_session_
;
std
::
shared_ptr
<
RTC
::
SrtpSession
>
srtp_session_recv_
;
std
::
shared_ptr
<
RTC
::
IceServer
>
_ice_server
;
std
::
shared_ptr
<
RTC
::
DtlsTransport
>
_dtls_transport
;
std
::
shared_ptr
<
RTC
::
SrtpSession
>
_srtp_session_send
;
std
::
shared_ptr
<
RTC
::
SrtpSession
>
_srtp_session_recv
;
RtcSession
::
Ptr
_offer_sdp
;
RtcSession
::
Ptr
_answer_sdp
;
};
#include "Poller/EventPoller.h"
#include "Network/Socket.h"
#include "Rtsp/RtspMediaSource.h"
using
namespace
toolkit
;
using
namespace
mediakit
;
class
WebRtcTransportImp
:
public
WebRtcTransport
,
public
std
::
enable_shared_from_this
<
WebRtcTransportImp
>
{
public
:
using
Ptr
=
std
::
shared_ptr
<
WebRtcTransportImp
>
;
~
WebRtcTransportImp
()
override
=
default
;
/**
* 创建WebRTC对象
* @param poller 改对象需要绑定的线程
* @return 对象
*/
static
Ptr
create
(
const
EventPoller
::
Ptr
&
poller
);
~
WebRtcTransportImp
()
override
=
default
;
/**
* 绑定rtsp媒体源
* @param src 媒体源
*/
void
attach
(
const
RtspMediaSource
::
Ptr
&
src
);
protected
:
void
on
Write
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
)
override
;
int
getPayloadType
()
const
override
;
void
on
StartWebRTC
(
)
override
;
void
onSendSockData
(
const
char
*
buf
,
size_t
len
,
struct
sockaddr_in
*
dst
)
override
;
uint32_t
getSSRC
()
const
override
;
uint16_t
getPort
()
const
override
;
std
::
string
getIP
()
const
override
;
void
onDtlsConnected
()
override
;
SdpAttrCandidate
::
Ptr
getIceCandidate
()
const
override
;
private
:
WebRtcTransportImp
(
const
EventPoller
::
Ptr
&
poller
);
void
onDestory
()
override
;
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论