美文网首页webrtc技术探讨WebRTCWebRTC
webrtc带宽预测---发送端预测

webrtc带宽预测---发送端预测

作者: ai___believe | 来源:发表于2017-05-24 15:51 被阅读383次

    SR RR

    通过RR包,将丢包率信息回传给发送端,根据丢包率做发送端带宽估计。接收RTCP包,以及对应处理流程基本相同,具体流程如下:

    void UdpTransportImpl::IncomingRTCPCallback
    void UdpTransportImpl::IncomingRTCPFunction
    void VideoChannelTransport::IncomingRTCPPacket
    int ViENetworkImpl::ReceivedRTCPPacket
    int32_t ViEChannel::ReceivedRTCPPacket
    int ViEReceiver::ReceivedRTCPPacket
    int ViEReceiver::InsertRTCPPacket
    int32_t ModuleRtpRtcpImpl::IncomingRtcpPacket
    void RTCPReceiver::TriggerCallbacksFromRTCPPacket
    void OnReceivedRtcpReceiverReport
    void BitrateControllerImpl::OnReceivedRtcpReceiverReport
    void SendSideBandwidthEstimation::UpdateReceiverBlock
    void SendSideBandwidthEstimation::UpdateEstimate
    

    bitrate_controller模块接口是bitrate_controller_impl.h文件,通过这个文件就可以建立整个模块。

    int ViEBaseImpl::CreateChannel
    int ViEBaseImpl::CreateChannel
    rtc::scoped_ptr<ChannelGroup> group
    ChannelGroup::ChannelGroup
    BitrateController* BitrateController::CreateBitrateController
    

    其他的对象也都在此BitrateControllerImpl类中,从而将整个模块联系起来。

    有一个线程一直会轮询这个更新带宽评估的函数,因为接收到反馈包之后,会进行评估,这里具体什么用意,后面看。

    int32_t BitrateControllerImpl::Process()
    void SendSideBandwidthEstimation::UpdateEstimate(int64_t now_ms)
    

    设置保留带宽,用于音频

    int Conductor::VideoSetStream
    int ViERTP_RTCPImpl::SetReservedTransmitBitrate
    bool ViEChannelManager::SetReservedTransmitBitrate
    void BitrateControllerImpl::SetReservedBitrate
    

    获取用于编码器的起始码率

    int Conductor::VideoSetSendCodec
    int ViECodecImpl::SetSendCodec
    int32_t ViEEncoder::SetEncoder
    bool BitrateControllerImpl::AvailableBandwidth
    

    根据上一步的起始码率以及设置的起始码率,取较大值设置到SendSideBandwidthEstimation

    int32_t ViEEncoder::SetEncoder
    void BitrateControllerImpl::SetStartBitrate
    void SendSideBandwidthEstimation::SetSendBitrate
    

    设置最小最大码率,这个码率怎么来的,应该是上面设置下来的,后面看。

    int32_t ViEEncoder::SetEncoder
    void BitrateControllerImpl::SetMinMaxBitrate
    void SendSideBandwidthEstimation::SetMinMaxBitrate
    

    设置模式,然后决定是否使用RembSuppressor,这个做什么用,后面看。

    int32_t ViEEncoder::SetEncoder
    void BitrateControllerImpl::SetCodecMode(webrtc::VideoCodecMode mode) 
    void RembSuppressor::SetEnabled(bool enabled)
    

    计算RTT

    照抄下面这篇博客,验证基本正确。

    http://www.cnblogs.com/lingdhox/p/5746210.html

    A 发送 SR 包, 并记录SR包的发送时间. 记为send_time
    B 接收到 A的SR包后, 记录下最后一次接受到SR包的时间. 记为last_recv_time... (B等待发送rtcp包)B 发送 RR包, 计算从[last_recv_time] 到 当前时间的延时. 记录为delay_since_last_SR. 附加到RR包中. A 收到 B的RR包后, 计算RTT

    RTT = send_time - delay_since_last_SR - last_recv_time
    
    A -> 发送SR包.
    ModuleRtpRtcpImpl::Process
    RTCPSender::SendRTCP
    RTCPSender::PrepareRTCP
    RTCPSender::BuildSR
    

    PrepareRTCP 中通过_sending(是否是发送端) 状态判定发送SR或RR. SR包中含有发送时的NTP时间戳. BuildSR中_lastSendReport 记录NTP时间的中间32位. 可以标识SR包, 也就是B回应RR包中report block的LSR字段(last SR timestamp ), 通过LSR可以查找_lastRTCPTime._lastRTCPTime记录RTCP_NUMBER_OF_SR个数的SR发送时间.这两个数组是一一对应的.

    _lastRTCPTime[0] = Clock::NtpToMs(NTPsec, NTPfrac);
    _lastSendReport[0] = (NTPsec << 16) + (NTPfrac >> 16);
    

    最后SendToNetwork.

    B -> 接收到SR包.
    ModuleRtpRtcpImpl::IncomingRtcpPacket
    RTCPReceiver::IncomingRTCPPacket
    RTCPReceiver::HandleSenderReceiverReport
    

    在HandleSenderReceiverReport 中保存 SR包中的NTP时间戳

    _remoteSenderInfo.NTPseconds = rtcpPacket.SR.NTPMostSignificant;
    _remoteSenderInfo.NTPfraction = rtcpPacket.SR.NTPLeastSignificant;
    

    并记录SR包接到时的NTP时间戳

    _clock->CurrentNtp(_lastReceivedSRNTPsecs, _lastReceivedSRNTPfrac);
    
    B -> 发送RR包

    获取回馈状态, 并发送给A

    ModuleRtpRtcpImpl::Process()
    if (rtcp_sender_.TimeToSendRTCPReport()) {
    rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport);
    }
    
    ModuleRtpRtcpImpl::GetFeedbackState()
    ModuleRtpRtcpImpl::LastReceivedNTP
    

    state.last_rr_ntp_secs 和state.last_rr_ntp_frac即为上一次接收到SR包时, 记录的_clock->CurrentNtp(_lastReceivedSRNTPsecs, _lastReceivedSRNTPfrac); 时间戳state.remote_sr 通过_remoteSenderInfo.NTPseconds 和 _remoteSenderInfo.NTPfraction, 取中间32位算出.

    RTCPSender::PrepareReport
    在这里计算延时, 填充到report block中.

    // get our NTP as late as possible to avoid a race
    _clock->CurrentNtp(*ntp_secs, *ntp_frac);
    
    // Delay since last received report
    uint32_t delaySinceLastReceivedSR = 0;
    if ((feedback_state.last_rr_ntp_secs != 0) ||
    (feedback_state.last_rr_ntp_frac != 0)) {
    // get the 16 lowest bits of seconds and the 16 higest bits of fractions
    uint32_t now=*ntp_secs&0x0000FFFF;
    now <<=16;
    now += (*ntp_frac&0xffff0000)>>16;
    
    uint32_t receiveTime = feedback_state.last_rr_ntp_secs&0x0000FFFF;
    receiveTime <<=16;
    receiveTime += (feedback_state.last_rr_ntp_frac&0xffff0000)>>16;
    
    delaySinceLastReceivedSR = now-receiveTime;
    }
    report_block->delaySinceLastSR = delaySinceLastReceivedSR;
    report_block->lastSR = feedback_state.remote_sr;
    

    report_block->delaySinceLastSR 即为 从接到SR包到发送RR包之间的延时.
    report_block->lastSR 即SR包中NTP时间戳的中间32位. (在A端_lastSendReport数组中记录).

    A 收到 B的RR包
    ModuleRtpRtcpImpl::IncomingRtcpPacket
    RTCPReceiver::IncomingRTCPPacket
    RTCPReceiver::HandleSenderReceiverReport
    RTCPReceiver::HandleReportBlock
    

    通过 lastSR 到sender模块中取出SR包的发送时间.

    uint32_t sendTimeMS =
    _rtpRtcp.SendTimeOfSendReport(rtcpPacket.ReportBlockItem.LastSR);
    

    计算RTT .

    uint32_t delaySinceLastSendReport =
    rtcpPacket.ReportBlockItem.DelayLastSR;
    
    // local NTP time when we received this
    uint32_t lastReceivedRRNTPsecs = 0;
    uint32_t lastReceivedRRNTPfrac = 0;
    
    _clock->CurrentNtp(lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);
    
    // time when we received this in MS
    uint32_t receiveTimeMS = Clock::NtpToMs(lastReceivedRRNTPsecs,
    lastReceivedRRNTPfrac);
    
    // Estimate RTT
    uint32_t d = (delaySinceLastSendReport & 0x0000ffff) * 1000;
    d /= 65536;
    d += ((delaySinceLastSendReport & 0xffff0000) >> 16) * 1000;
    
    int32_t RTT = 0;
    
    if (sendTimeMS > 0) {
    RTT = receiveTimeMS - d - sendTimeMS;
    ....
    }
    

    注意:
    delay since last SR (DLSR) 的单位是1/65536秒.
    为什么在获取本地时间不直接获取,而要先得到NTP再转为毫秒,应该是要时间统一都用NTP时间,而不是本地时间。

    NTP相关计算

    通过_clock->CurrentNtp()方法来获得当前时刻的ntp,其中lastReceivedRRNTPsecs 为秒,lastReceivedRRNTPfrac 为小数点后面部分。

      // local NTP time when we received this
      uint32_t lastReceivedRRNTPsecs = 0;
      uint32_t lastReceivedRRNTPfrac = 0;
      _clock->CurrentNtp(lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);
      // time when we received this in MS
    
      void CurrentNtp(uint32_t& seconds, uint32_t& fractions) const override {
        timeval tv = CurrentTimeVal();
        double microseconds_in_seconds;
        Adjust(tv, &seconds, &microseconds_in_seconds);
        fractions = static_cast<uint32_t>(
            microseconds_in_seconds * kMagicNtpFractionalUnit + 0.5);
      }
    

    通过CurrentTimeVal()方法的复杂计算之后,最后得到秒和微妙。

      timeval CurrentTimeVal() const override {
        const uint64_t FILETIME_1970 = 0x019db1ded53e8000;
    
        FILETIME StartTime;
        uint64_t Time;
        struct timeval tv;
    
        // We can't use query performance counter since they can change depending on
        // speed stepping.
        GetTime(&StartTime);
    
        Time = (((uint64_t) StartTime.dwHighDateTime) << 32) +
               (uint64_t) StartTime.dwLowDateTime;
    
        // Convert the hecto-nano second time to tv format.
        Time -= FILETIME_1970;
    
        tv.tv_sec = (uint32_t)(Time / (uint64_t)10000000);
        tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10);
        return tv;
      }
    

    Adjust()对秒和微秒做微调。

      static void Adjust(const timeval& tv, uint32_t* adjusted_s,
                         double* adjusted_us_in_s) {
        *adjusted_s = tv.tv_sec + kNtpJan1970;
        *adjusted_us_in_s = tv.tv_usec / 1e6;
    
        if (*adjusted_us_in_s >= 1) {
          *adjusted_us_in_s -= 1;
          ++*adjusted_s;
        } else if (*adjusted_us_in_s < -1) {
          *adjusted_us_in_s += 1;
          --*adjusted_s;
        }
      }
    };
    

    通过NtpToMs()将NTP时间转为毫秒

      int64_t receiveTimeMS = Clock::NtpToMs(lastReceivedRRNTPsecs,
                                             lastReceivedRRNTPfrac);
    
    int64_t Clock::NtpToMs(uint32_t ntp_secs, uint32_t ntp_frac) {
      const double ntp_frac_ms = static_cast<double>(ntp_frac) / kNtpFracPerMs;
      return 1000 * static_cast<int64_t>(ntp_secs) +
          static_cast<int64_t>(ntp_frac_ms + 0.5);
    }
    

    相关文章

      网友评论

        本文标题:webrtc带宽预测---发送端预测

        本文链接:https://www.haomeiwen.com/subject/zubnxxtx.html