mediasoup的Transport体系是连接WebRTC客户端与服务器媒体处理核心的桥梁。基于其通信框架,Transport负责管理网络连接、传输协议以及数据流转发。以下是各Transport类型的结构化整理,包含其核心功能、适用场景及关键代码实现。
一、Transport体系架构概览
mediasoup的Transport继承体系采用分层设计,
所有Transport都继承自基类RTC::Transport::Transport,共享以下核心能力:
- 生产者/消费者管理 :维护
Producer和Consumer的映射表 - 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 性能优化建议
- 缓冲区管理:
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)