WebRTC RTP RTCP module

Abstract

WebRTC RTP RTCP module

Authors

Walter Fan

Status

WIP

Updated

2024-08-21

Overview

rtp_rtcp 是 libwebrtc 的一个核心模块

constexpr TimeDelta RTCP_SEND_BEFORE_KEY_FRAME = TimeDelta::Millis(100);
constexpr int RTCP_MAX_REPORT_BLOCKS = 31;  // RFC 3550 page 37

RTCP Mode

RtcpMode 有三种:

  • kOff

  • kCompound 复合包

  • kReducedSize 缩小尺寸包

// RTCP mode to use. Compound mode is described by RFC 4585
// and reduced-size RTCP mode is described by RFC 5506.
enum class RtcpMode { kOff, kCompound, kReducedSize };

RTX Mode

enum RtxMode {
kRtxOff = 0x0,
kRtxRetransmitted = 0x1,     // Only send retransmissions over RTX.
kRtxRedundantPayloads = 0x2  // Preventively send redundant payloads
                            // instead of padding.
};

WebRTC 中计算的汇报间隔

默认汇报间隔是 * 视频会话: 1s * 音频会话: 5s

constexpr TimeDelta kDefaultVideoReportInterval = TimeDelta::Seconds(1);
constexpr TimeDelta kDefaultAudioReportInterval = TimeDelta::Seconds(5);

实际上会根据反馈的网络状态来调整发送频率

void RTCPSender::PrepareReport(const FeedbackState& feedback_state) {
    bool generate_report;
    if (IsFlagPresent(kRtcpSr) || IsFlagPresent(kRtcpRr)) {
        // Report type already explicitly set, don't automatically populate.
        generate_report = true;
        RTC_DCHECK(ConsumeFlag(kRtcpReport) == false);
    } else {
        generate_report =
            (ConsumeFlag(kRtcpReport) && method_ == RtcpMode::kReducedSize) ||
            method_ == RtcpMode::kCompound;
        if (generate_report)
        SetFlag(sending_ ? kRtcpSr : kRtcpRr, true);
    }

    if (IsFlagPresent(kRtcpSr) || (IsFlagPresent(kRtcpRr) && !cname_.empty()))
        SetFlag(kRtcpSdes, true);

    if (generate_report) {
        if ((!sending_ && xr_send_receiver_reference_time_enabled_) ||
            !feedback_state.last_xr_rtis.empty() ||
            send_video_bitrate_allocation_) {
            SetFlag(kRtcpAnyExtendedReports, true);
        }

        // generate next time to send an RTCP report
        TimeDelta min_interval = report_interval_;

        if (!audio_ && sending_) {
            // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
            int send_bitrate_kbit = feedback_state.send_bitrate / 1000;
            if (send_bitrate_kbit != 0) {
                min_interval = std::min(TimeDelta::Millis(360000 / send_bitrate_kbit),
                                        report_interval_);
            }
        }

        // The interval between RTCP packets is varied randomly over the
        // range [1/2,3/2] times the calculated interval.
        int min_interval_int = rtc::dchecked_cast<int>(min_interval.ms());
        TimeDelta time_to_next = TimeDelta::Millis(
            random_.Rand(min_interval_int * 1 / 2, min_interval_int * 3 / 2));

        RTC_DCHECK(!time_to_next.IsZero());
        SetNextRtcpSendEvaluationDuration(time_to_next);

        // RtcpSender expected to be used for sending either just sender reports
        // or just receiver reports.
        RTC_DCHECK(!(IsFlagPresent(kRtcpSr) && IsFlagPresent(kRtcpRr)));
    }
}

WebRTC中支持的 RTP 扩展头

// This enum must not have any gaps, i.e., all integers between
// kRtpExtensionNone and kRtpExtensionNumberOfExtensions must be valid enum
// entries.
enum RTPExtensionType : int {
    kRtpExtensionNone,
    kRtpExtensionTransmissionTimeOffset,
    kRtpExtensionAudioLevel,
    kRtpExtensionCsrcAudioLevel,
    kRtpExtensionInbandComfortNoise,
    kRtpExtensionAbsoluteSendTime,
    kRtpExtensionAbsoluteCaptureTime,
    kRtpExtensionVideoRotation,
    kRtpExtensionTransportSequenceNumber,
    kRtpExtensionTransportSequenceNumber02,
    kRtpExtensionPlayoutDelay,
    kRtpExtensionVideoContentType,
    kRtpExtensionVideoLayersAllocation,
    kRtpExtensionVideoTiming,
    kRtpExtensionRtpStreamId,
    kRtpExtensionRepairedRtpStreamId,
    kRtpExtensionMid,
    kRtpExtensionGenericFrameDescriptor00,
    kRtpExtensionGenericFrameDescriptor = kRtpExtensionGenericFrameDescriptor00,
    kRtpExtensionGenericFrameDescriptor02,
    kRtpExtensionColorSpace,
    kRtpExtensionVideoFrameTrackingId,
    kRtpExtensionNumberOfExtensions  // Must be the last entity in the enum.
};

