mediasoup Transport详解与代码实现

mediasoup的Transport体系是连接WebRTC客户端与服务器媒体处理核心的桥梁。基于其通信框架,Transport负责管理网络连接、传输协议以及数据流转发。以下是各Transport类型的结构化整理,包含其核心功能、适用场景及关键代码实现。

一、Transport体系架构概览

mediasoup的Transport继承体系采用分层设计,
所有Transport都继承自基类RTC::Transport::Transport,共享以下核心能力:

  • 生产者/消费者管理 :维护ProducerConsumer的映射表
  • RTP/RTCP处理:提供数据包收发的基础接口
  • 状态管理:跟踪传输连接状态
  • 统计信息收集:收集字节数、数据包数等指标

二、WebRtcTransport:WebRTC标准传输

2.1 功能特性

  • 完整WebRTC协议栈:集成ICE、DTLS、SRTP、SCTP
  • NAT穿透:支持STUN和TURN服务器
  • 双栈支持:同时监听UDP和TCP端口
  • 端口聚合:可通过WebRtcServer共享端口资源

2.2 核心代码实现

2.2.1 构造函数与Socket创建

cpp 复制代码
// 构造函数逻辑
WebRtcTransport::WebRtcTransport(
    RTC::Shared* shared,
    const std::string& id,
    RTC::Transport::Listener* listener,
    const FBS::WebRtcTransport::WebRtcTransportOptions* options)
    : RTC::Transport::Transport(shared, id, listener, options->base())
{
    // 检查是否使用WebRtcServer
    if (options->webRtcServerId())
    {
        // 从shared中查找WebRtcServer
        this->webRtcServer = shared->GetWebRtcServer(options->webRtcServerId()->str());
        if (!this->webRtcServer)
            MS_THROW_ERROR("WebRtcServer not found");
        
        // 注册到WebRtcServer
        this->webRtcServer->AddWebRtcTransport(this);
    }
    else
    {
        // 独立创建Socket(逻辑与WebRtcServer类似)
        const auto* listenInfos = options->listenInfos();
        for (const auto* listenInfo : *listenInfos)
        {
            if (listenInfo->protocol() == FBS::Transport::Protocol::UDP)
            {
                // 创建UdpSocket
                this->udpSocket = new RTC::UdpSocket(
                    this,
                    listenInfo->ip()->str(),
                    listenInfo->port(),
                    listenInfo->flags());
            }
            else if (listenInfo->protocol() == FBS::Transport::Protocol::TCP)
            {
                // 创建TcpServer
                this->tcpServer = new RTC::TcpServer(
                    this,
                    this,
                    listenInfo->ip()->str(),
                    listenInfo->port(),
                    listenInfo->flags());
            }
        }
    }
    
    // 创建ICE和DTLS组件
    this->iceServer = new RTC::IceServer(this, options->iceParameters());
    this->dtlsTransport = new RTC::DtlsTransport(this, options->dtlsParameters());
}

2.2.2 数据接收流程

cpp 复制代码
// UDP数据接收(WebRtcServer转发或直接接收)
void WebRtcTransport::OnUdpSocketPacketReceived(
    RTC::UdpSocket* socket,
    const uint8_t* data,
    size_t len,
    const struct sockaddr* remoteAddr)
{
    // 创建TransportTuple标识连接
    RTC::TransportTuple tuple(socket, remoteAddr);
    
    // 检查是否是STUN报文
    if (RTC::StunPacket::IsStun(data, len))
    {
        // 处理ICE连接检查
        this->iceServer->ProcessStunPacket(&tuple, data, len);
    }
    // 检查是否是DTLS报文
    else if (RTC::DtlsTransport::IsDtls(data, len))
    {
        // 转发到DTLS层处理
        this->dtlsTransport->ProcessDtlsData(data, len, &tuple);
    }
    // 检查是否是RTP/RTCP报文
    else if (RTC::RtpPacket::IsRtp(data, len) || RTC::RtcpPacket::IsRtcp(data, len))
    {
        // 检查SRTP解密会话是否已建立
        if (this->srtpRecvSession)
        {
            // 解密并处理RTP/RTCP
            this->HandleRtpOrRtcpPacket(data, len, &tuple);
        }
    }
}

