SDP中我们启用了BUNDLE,即a=group:BUNDLE 0 1 2,这样DataChannel中的sctp数据、音频和视频数据将共用一个socket,那么怎样把sctp数据和rtp数据分离出来呢?
一、相关类
DtlsTransport
SrtpTransport,继承自RtpTransport
SctpTransport
对应关系:
一个PeerConnection对应一个JsepTransportController
一个JsepTransportController对应多个JsepTransport,一个mid对应一个,如果启用BUNDLE则多个mid最终会使用同一个JsepTransport
一个JsepTransport对应一个DtlsSrtpTransport
一个DtlsSrtpTransport对应一个DtlsTransport
一个DtlsTransport对应一个P2PTransportChannel
数据回调顺序:
P2PTransportChannel -> DtlsTransport -> SrtpTransport
-> SctpTransport(同SrtpTransport并列)
二、逻辑关系
DtslTransport作为p2p层的观察者,接收到数据后通过DtlsTransport::OnReadPacket()传出来,这里传来的是从网络收到的一手数据,OnReadPacket中需要进行判断是否是dtls数据,判断方法见IsDtlsPacket函数,如果是则进行dtls后续处理,处理完毕后通过OnDtlsEvent触发SignalReadPacket信号;如果不是则直接出发SignalReadPacket,见代码:
void DtlsTransport::OnReadPacket(rtc::PacketTransportInternal* transport,
const char* data,
size_t size,
const rtc::PacketTime& packet_time,
int flags) {
switch (dtls_state())
{
....
case DTLS_TRANSPORT_CONNECTED:
if (IsDtlsPacket(data, size)) //判断是否Dtls数据
{
if (!HandleDtlsPacket(data, size)) //处理Dtls数据
{
return;
}
}
else
{
// Signal this upwards as a bypass packet.
SignalReadPacket(this, data, size, packet_time, PF_SRTP_BYPASS);
}
}
...
}
SctpTransport 是DataChannel的传输层,也是DtlsTransport的观察者,其OnPacketRead函数被绑定到DtlsTransport的SignalReadPacket信号上;
SrtpTransport 是rtp数据的传输层,也是DtlsTransport的观察者,其OnReadPacket函数同样被绑定到DtlsTransport的SignalReadPacket信号上;
这样当SignalReadPacket信号触发时,SrtpTransport和SctpTransport均被通知到,SrtpTransport::OnReadPacket(在其父类RtpTransport中)中先判断是否是rtp,不是则直接扔掉,见代码:
void DtlsTransport::OnDtlsEvent(rtc::StreamInterface* dtls, int sig, int err)
{
...
if (sig & rtc::SE_READ)
{
...
do {
ret = dtls_->Read(buf, sizeof(buf), &read, &read_error);
if (ret == rtc::SR_SUCCESS)
{
//触发信号
SignalReadPacket(this, buf, read, rtc::CreatePacketTime(0), 0);
}
}while (ret == rtc::SR_SUCCESS);
}
....
}
void RtpTransport::OnReadPacket(rtc::PacketTransportInternal* transport,
const char* data,
size_t len,
const rtc::PacketTime& packet_time,
int flags) {
...
// Filter out the packet that is neither RTP nor RTCP.
if (!rtcp && !cricket::IsRtpPacket(data, len)) {
return;
}
...
}