RTP 包中的媒体内容类型

// NOTE! `kNumMediaTypes` must be kept in sync with RtpPacketMediaType!
static constexpr size_t kNumMediaTypes = 5;
enum class RtpPacketMediaType : size_t {
    kAudio,                         // Audio media packets.
    kVideo,                         // Video media packets.
    kRetransmission,                // Retransmisions, sent as response to NACK.
    kForwardErrorCorrection,        // FEC packets.
    kPadding = kNumMediaTypes - 1,  // RTX or plain padding sent to maintain BWE.
    // Again, don't forget to udate `kNumMediaTypes` if you add another value!
};

RTCP 包

RTCP 包类型

enum RTCPPacketType : uint32_t {
    kRtcpReport = 0x0001,
    kRtcpSr = 0x0002,
    kRtcpRr = 0x0004,
    kRtcpSdes = 0x0008,
    kRtcpBye = 0x0010,
    kRtcpPli = 0x0020,
    kRtcpNack = 0x0040,
    kRtcpFir = 0x0080,
    kRtcpTmmbr = 0x0100,
    kRtcpTmmbn = 0x0200,
    kRtcpSrReq = 0x0400,
    kRtcpLossNotification = 0x2000,
    kRtcpRemb = 0x10000,
    kRtcpTransmissionTimeOffset = 0x20000,
    kRtcpXrReceiverReferenceTime = 0x40000,
    kRtcpXrDlrrReportBlock = 0x80000,
    kRtcpTransportFeedback = 0x100000,
    kRtcpXrTargetBitrate = 0x200000
};

SenderReportStats

// Stats for RTCP sender reports (SR) for a specific SSRC.
// Refer to https://tools.ietf.org/html/rfc3550#section-6.4.1.
struct SenderReportStats {
    // Arrival NTP timestamp for the last received RTCP SR.
    NtpTime last_arrival_timestamp;
    // Received (a.k.a., remote) NTP timestamp for the last received RTCP SR.
    NtpTime last_remote_timestamp;
    // Total number of RTP data packets transmitted by the sender since starting
    // transmission up until the time this SR packet was generated. The count
    // should be reset if the sender changes its SSRC identifier.
    uint32_t packets_sent;
    // Total number of payload octets (i.e., not including header or padding)
    // transmitted in RTP data packets by the sender since starting transmission
    // up until the time this SR packet was generated. The count should be reset
    // if the sender changes its SSRC identifier.
    uint64_t bytes_sent;
    // Total number of RTCP SR blocks received.
    // https://www.w3.org/TR/webrtc-stats/#dom-rtcremoteoutboundrtpstreamstats-reportssent.
    uint64_t reports_count;
};

RTCP sender

  • configuration

struct Configuration {
    // TODO(bugs.webrtc.org/11581): Remove this temporary conversion utility
    // once rtc_rtcp_impl.cc/h are gone.
    static Configuration FromRtpRtcpConfiguration(
        const RtpRtcpInterface::Configuration& config);

    // True for a audio version of the RTP/RTCP module object false will create
    // a video version.
    bool audio = false;
    // SSRCs for media and retransmission, respectively.
    // FlexFec SSRC is fetched from `flexfec_sender`.
    uint32_t local_media_ssrc = 0;
    // The clock to use to read time. If nullptr then system clock will be used.
    Clock* clock = nullptr;
    // Transport object that will be called when packets are ready to be sent
    // out on the network.
    Transport* outgoing_transport = nullptr;
    // Estimate RTT as non-sender as described in
    // https://tools.ietf.org/html/rfc3611#section-4.4 and #section-4.5
    bool non_sender_rtt_measurement = false;
    // Optional callback which, if specified, is used by RTCPSender to schedule
    // the next time to evaluate if RTCP should be sent by means of
    // TimeToSendRTCPReport/SendRTCP.
    // The RTCPSender client still needs to call TimeToSendRTCPReport/SendRTCP
    // to actually get RTCP sent.
    //
    // Note: It's recommended to use the callback to ensure program design that
    // doesn't use polling.
    // TODO(bugs.webrtc.org/11581): Make mandatory once downstream consumers
    // have migrated to the callback solution.
    std::function<void(TimeDelta)> schedule_next_rtcp_send_evaluation_function;

    RtcEventLog* event_log = nullptr;
    absl::optional<TimeDelta> rtcp_report_interval;
    ReceiveStatisticsProvider* receive_statistics = nullptr;
    RtcpPacketTypeCounterObserver* rtcp_packet_type_counter_observer = nullptr;
};