// TCP连接处理
void WebRtcTransport::OnTcpConnectionClosed(
    RTC::TcpConnection* connection)
{
    // 查找并清理对应的TransportTuple
    auto it = this->tupleTcpConnections.find(connection);
    if (it != this->tupleTcpConnections.end())
    {
        RTC::TransportTuple* tuple = it->second;
        // 清理ICE和DTLS状态
        this->iceServer->RemoveTuple(tuple);
        this->dtlsTransport->RemoveTuple(tuple);
        delete tuple;
        this->tupleTcpConnections.erase(it);
    }
}

三、PlainTransport:简单协议传输

3.1 功能特性

  • 轻量级协议:支持UDP、TCP(可选)
  • 无加密传输:可选SRTP加密
  • COMEDIA模式:支持反向连接(客户端连接服务器)
  • 第三方集成:专为FFmpeg、GStreamer等工具设计

3.2 核心代码实现

3.2.1 构造函数与配置

cpp 复制代码
PlainTransport::PlainTransport(
    RTC::Shared* shared,
    const std::string& id,
    RTC::Transport::Listener* listener,
    const FBS::PlainTransport::PlainTransportOptions* options)
    : RTC::Transport::Transport(shared, id, listener, options->base())
{
    // 解析配置选项
    this->comedia = options->comedia();
    this->rtcpMux = options->rtcpMux();
    
    // 创建UDP Socket(支持端口范围)
    const auto* listenInfo = options->listenInfo();
    if (listenInfo->portRange()->min() != 0 && listenInfo->portRange()->max() != 0)
    {
        uint64_t portRangeHash = 0u;
        this->udpSocket = new RTC::UdpSocket(
            this,
            listenInfo->ip()->str(),
            listenInfo->portRange()->min(),
            listenInfo->portRange()->max(),
            listenInfo->flags(),
            portRangeHash);
    }
    else
    {
        this->udpSocket = new RTC::UdpSocket(
            this,
            listenInfo->ip()->str(),
            listenInfo->port(),
            listenInfo->flags());
    }
    
    // 配置SRTP(如果启用)
    if (options->srtpParameters())
    {
        this->srtpSendSession = new RTC::SrtpSession(
            RTC::SrtpSession::Type::OUTBOUND,
            options->srtpParameters()->cryptoSuite()->str(),
            options->srtpParameters()->keyBase64()->str());
            
        this->srtpRecvSession = new RTC::SrtpSession(
            RTC::SrtpSession::Type::INBOUND,
            options->srtpParameters()->cryptoSuite()->str(),
            options->srtpParameters()->keyBase64()->str());
    }
}

3.2.2 COMEDIA模式处理

cpp 复制代码
// COMEDIA模式:等待客户端连接
void PlainTransport::OnUdpSocketPacketReceived(
    RTC::UdpSocket* socket,
    const uint8_t* data,
    size_t len,
    const struct sockaddr* remoteAddr)
{
    // 创建tuple标识
    RTC::TransportTuple tuple(socket, remoteAddr);
    
    // 如果是COMEDIA模式且尚未建立连接
    if (this->comedia && !this->tuple)
    {
        // 保存第一个连接的客户端地址
        this->tuple = new RTC::TransportTuple(tuple);
        
        // 通知监听者连接已建立
        this->listener->OnPlainTransportConnected(this);
    }
    
    // 检查tuple是否匹配
    if (this->tuple && *this->tuple == tuple)
    {
        // 处理数据包
        this->HandleIncomingPacket(data, len);
    }
}

