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