数据是怎样被分离到DataChannel中的

        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;
  }
  ...
}

### WebRTC 中 DataChannel 的作用 在 WebRTC 中,DataChannel 提供了一种机制来实现实时应用之间的双向通信。这种通信不仅限于音视频流,还可以用于任意形式的数据交换[^1]。 具体来说,DataChannel 可以用来: - 发送聊天消息 - 实现点对点文件传输 - 进行游戏状态同步 - 执行远程控制命令 由于这些数据音视频共享同一个 UDP Socket,因此也继承了 NAT 穿透能力,使得即使在网络受限的情况下也能保持良好的连通性。 ### 数据传输模式 WebRTC DataChannel 支持两种不同的传输语义: - **可靠模式 (DCT_SCTP)**:确保所有发送的数据包按顺序到达接收端,适用于需要严格保证数据完整性的场景。 - **不可靠模式 (DCT_RTP)**:提供更低延迟但不保证数据包一定能够成功送达或按照特定顺序抵达,适合对实时性要求较高的应用场景[^2]。 ### 技术细节 从底层实现角度来看,WebRTC 使用 SCTP 协议作为 DataChannel 的基础传输层协议。SCTP 是一种面向连接的传输层协议,能够在单个关联中支持多个独立的消息流,并且具有内置的心跳检测和路径管理功能,这使其非常适合构建稳定可靠的 P2P 应用程序[^3]。 创建 DataChannel 需要在调用 `CreateOffer` 或者 `CreateAnswer` 方法之前执行相应的 API 调用,以便正确配置会话描述并建立通道[^4]。 ```javascript // 创建一个新的 RTCPeerConnection 对象 const pc = new RTCPeerConnection(); // 定义要创建的数据通道参数 let channelOptions = { ordered: true, // 是否启用有序传递,默认为true表示开启 }; // 建立新的 RTCDataChannel 并指定回调处理接收到的信息事件 const dataChannel = pc.createDataChannel('myLabel', channelOptions); dataChannel.onmessage = function(event) { console.log(`Received message ${event.data}`); }; // 准备发起 offer 或响应 answer... pc.createOffer().then(...).catch(...); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

airmanisvip

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值