// 数据包处理
void PlainTransport::HandleIncomingPacket(const uint8_t* data, size_t len)
{
    // 检查是否是RTP/RTCP
    if (RTC::RtpPacket::IsRtp(data, len))
    {
        if (this->srtpRecvSession)
        {
            // SRTP解密
            size_t decryptedLen = len;
            if (!this->srtpRecvSession->DecryptSrtp(
                const_cast<uint8_t*>(data), &decryptedLen))
            {
                MS_WARN_TAG(plain_transport, "SRTP解密失败");
                return;
            }
        }
        
        // 创建RTP包并分发
        auto* packet = RTC::RtpPacket::Parse(data, len);
        if (packet)
        {
            this->ReceiveRtpPacket(packet);
            delete packet;
        }
    }
    else if (RTC::RtcpPacket::IsRtcp(data, len))
    {
        // RTCP处理逻辑类似
        this->ReceiveRtcpPacket(data, len);
    }
}

四、PipeTransport:路由器间传输

4.1 功能特性

  • 路由器级联:连接同一主机或不同主机的Router实例
  • UDP专有:仅支持UDP协议
  • 元数据传递:支持携带Producer/Consumer ID等元数据
  • 高效转发:避免不必要的编码/解码

4.2 核心代码实现

4.2.1 数据包封装格式

cpp 复制代码
// PipeTransport数据包头部结构
struct PipePacketHeader
{
    uint8_t version;          // 协议版本
    uint8_t packetType;       // 包类型:RTP、RTCP、通知等
    uint16_t payloadLength;   // 有效载荷长度
    uint32_t routerId;        // 源路由器ID
    uint32_t producerId;      // 生产者ID(可选)
    uint32_t consumerId;      // 消费者ID(可选)
    uint64_t timestamp;       // 时间戳
    // 后续为实际RTP/RTCP数据
};

// 数据包类型枚举
enum PipePacketType : uint8_t
{
    RTP = 0x01,
    RTCP = 0x02,
    PRODUCER_CLOSED = 0x10,
    CONSUMER_PAUSED = 0x11,
    CONSUMER_RESUMED = 0x12
};

4.2.2 数据发送逻辑

cpp 复制代码
void PipeTransport::SendRtpPacket(
    RTC::RtpPacket* packet,
    RTC::Transport::Consumer* consumer)
{
    // 构建PipeTransport头部
    const size_t headerSize = sizeof(PipePacketHeader);
    const size_t packetSize = headerSize + packet->GetSize();
    
    uint8_t* buffer = new uint8_t[packetSize];
    PipePacketHeader* header = reinterpret_cast<PipePacketHeader*>(buffer);
    
    // 填充头部信息
    header->version = 1;
    header->packetType = PipePacketType::RTP;
    header->payloadLength = static_cast<uint16_t>(packet->GetSize());
    header->routerId = this->router->GetId();
    
    if (consumer)
    {
        header->consumerId = consumer->id;
    }
    
    header->timestamp = uv_hrtime(); // 高精度时间戳
    
    // 拷贝RTP数据
    std::memcpy(buffer + headerSize, packet->GetData(), packet->GetSize());
    
    // 通过UDP Socket发送
    if (this->udpSocket && this->remoteAddr)
    {
        this->udpSocket->Send(buffer, packetSize, this->remoteAddr);
    }
    
    delete[] buffer;
}

// 数据接收处理
void PipeTransport::OnUdpSocketPacketReceived(
    RTC::UdpSocket* socket,
    const uint8_t* data,
    size_t len,
    const struct sockaddr* remoteAddr)
{
    // 验证数据包长度
    if (len < sizeof(PipePacketHeader))
        return;
    
    const PipePacketHeader* header = reinterpret_cast<const PipePacketHeader*>(data);
    
    // 验证协议版本
    if (header->version != 1)
        return;
    
    // 根据包类型处理
    switch (header->packetType)
    {
        case PipePacketType::RTP:
        {
            // 提取RTP数据
            const uint8_t* rtpData = data + sizeof(PipePacketHeader);
            size_t rtpLen = header->payloadLength;
            
            // 解析RTP包
            auto* packet = RTC::RtpPacket::Parse(rtpData, rtpLen);
            if (packet)
            {
                // 根据consumerId查找目标Consumer
                if (header->consumerId != 0)
                {
                    auto* consumer = this->GetConsumerById(header->consumerId);
                    if (consumer)
                    {
                        consumer->ReceiveRtpPacket(packet);
                    }
                }
                delete packet;
            }
            break;
        }
        
        case PipePacketType::PRODUCER_CLOSED:
            // 处理Producer关闭通知
            this->HandleProducerClosed(header->producerId);
            break;
            
        // 其他包类型处理...
    }
}

