1 /*
2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/rtp_rtcp/source/rtp_sender_video.h"
12 
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <limits>
17 #include <memory>
18 #include <utility>
19 #include <vector>
20 
21 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
22 #include "modules/rtp_rtcp/source/byte_io.h"
23 #include "modules/rtp_rtcp/source/rtp_format_video_generic.h"
24 #include "modules/rtp_rtcp/source/rtp_format_vp8.h"
25 #include "modules/rtp_rtcp/source/rtp_format_vp9.h"
26 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
27 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
28 #include "rtc_base/checks.h"
29 #include "rtc_base/logging.h"
30 #include "rtc_base/ptr_util.h"
31 #include "rtc_base/trace_event.h"
32 
33 namespace webrtc {
34 
35 namespace {
36 constexpr size_t kRedForFecHeaderLength = 1;
37 constexpr int64_t kMaxUnretransmittableFrameIntervalMs = 33 * 4;
38 
BuildRedPayload(const RtpPacketToSend & media_packet,RtpPacketToSend * red_packet)39 void BuildRedPayload(const RtpPacketToSend& media_packet,
40                      RtpPacketToSend* red_packet) {
41   uint8_t* red_payload = red_packet->AllocatePayload(
42       kRedForFecHeaderLength + media_packet.payload_size());
43   RTC_DCHECK(red_payload);
44   red_payload[0] = media_packet.PayloadType();
45 
46   auto media_payload = media_packet.payload();
47   memcpy(&red_payload[kRedForFecHeaderLength], media_payload.data(),
48          media_payload.size());
49 }
50 }  // namespace
51 
RTPSenderVideo(Clock * clock,RTPSender * rtp_sender,FlexfecSender * flexfec_sender)52 RTPSenderVideo::RTPSenderVideo(Clock* clock,
53                                RTPSender* rtp_sender,
54                                FlexfecSender* flexfec_sender)
55     : rtp_sender_(rtp_sender),
56       clock_(clock),
57       video_type_(kRtpVideoGeneric),
58       retransmission_settings_(kRetransmitBaseLayer |
59                                kConditionallyRetransmitHigherLayers),
60       last_rotation_(kVideoRotation_0),
61       red_payload_type_(-1),
62       ulpfec_payload_type_(-1),
63       flexfec_sender_(flexfec_sender),
64       delta_fec_params_{0, 1, kFecMaskRandom},
65       key_fec_params_{0, 1, kFecMaskRandom},
66       fec_bitrate_(1000, RateStatistics::kBpsScale),
67       video_bitrate_(1000, RateStatistics::kBpsScale) {}
68 
~RTPSenderVideo()69 RTPSenderVideo::~RTPSenderVideo() {}
70 
SetVideoCodecType(RtpVideoCodecTypes video_type)71 void RTPSenderVideo::SetVideoCodecType(RtpVideoCodecTypes video_type) {
72   video_type_ = video_type;
73 }
74 
VideoCodecType() const75 RtpVideoCodecTypes RTPSenderVideo::VideoCodecType() const {
76   return video_type_;
77 }
78 
79 // Static.
CreateVideoPayload(const char payload_name[RTP_PAYLOAD_NAME_SIZE],int8_t payload_type)80 RtpUtility::Payload* RTPSenderVideo::CreateVideoPayload(
81     const char payload_name[RTP_PAYLOAD_NAME_SIZE],
82     int8_t payload_type) {
83   RtpVideoCodecTypes video_type = kRtpVideoGeneric;
84   if (RtpUtility::StringCompare(payload_name, "VP8", 3)) {
85     video_type = kRtpVideoVp8;
86   } else if (RtpUtility::StringCompare(payload_name, "VP9", 3)) {
87     video_type = kRtpVideoVp9;
88   } else if (RtpUtility::StringCompare(payload_name, "H264", 4)) {
89     video_type = kRtpVideoH264;
90   } else if (RtpUtility::StringCompare(payload_name, "I420", 4)) {
91     video_type = kRtpVideoGeneric;
92   } else {
93     video_type = kRtpVideoGeneric;
94   }
95   VideoPayload vp;
96   vp.videoCodecType = video_type;
97   return new RtpUtility::Payload(payload_name, PayloadUnion(vp));
98 }
99 
SendVideoPacket(std::unique_ptr<RtpPacketToSend> packet,StorageType storage)100 void RTPSenderVideo::SendVideoPacket(std::unique_ptr<RtpPacketToSend> packet,
101                                      StorageType storage) {
102   // Remember some values about the packet before sending it away.
103   size_t packet_size = packet->size();
104   uint16_t seq_num = packet->SequenceNumber();
105   uint32_t rtp_timestamp = packet->Timestamp();
106   if (!rtp_sender_->SendToNetwork(std::move(packet), storage,
107                                   RtpPacketSender::kLowPriority)) {
108     RTC_LOG(LS_WARNING) << "Failed to send video packet " << seq_num;
109     return;
110   }
111   rtc::CritScope cs(&stats_crit_);
112   video_bitrate_.Update(packet_size, clock_->TimeInMilliseconds());
113   TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
114                        "Video::PacketNormal", "timestamp", rtp_timestamp,
115                        "seqnum", seq_num);
116 }
117 
SendVideoPacketAsRedMaybeWithUlpfec(std::unique_ptr<RtpPacketToSend> media_packet,StorageType media_packet_storage,bool protect_media_packet)118 void RTPSenderVideo::SendVideoPacketAsRedMaybeWithUlpfec(
119     std::unique_ptr<RtpPacketToSend> media_packet,
120     StorageType media_packet_storage,
121     bool protect_media_packet) {
122   uint32_t rtp_timestamp = media_packet->Timestamp();
123   uint16_t media_seq_num = media_packet->SequenceNumber();
124 
125   std::unique_ptr<RtpPacketToSend> red_packet(
126       new RtpPacketToSend(*media_packet));
127   BuildRedPayload(*media_packet, red_packet.get());
128 
129   std::vector<std::unique_ptr<RedPacket>> fec_packets;
130   StorageType fec_storage = kDontRetransmit;
131   {
132     // Only protect while creating RED and FEC packets, not when sending.
133     rtc::CritScope cs(&crit_);
134     red_packet->SetPayloadType(red_payload_type_);
135     if (ulpfec_enabled()) {
136       if (protect_media_packet) {
137         ulpfec_generator_.AddRtpPacketAndGenerateFec(
138             media_packet->data(), media_packet->payload_size(),
139             media_packet->headers_size());
140       }
141       uint16_t num_fec_packets = ulpfec_generator_.NumAvailableFecPackets();
142       if (num_fec_packets > 0) {
143         uint16_t first_fec_sequence_number =
144             rtp_sender_->AllocateSequenceNumber(num_fec_packets);
145         fec_packets = ulpfec_generator_.GetUlpfecPacketsAsRed(
146             red_payload_type_, ulpfec_payload_type_, first_fec_sequence_number,
147             media_packet->headers_size());
148         RTC_DCHECK_EQ(num_fec_packets, fec_packets.size());
149         if (retransmission_settings_ & kRetransmitFECPackets)
150           fec_storage = kAllowRetransmission;
151       }
152     }
153   }
154   // Send |red_packet| instead of |packet| for allocated sequence number.
155   size_t red_packet_size = red_packet->size();
156   if (rtp_sender_->SendToNetwork(std::move(red_packet), media_packet_storage,
157                                  RtpPacketSender::kLowPriority)) {
158     rtc::CritScope cs(&stats_crit_);
159     video_bitrate_.Update(red_packet_size, clock_->TimeInMilliseconds());
160     TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
161                          "Video::PacketRed", "timestamp", rtp_timestamp,
162                          "seqnum", media_seq_num);
163   } else {
164     RTC_LOG(LS_WARNING) << "Failed to send RED packet " << media_seq_num;
165   }
166   for (const auto& fec_packet : fec_packets) {
167     // TODO(danilchap): Make ulpfec_generator_ generate RtpPacketToSend to avoid
168     // reparsing them.
169     std::unique_ptr<RtpPacketToSend> rtp_packet(
170         new RtpPacketToSend(*media_packet));
171     RTC_CHECK(rtp_packet->Parse(fec_packet->data(), fec_packet->length()));
172     rtp_packet->set_capture_time_ms(media_packet->capture_time_ms());
173     uint16_t fec_sequence_number = rtp_packet->SequenceNumber();
174     if (rtp_sender_->SendToNetwork(std::move(rtp_packet), fec_storage,
175                                    RtpPacketSender::kLowPriority)) {
176       rtc::CritScope cs(&stats_crit_);
177       fec_bitrate_.Update(fec_packet->length(), clock_->TimeInMilliseconds());
178       TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
179                            "Video::PacketUlpfec", "timestamp", rtp_timestamp,
180                            "seqnum", fec_sequence_number);
181     } else {
182       RTC_LOG(LS_WARNING) << "Failed to send ULPFEC packet "
183                           << fec_sequence_number;
184     }
185   }
186 }
187 
SendVideoPacketWithFlexfec(std::unique_ptr<RtpPacketToSend> media_packet,StorageType media_packet_storage,bool protect_media_packet)188 void RTPSenderVideo::SendVideoPacketWithFlexfec(
189     std::unique_ptr<RtpPacketToSend> media_packet,
190     StorageType media_packet_storage,
191     bool protect_media_packet) {
192   RTC_DCHECK(flexfec_sender_);
193 
194   if (protect_media_packet)
195     flexfec_sender_->AddRtpPacketAndGenerateFec(*media_packet);
196 
197   SendVideoPacket(std::move(media_packet), media_packet_storage);
198 
199   if (flexfec_sender_->FecAvailable()) {
200     std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
201         flexfec_sender_->GetFecPackets();
202     for (auto& fec_packet : fec_packets) {
203       size_t packet_length = fec_packet->size();
204       uint32_t timestamp = fec_packet->Timestamp();
205       uint16_t seq_num = fec_packet->SequenceNumber();
206       if (rtp_sender_->SendToNetwork(std::move(fec_packet), kDontRetransmit,
207                                      RtpPacketSender::kLowPriority)) {
208         rtc::CritScope cs(&stats_crit_);
209         fec_bitrate_.Update(packet_length, clock_->TimeInMilliseconds());
210         TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
211                              "Video::PacketFlexfec", "timestamp", timestamp,
212                              "seqnum", seq_num);
213       } else {
214         RTC_LOG(LS_WARNING) << "Failed to send FlexFEC packet " << seq_num;
215       }
216     }
217   }
218 }
219 
SetUlpfecConfig(int red_payload_type,int ulpfec_payload_type)220 void RTPSenderVideo::SetUlpfecConfig(int red_payload_type,
221                                      int ulpfec_payload_type) {
222   // Sanity check. Per the definition of UlpfecConfig (see config.h),
223   // a payload type of -1 means that the corresponding feature is
224   // turned off.
225   RTC_DCHECK_GE(red_payload_type, -1);
226   RTC_DCHECK_LE(red_payload_type, 127);
227   RTC_DCHECK_GE(ulpfec_payload_type, -1);
228   RTC_DCHECK_LE(ulpfec_payload_type, 127);
229 
230   rtc::CritScope cs(&crit_);
231   red_payload_type_ = red_payload_type;
232   ulpfec_payload_type_ = ulpfec_payload_type;
233 
234   // Must not enable ULPFEC without RED.
235   // TODO(brandtr): We currently support enabling RED without ULPFEC. Change
236   // this when we have removed the RED/RTX send-side workaround, so that we
237   // ensure that RED and ULPFEC are only enabled together.
238   RTC_DCHECK(red_enabled() || !ulpfec_enabled());
239 
240   // Reset FEC parameters.
241   delta_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom};
242   key_fec_params_ = FecProtectionParams{0, 1, kFecMaskRandom};
243 }
244 
GetUlpfecConfig(int * red_payload_type,int * ulpfec_payload_type) const245 void RTPSenderVideo::GetUlpfecConfig(int* red_payload_type,
246                                      int* ulpfec_payload_type) const {
247   rtc::CritScope cs(&crit_);
248   *red_payload_type = red_payload_type_;
249   *ulpfec_payload_type = ulpfec_payload_type_;
250 }
251 
CalculateFecPacketOverhead() const252 size_t RTPSenderVideo::CalculateFecPacketOverhead() const {
253   if (flexfec_enabled())
254     return flexfec_sender_->MaxPacketOverhead();
255 
256   size_t overhead = 0;
257   if (red_enabled()) {
258     // The RED overhead is due to a small header.
259     overhead += kRedForFecHeaderLength;
260   }
261   if (ulpfec_enabled()) {
262     // For ULPFEC, the overhead is the FEC headers plus RED for FEC header
263     // (see above) plus anything in RTP header beyond the 12 bytes base header
264     // (CSRC list, extensions...)
265     // This reason for the header extensions to be included here is that
266     // from an FEC viewpoint, they are part of the payload to be protected.
267     // (The base RTP header is already protected by the FEC header.)
268     overhead += ulpfec_generator_.MaxPacketOverhead() +
269                 (rtp_sender_->RtpHeaderLength() - kRtpHeaderSize);
270   }
271   return overhead;
272 }
273 
SetFecParameters(const FecProtectionParams & delta_params,const FecProtectionParams & key_params)274 void RTPSenderVideo::SetFecParameters(const FecProtectionParams& delta_params,
275                                       const FecProtectionParams& key_params) {
276   rtc::CritScope cs(&crit_);
277   delta_fec_params_ = delta_params;
278   key_fec_params_ = key_params;
279 }
280 
FlexfecSsrc() const281 rtc::Optional<uint32_t> RTPSenderVideo::FlexfecSsrc() const {
282   if (flexfec_sender_) {
283     return flexfec_sender_->ssrc();
284   }
285   return rtc::nullopt;
286 }
287 
SendVideo(RtpVideoCodecTypes video_type,FrameType frame_type,int8_t payload_type,uint32_t rtp_timestamp,int64_t capture_time_ms,const uint8_t * payload_data,size_t payload_size,const RTPFragmentationHeader * fragmentation,const RTPVideoHeader * video_header,int64_t expected_retransmission_time_ms,const StreamId * rtpStreamId,const StreamId * mId)288 bool RTPSenderVideo::SendVideo(RtpVideoCodecTypes video_type,
289                                FrameType frame_type,
290                                int8_t payload_type,
291                                uint32_t rtp_timestamp,
292                                int64_t capture_time_ms,
293                                const uint8_t* payload_data,
294                                size_t payload_size,
295                                const RTPFragmentationHeader* fragmentation,
296                                const RTPVideoHeader* video_header,
297                                int64_t expected_retransmission_time_ms,
298                                const StreamId* rtpStreamId,
299                                const StreamId* mId) {
300   if (payload_size == 0)
301     return false;
302 
303   // Create header that will be reused in all packets.
304   std::unique_ptr<RtpPacketToSend> rtp_header = rtp_sender_->AllocatePacket();
305   rtp_header->SetPayloadType(payload_type);
306   rtp_header->SetTimestamp(rtp_timestamp);
307   rtp_header->set_capture_time_ms(capture_time_ms);
308 
309   if (rtpStreamId && !rtpStreamId->empty()) {
310      rtp_header->SetExtension<RtpStreamId>(*rtpStreamId);
311   }
312   if (mId && !mId->empty()) {
313      rtp_header->SetExtension<RtpMid>(*mId);
314   }
315 
316   auto last_packet = rtc::MakeUnique<RtpPacketToSend>(*rtp_header);
317 
318   size_t fec_packet_overhead;
319   bool red_enabled;
320   int32_t retransmission_settings;
321   {
322     rtc::CritScope cs(&crit_);
323     // According to
324     // http://www.etsi.org/deliver/etsi_ts/126100_126199/126114/12.07.00_60/
325     // ts_126114v120700p.pdf Section 7.4.5:
326     // The MTSI client shall add the payload bytes as defined in this clause
327     // onto the last RTP packet in each group of packets which make up a key
328     // frame (I-frame or IDR frame in H.264 (AVC), or an IRAP picture in H.265
329     // (HEVC)). The MTSI client may also add the payload bytes onto the last RTP
330     // packet in each group of packets which make up another type of frame
331     // (e.g. a P-Frame) only if the current value is different from the previous
332     // value sent.
333     if (video_header) {
334       // Set rotation when key frame or when changed (to follow standard).
335       // Or when different from 0 (to follow current receiver implementation).
336       VideoRotation current_rotation = video_header->rotation;
337       if (frame_type == kVideoFrameKey || current_rotation != last_rotation_ ||
338           current_rotation != kVideoRotation_0)
339         last_packet->SetExtension<VideoOrientation>(current_rotation);
340       last_rotation_ = current_rotation;
341       // Report content type only for key frames.
342       if (frame_type == kVideoFrameKey &&
343           video_header->content_type != VideoContentType::UNSPECIFIED) {
344         last_packet->SetExtension<VideoContentTypeExtension>(
345             video_header->content_type);
346       }
347       if (video_header->video_timing.flags != TimingFrameFlags::kInvalid) {
348         last_packet->SetExtension<VideoTimingExtension>(
349             video_header->video_timing);
350       }
351     }
352 
353     // FEC settings.
354     const FecProtectionParams& fec_params =
355         frame_type == kVideoFrameKey ? key_fec_params_ : delta_fec_params_;
356     if (flexfec_enabled())
357       flexfec_sender_->SetFecParameters(fec_params);
358     if (ulpfec_enabled())
359       ulpfec_generator_.SetFecParameters(fec_params);
360 
361     fec_packet_overhead = CalculateFecPacketOverhead();
362     red_enabled = this->red_enabled();
363     retransmission_settings = retransmission_settings_;
364   }
365 
366   size_t packet_capacity = rtp_sender_->MaxRtpPacketSize() -
367                            fec_packet_overhead -
368                            (rtp_sender_->RtxStatus() ? kRtxHeaderSize : 0);
369   RTC_DCHECK_LE(packet_capacity, rtp_header->capacity());
370   RTC_DCHECK_GT(packet_capacity, rtp_header->headers_size());
371   RTC_DCHECK_GT(packet_capacity, last_packet->headers_size());
372   size_t max_data_payload_length = packet_capacity - rtp_header->headers_size();
373   RTC_DCHECK_GE(last_packet->headers_size(), rtp_header->headers_size());
374   size_t last_packet_reduction_len =
375       last_packet->headers_size() - rtp_header->headers_size();
376 
377   std::unique_ptr<RtpPacketizer> packetizer(RtpPacketizer::Create(
378       video_type, max_data_payload_length, last_packet_reduction_len,
379       video_header ? &(video_header->codecHeader) : nullptr, frame_type));
380 
381   const uint8_t temporal_id =
382       video_header ? GetTemporalId(*video_header) : kNoTemporalIdx;
383   StorageType storage = GetStorageType(temporal_id, retransmission_settings,
384                                        expected_retransmission_time_ms);
385 
386   size_t num_packets =
387       packetizer->SetPayloadData(payload_data, payload_size, fragmentation);
388 
389   if (num_packets == 0)
390     return false;
391 
392   bool first_frame = first_frame_sent_();
393   for (size_t i = 0; i < num_packets; ++i) {
394     bool last = (i + 1) == num_packets;
395     auto packet = last ? std::move(last_packet)
396                        : rtc::MakeUnique<RtpPacketToSend>(*rtp_header);
397     if (!packetizer->NextPacket(packet.get()))
398       return false;
399     RTC_DCHECK_LE(packet->payload_size(),
400                   last ? max_data_payload_length - last_packet_reduction_len
401                        : max_data_payload_length);
402     if (!rtp_sender_->AssignSequenceNumber(packet.get()))
403       return false;
404 
405     // No FEC protection for upper temporal layers, if used.
406     bool protect_packet = temporal_id == 0 || temporal_id == kNoTemporalIdx;
407 
408     // Put packetization finish timestamp into extension.
409     if (packet->HasExtension<VideoTimingExtension>()) {
410       packet->set_packetization_finish_time_ms(clock_->TimeInMilliseconds());
411       // TODO(ilnik): Due to webrtc:7859, packets with timing extensions are not
412       // protected by FEC. It reduces FEC efficiency a bit. When FEC is moved
413       // below the pacer, it can be re-enabled for these packets.
414       // NOTE: Any RTP stream processor in the network, modifying 'network'
415       // timestamps in the timing frames extension have to be an end-point for
416       // FEC, otherwise recovered by FEC packets will be corrupted.
417       protect_packet = false;
418     }
419 
420     if (flexfec_enabled()) {
421       // TODO(brandtr): Remove the FlexFEC code path when FlexfecSender
422       // is wired up to PacedSender instead.
423       SendVideoPacketWithFlexfec(std::move(packet), storage, protect_packet);
424     } else if (red_enabled) {
425       SendVideoPacketAsRedMaybeWithUlpfec(std::move(packet), storage,
426                                           protect_packet);
427     } else {
428       SendVideoPacket(std::move(packet), storage);
429     }
430 
431     if (first_frame) {
432       if (i == 0) {
433         RTC_LOG(LS_INFO)
434             << "Sent first RTP packet of the first video frame (pre-pacer)";
435       }
436       if (last) {
437         RTC_LOG(LS_INFO)
438             << "Sent last RTP packet of the first video frame (pre-pacer)";
439       }
440     }
441   }
442 
443   TRACE_EVENT_ASYNC_END1("webrtc", "Video", capture_time_ms, "timestamp",
444                          rtp_timestamp);
445   return true;
446 }
447 
VideoBitrateSent() const448 uint32_t RTPSenderVideo::VideoBitrateSent() const {
449   rtc::CritScope cs(&stats_crit_);
450   return video_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
451 }
452 
FecOverheadRate() const453 uint32_t RTPSenderVideo::FecOverheadRate() const {
454   rtc::CritScope cs(&stats_crit_);
455   return fec_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
456 }
457 
SelectiveRetransmissions() const458 int RTPSenderVideo::SelectiveRetransmissions() const {
459   rtc::CritScope cs(&crit_);
460   return retransmission_settings_;
461 }
462 
SetSelectiveRetransmissions(uint8_t settings)463 void RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) {
464   rtc::CritScope cs(&crit_);
465   retransmission_settings_ = settings;
466 }
467 
GetStorageType(uint8_t temporal_id,int32_t retransmission_settings,int64_t expected_retransmission_time_ms)468 StorageType RTPSenderVideo::GetStorageType(
469     uint8_t temporal_id,
470     int32_t retransmission_settings,
471     int64_t expected_retransmission_time_ms) {
472   if (retransmission_settings == kRetransmitOff)
473     return StorageType::kDontRetransmit;
474   if (retransmission_settings == kRetransmitAllPackets)
475     return StorageType::kAllowRetransmission;
476 
477   rtc::CritScope cs(&stats_crit_);
478   // Media packet storage.
479   if ((retransmission_settings & kConditionallyRetransmitHigherLayers) &&
480       UpdateConditionalRetransmit(temporal_id,
481                                   expected_retransmission_time_ms)) {
482     retransmission_settings |= kRetransmitHigherLayers;
483   }
484 
485   if (temporal_id == kNoTemporalIdx)
486     return kAllowRetransmission;
487 
488   if ((retransmission_settings & kRetransmitBaseLayer) && temporal_id == 0)
489     return kAllowRetransmission;
490 
491   if ((retransmission_settings & kRetransmitHigherLayers) && temporal_id > 0)
492     return kAllowRetransmission;
493 
494   return kDontRetransmit;
495 }
496 
GetTemporalId(const RTPVideoHeader & header)497 uint8_t RTPSenderVideo::GetTemporalId(const RTPVideoHeader& header) {
498   switch (header.codec) {
499     case kRtpVideoVp8:
500       return header.codecHeader.VP8.temporalIdx;
501     case kRtpVideoVp9:
502       return header.codecHeader.VP9.temporal_idx;
503     default:
504       return kNoTemporalIdx;
505   }
506 }
507 
UpdateConditionalRetransmit(uint8_t temporal_id,int64_t expected_retransmission_time_ms)508 bool RTPSenderVideo::UpdateConditionalRetransmit(
509     uint8_t temporal_id,
510     int64_t expected_retransmission_time_ms) {
511   int64_t now_ms = clock_->TimeInMilliseconds();
512   // Update stats for any temporal layer.
513   TemporalLayerStats* current_layer_stats =
514       &frame_stats_by_temporal_layer_[temporal_id];
515   current_layer_stats->frame_rate_fp1000s.Update(1, now_ms);
516   int64_t tl_frame_interval = now_ms - current_layer_stats->last_frame_time_ms;
517   current_layer_stats->last_frame_time_ms = now_ms;
518 
519   // Conditional retransmit only applies to upper layers.
520   if (temporal_id != kNoTemporalIdx && temporal_id > 0) {
521     if (tl_frame_interval >= kMaxUnretransmittableFrameIntervalMs) {
522       // Too long since a retransmittable frame in this layer, enable NACK
523       // protection.
524       return true;
525     } else {
526       // Estimate when the next frame of any lower layer will be sent.
527       const int64_t kUndefined = std::numeric_limits<int64_t>::max();
528       int64_t expected_next_frame_time = kUndefined;
529       for (int i = temporal_id - 1; i >= 0; --i) {
530         TemporalLayerStats* stats = &frame_stats_by_temporal_layer_[i];
531         rtc::Optional<uint32_t> rate = stats->frame_rate_fp1000s.Rate(now_ms);
532         if (rate) {
533           int64_t tl_next = stats->last_frame_time_ms + 1000000 / *rate;
534           if (tl_next - now_ms > -expected_retransmission_time_ms &&
535               tl_next < expected_next_frame_time) {
536             expected_next_frame_time = tl_next;
537           }
538         }
539       }
540 
541       if (expected_next_frame_time == kUndefined ||
542           expected_next_frame_time - now_ms > expected_retransmission_time_ms) {
543         // The next frame in a lower layer is expected at a later time (or
544         // unable to tell due to lack of data) than a retransmission is
545         // estimated to be able to arrive, so allow this packet to be nacked.
546         return true;
547       }
548     }
549   }
550 
551   return false;
552 }
553 
554 }  // namespace webrtc
555