WebRTC RTX
Table of Contents
在 WebRTC 中常用的 QoS 策略有
- 反馈:例如 PLI , NACK
- 冗余, 例如 FEC, RTX
- 调整:例如码率,分辨率及帧率的调整
- 缓存: 例如 Receive Adaptive Jitter Buffer, Send Buffer
这些措施的采用需要基于拥塞控制(congestion control) 及带宽估计(bandwidth estimation)技术, 不同的网络条件下需要采用不同的措施。
Webrtc 默认是开启 RTX (重传),它一般采用不同的 SSRC 进行传输
RTX 包的 Payload 在 RFC4588 中有详细描述,一般 NACK 和 Bandwidth Probe 也可能走 RTX 通道。
FEC 用作丢包恢复需要占用更多的带宽,即使 5% 的丢包需要几乎一倍的带宽,在带宽有限的情况下可能会使情况更糟。
RTX 不会占用太多的带宽,接收方发送 NACK 指明哪些包丢失了,发送方通过单独的 RTP 流(不同的 SSRC)来重传丢失的包,但是 RTX 至少需要一个 RTT 来修复丢失的包。
音频流对于延迟很敏感,而且占用带宽不多,所以用 FEC 更好。
视频流对于延迟没那么敏感,而且占用带宽很多,所以用 RTX 更好。
RTX packet 的处理
void RtxReceiveStream::SetAssociatedPayloadTypes(
std::map<int, int> associated_payload_types) {
RTC_DCHECK_RUN_ON(&packet_checker_);
associated_payload_types_ = std::move(associated_payload_types);
}
void RtxReceiveStream::OnRtpPacket(const RtpPacketReceived& rtx_packet) {
RTC_DCHECK_RUN_ON(&packet_checker_);
if (rtp_receive_statistics_) {
rtp_receive_statistics_->OnRtpPacket(rtx_packet);
}
rtc::ArrayView<const uint8_t> payload = rtx_packet.payload();
if (payload.size() < kRtxHeaderSize) {
return;
}
auto it = associated_payload_types_.find(rtx_packet.PayloadType());
if (it == associated_payload_types_.end()) {
RTC_DLOG(LS_VERBOSE) << "Unknown payload type "
<< static_cast<int>(rtx_packet.PayloadType())
<< " on rtx ssrc " << rtx_packet.Ssrc();
return;
}
RtpPacketReceived media_packet;
media_packet.CopyHeaderFrom(rtx_packet);
media_packet.SetSsrc(media_ssrc_);
media_packet.SetSequenceNumber((payload[0] << 8) + payload[1]);
media_packet.SetPayloadType(it->second);
media_packet.set_recovered(true);
media_packet.set_arrival_time(rtx_packet.arrival_time());
// Skip the RTX header.
rtc::ArrayView<const uint8_t> rtx_payload = payload.subview(kRtxHeaderSize);
uint8_t* media_payload = media_packet.AllocatePayload(rtx_payload.size());
RTC_DCHECK(media_payload != nullptr);
memcpy(media_payload, rtx_payload.data(), rtx_payload.size());
media_sink_->OnRtpPacket(media_packet);
}
Reference
Comments |0|
Category: Uncategorized