[Webrtc] webrtc rtp retransmission of code analysis

pgm unlikely to be used, did not imagine the reliable, retransmission seemingly still using multicast retransmission, packet loss rate of 80% of the network feel nothing improvements, if improved delay estimation is not a small problem.

I heard there rtp nack mechanism, webrtc based rtp achieve a retransmission reliability to a certain extent.

Found under the guidance of the great God of the brightest rfc4585, to see such a passage
RTCP extended feedback messages, there is a nack message

When FMT = 1 and PT = 205, represents that the packet is an NACK packet

Name Value Brief Description
RTPFB 205 Transport layer FB message
PSFB 206 Pyload-specific FB message
0:    unassigned
1:    Generic NACK
2-30: unassigned
31:   reserved for future expansion of the identifier number space

The Generic NACK message is identified by PT=RTPFB and FMT=1.

FCI field data have shown below

PID: indicates Packet ID, for indicating the number of the current receiving end of the lost data packet is the next expected packet reception side received
BLP: indicates bitmask of following lost lost packets, two bytes, 16-bit, indicates Subsequently packet loss case 16 behind the PID.

rtp agreement itself will not help you retransmission. Application should do their own parsing process rtcp

webrtc achieve on a nack

I suddenly think of it, my next entry time had webrtc source, not deleted (possibly too big, too slow there is no delete delete), so he took out and looked at the source code for the realization of this part of the webrtc

This portion of the code amount is not much, easy to understand, is probably the transmitting side receives rtcp rtcp Receiver packet parsing is found NACK, the transmitting side resends rtp tell the receiving side requests retransmission of data packet

bool RTCPReceiver::IncomingPacket(const uint8_t* packet, size_t packet_size) {
  if (packet_size == 0) {
    LOG(LS_WARNING) << "Incoming empty RTCP packet";
    return false;
  }

  PacketInformation packet_information;
  if (!ParseCompoundPacket(packet, packet + packet_size, &packet_information))
    return false;
  TriggerCallbacksFromRTCPPacket(packet_information);
  return true;
}

The code is received rtcp Receiver after the preliminary determination rtcp packets, ParseCompoundPacketfunction rtcp configured to parse the packet, the key information stored in the excised PacketInformationtransfer structural body to the trigger callback TriggerCallbacksFromRTCPPacketfunction for triggering packet received rtcp callback.

The following is ParseCompoundPacketimplemented structure

struct RTCPReceiver::PacketInformation {
  uint32_t packet_type_flags = 0;  // RTCPPacketTypeFlags bit field.

  uint32_t remote_ssrc = 0;
  std::vector<uint16_t> nack_sequence_numbers;
  ReportBlockList report_blocks;
  int64_t rtt_ms = 0;
  uint8_t sli_picture_id = 0;
  uint64_t rpsi_picture_id = 0;
  uint32_t receiver_estimated_max_bitrate_bps = 0;
  std::unique_ptr<rtcp::TransportFeedback> transport_feedback;
};

nack_sequence_numbersNo. receiving end of the packet has been received is not resolved after the parsing process is simple, through the achievement is not launched unpacking described.

void RTCPReceiver::TriggerCallbacksFromRTCPPacket(
    const PacketInformation& packet_information) {
...
  if (!receiver_only_ && (packet_information.packet_type_flags & kRtcpNack)) {
    if (!packet_information.nack_sequence_numbers.empty()) {
      LOG(LS_VERBOSE) << "Incoming NACK length: "
                      << packet_information.nack_sequence_numbers.size();
      _rtpRtcp.OnReceivedNack(packet_information.nack_sequence_numbers);
    }
...
}

TriggerCallbacksFromRTCPPacketFunction is determined according to the parsed information data packet the current packet type is rtcp NACK, triggers callback that will not directly but SENDER rtp rtp-rtcp to this module by the calling module rtp SENDER, and this module is rtp rtcp the central component (and webrtc related to the structure), also played a role in decoupling

This small amount of code called middle

void ModuleRtpRtcpImpl::OnReceivedNack(
    const std::vector<uint16_t>& nack_sequence_numbers) {
  for (uint16_t nack_sequence_number : nack_sequence_numbers) {
    send_loss_stats_.AddLostPacket(nack_sequence_number);
  }
  if (!rtp_sender_.StorePackets() ||
      nack_sequence_numbers.size() == 0) {
    return;
  }
  // Use RTT from RtcpRttStats class if provided.
  int64_t rtt = rtt_ms();
  if (rtt == 0) {
    rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL);
  }
  rtp_sender_.OnReceivedNack(nack_sequence_numbers, rtt);
}

Start doing some recording, record packet loss and rtt is used for flow control, receive nack when the time does not necessarily retransmission, rtt will be used to make a judgment.

The following code is rtp sender for retransmission packets

void RTPSender::OnReceivedNack(
    const std::vector<uint16_t>& nack_sequence_numbers,
    int64_t avg_rtt) {
  TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
               "RTPSender::OnReceivedNACK", "num_seqnum",
               nack_sequence_numbers.size(), "avg_rtt", avg_rtt);
  for (uint16_t seq_no : nack_sequence_numbers) {
    const int32_t bytes_sent = ReSendPacket(seq_no, 5 + avg_rtt);
    if (bytes_sent < 0) {
      // Failed to send one Sequence number. Give up the rest in this nack.
      LOG(LS_WARNING) << "Failed resending RTP packet " << seq_no
                      << ", Discard rest of packets";
      break;
    }
  }
}

TRACE_EVENTGoogle debug mechanism is used, do not ignore it, this function will cycle retransmit lost packets in the queue, but not necessarily sent successfully, the packet buffer is limited, if you want to resend the packet is no longer cache , you can not change it, right?

int32_t RTPSender::ReSendPacket(uint16_t packet_id, int64_t min_resend_time) {
  std::unique_ptr<RtpPacketToSend> packet =
      packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true);
  if (!packet) {
    // Packet not found.
    return 0;
  }

  // Check if we're overusing retransmission bitrate.
  // TODO(sprang): Add histograms for nack success or failure reasons.
  RTC_DCHECK(retransmission_rate_limiter_);
  if (!retransmission_rate_limiter_->TryUseRate(packet->size()))
    return -1;

  if (paced_sender_) {
    // Convert from TickTime to Clock since capture_time_ms is based on
    // TickTime.
    int64_t corrected_capture_tims_ms =
        packet->capture_time_ms() + clock_delta_ms_;
    paced_sender_->InsertPacket(RtpPacketSender::kNormalPriority,
                                packet->Ssrc(), packet->SequenceNumber(),
                                corrected_capture_tims_ms,
                                packet->payload_size(), true);

    return packet->size();
  }
  bool rtx = (RtxStatus() & kRtxRetransmitted) > 0;
  int32_t packet_size = static_cast<int32_t>(packet->size());
  if (!PrepareAndSendPacket(std::move(packet), rtx, true,
                            PacketInfo::kNotAProbe))
    return -1;
  return packet_size;
}
  • Retransmitted data packet will first check the operating history buffer has no data packet, if not, continues the outer loop, the next packet retransmission.
  • If there are bandwidth limitations, you need to look at the current retransmission mechanism given to whether a bandwidth has been used up, ran out to stop the retransmission cycle operation.
  • min_resend_timeTime for detection. If the retransmission number of the same packet is requested before had, in a short time it is no longer retransmitted

Guess you like

Origin www.cnblogs.com/lenomirei/p/11329131.html