五、Transport对比与应用场景

特性 WebRtcTransport PlainTransport PipeTransport
协议支持 UDP/TCP + ICE/DTLS/SRTP/SCTP UDP (TCP可选) + 可选SRTP UDP only
加密 强制DTLS-SRTP 可选SRTP 无加密
NAT穿透 完整ICE支持
使用场景 WebRTC客户端连接 第三方媒体工具集成 路由器间级联
复杂度
延迟 较高(协议开销) 最低
数据示例 {type: "webrtc", iceParameters: {...}, dtlsParameters: {...}} {type: "plain", comedia: true, rtcpMux: false} {type: "pipe", listenIp: "127.0.0.1", port: 5000}

六、实际应用示例

6.1 Node.js API使用

javascript 复制代码
// 创建WebRtcTransport
const webRtcTransport = await router.createWebRtcTransport({
    listenIps: [{ ip: "0.0.0.0", announcedIp: "192.168.1.100" }],
    enableUdp: true,
    enableTcp: true,
    preferUdp: true,
    initialAvailableOutgoingBitrate: 1000000
});

// 创建PlainTransport(用于FFmpeg推流)
const plainTransport = await router.createPlainTransport({
    listenIp: { ip: "0.0.0.0", announcedIp: "192.168.1.100" },
    rtcpMux: false,
    comedia: true  // 等待FFmpeg连接
});

// 创建PipeTransport(连接两个Router)
const pipeTransport = await router1.createPipeTransport({
    listenIp: { ip: "127.0.0.1", announcedIp: null },
    port: 5000
});

// 连接到另一个Router
await pipeTransport.connect({
    ip: "127.0.0.1",
    port: 5001,
    routerId: router2.id
});

6.2 性能优化建议

  1. 缓冲区管理
cpp 复制代码
// 使用预分配缓冲区池减少内存分配
class BufferPool {
public:
    BufferPool(size_t bufferSize, size_t poolSize) {
        for (size_t i = 0; i < poolSize; ++i) {
            buffers_.push(new uint8_t[bufferSize]);
        }
    }
    
    uint8_t* Acquire() {
        std::lock_guard<std::mutex> lock(mutex_);
        if (buffers_.empty()) {
            return new uint8_t[bufferSize_];
        }
        uint8_t* buf = buffers_.front();
        buffers_.pop();

----

## 参考来源
- [深入浅出mediasoup---通信框架](https://blog.csdn.net/zhh157/article/details/140577410)
相关推荐
换个昵称都难1 天前
webrtc 拥塞控制GCC 和PCC
webrtc
Cxiaomu1 天前
React接入WebRTC实时视频实践
react.js·音视频·webrtc
AndyHuang19761 天前
WebRTC 强制 Relay 模式下 TCP 重连失败深度排查与优化实战
webrtc
换个昵称都难1 天前
webrtc pacing 平滑发包模块
webrtc
换个昵称都难1 天前
webrtc 音频混音介绍
音视频·webrtc
换个昵称都难2 天前
webrtc QOS-RemoteBitrateEstimator接收端带宽估计(1)
webrtc
换个昵称都难2 天前
webrtc QOS-RemoteBitrateEstimator接收端带宽估计-四个实例(2)
webrtc
都在酒里2 天前
【极致低延时】香橙派部署 MediaMTX 实现 WebRTC 推流,延时仅 500-800ms,比局域网 ffmpeg 拉流快近 10 倍!(附踩坑全记录)
linux·arm开发·ffmpeg·webrtc·orangepi·嵌入式软件
换个昵称都难2 天前
WebRTC QoS 实战:从原理到弱网优化
开发语言·php·webrtc
小哈机器人2 天前
Phantom Bridge:一个基于WebRTC的ROS2远程可视化与遥操作工具
机器人·webrtc·数据可视化