| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" | 11 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h" |
| 12 | 12 |
| 13 #include <string.h> | 13 #include <string.h> |
| 14 | 14 |
| 15 #include <algorithm> | 15 #include <algorithm> |
| 16 #include <iterator> | 16 #include <iterator> |
| 17 #include <utility> | 17 #include <utility> |
| 18 | 18 |
| 19 #include "webrtc/base/checks.h" | 19 #include "webrtc/base/checks.h" |
| 20 #include "webrtc/base/logging.h" | 20 #include "webrtc/base/logging.h" |
| 21 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" | 21 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" |
| 22 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 22 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
| 23 #include "webrtc/modules/rtp_rtcp/source/forward_error_correction_internal.h" | 23 #include "webrtc/modules/rtp_rtcp/source/ulpfec_header_reader_writer.h" |
| 24 | 24 |
| 25 namespace webrtc { | 25 namespace webrtc { |
| 26 | 26 |
| 27 // FEC header size in bytes. | 27 namespace { |
| 28 constexpr size_t kFecHeaderSize = 10; | |
| 29 | |
| 30 // ULP header size in bytes (L bit is set). | |
| 31 constexpr size_t kUlpHeaderSizeLBitSet = (2 + kMaskSizeLBitSet); | |
| 32 | |
| 33 // ULP header size in bytes (L bit is cleared). | |
| 34 constexpr size_t kUlpHeaderSizeLBitClear = (2 + kMaskSizeLBitClear); | |
| 35 | |
| 36 // Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum. | 28 // Transport header size in bytes. Assume UDP/IPv4 as a reasonable minimum. |
| 37 constexpr size_t kTransportOverhead = 28; | 29 constexpr size_t kTransportOverhead = 28; |
| 30 } // namespace |
| 38 | 31 |
| 39 // Maximum number of media packets that can be protected. | 32 ForwardErrorCorrection::Packet::Packet() : length(0), data(), ref_count_(0) {} |
| 40 constexpr size_t ForwardErrorCorrection::kMaxMediaPackets; | 33 ForwardErrorCorrection::Packet::~Packet() = default; |
| 41 | |
| 42 // Maximum number of FEC packets stored internally. | |
| 43 constexpr size_t kMaxFecPackets = ForwardErrorCorrection::kMaxMediaPackets; | |
| 44 | 34 |
| 45 int32_t ForwardErrorCorrection::Packet::AddRef() { | 35 int32_t ForwardErrorCorrection::Packet::AddRef() { |
| 46 return ++ref_count_; | 36 return ++ref_count_; |
| 47 } | 37 } |
| 48 | 38 |
| 49 int32_t ForwardErrorCorrection::Packet::Release() { | 39 int32_t ForwardErrorCorrection::Packet::Release() { |
| 50 int32_t ref_count; | 40 int32_t ref_count; |
| 51 ref_count = --ref_count_; | 41 ref_count = --ref_count_; |
| 52 if (ref_count == 0) | 42 if (ref_count == 0) |
| 53 delete this; | 43 delete this; |
| 54 return ref_count; | 44 return ref_count; |
| 55 } | 45 } |
| 56 | 46 |
| 57 // This comparator is used to compare std::unique_ptr's pointing to | 47 // This comparator is used to compare std::unique_ptr's pointing to |
| 58 // subclasses of SortablePackets. It needs to be parametric since | 48 // subclasses of SortablePackets. It needs to be parametric since |
| 59 // the std::unique_ptr's are not covariant w.r.t. the types that | 49 // the std::unique_ptr's are not covariant w.r.t. the types that |
| 60 // they are pointing to. | 50 // they are pointing to. |
| 61 template <typename S, typename T> | 51 template <typename S, typename T> |
| 62 bool ForwardErrorCorrection::SortablePacket::LessThan::operator() ( | 52 bool ForwardErrorCorrection::SortablePacket::LessThan::operator() ( |
| 63 const S& first, | 53 const S& first, |
| 64 const T& second) { | 54 const T& second) { |
| 65 return IsNewerSequenceNumber(second->seq_num, first->seq_num); | 55 return IsNewerSequenceNumber(second->seq_num, first->seq_num); |
| 66 } | 56 } |
| 67 | 57 |
| 68 ForwardErrorCorrection::ReceivedPacket::ReceivedPacket() {} | 58 ForwardErrorCorrection::ReceivedPacket::ReceivedPacket() = default; |
| 69 ForwardErrorCorrection::ReceivedPacket::~ReceivedPacket() {} | 59 ForwardErrorCorrection::ReceivedPacket::~ReceivedPacket() = default; |
| 70 | 60 |
| 71 ForwardErrorCorrection::RecoveredPacket::RecoveredPacket() {} | 61 ForwardErrorCorrection::RecoveredPacket::RecoveredPacket() = default; |
| 72 ForwardErrorCorrection::RecoveredPacket::~RecoveredPacket() {} | 62 ForwardErrorCorrection::RecoveredPacket::~RecoveredPacket() = default; |
| 73 | 63 |
| 74 ForwardErrorCorrection::ForwardErrorCorrection() | 64 ForwardErrorCorrection::ProtectedPacket::ProtectedPacket() = default; |
| 75 : generated_fec_packets_(kMaxMediaPackets), received_fec_packets_(), | 65 ForwardErrorCorrection::ProtectedPacket::~ProtectedPacket() = default; |
| 76 packet_mask_(), tmp_packet_mask_() {} | |
| 77 ForwardErrorCorrection::~ForwardErrorCorrection() {} | |
| 78 | 66 |
| 79 // Input packet | 67 ForwardErrorCorrection::ReceivedFecPacket::ReceivedFecPacket() = default; |
| 80 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 68 ForwardErrorCorrection::ReceivedFecPacket::~ReceivedFecPacket() = default; |
| 81 // | RTP Header (12 octets) | | |
| 82 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 83 // | RTP Payload | | |
| 84 // | | | |
| 85 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 86 | 69 |
| 87 // Output packet | 70 ForwardErrorCorrection::ForwardErrorCorrection( |
| 88 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 71 std::unique_ptr<FecHeaderReader> fec_header_reader, |
| 89 // | FEC Header (10 octets) | | 72 std::unique_ptr<FecHeaderWriter> fec_header_writer) |
| 90 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 73 : fec_header_reader_(std::move(fec_header_reader)), |
| 91 // | FEC Level 0 Header | | 74 fec_header_writer_(std::move(fec_header_writer)), |
| 92 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 75 generated_fec_packets_(fec_header_writer_->MaxFecPackets()), |
| 93 // | FEC Level 0 Payload | | 76 packet_mask_size_(0) {} |
| 94 // | | | 77 |
| 95 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 78 ForwardErrorCorrection::~ForwardErrorCorrection() = default; |
| 96 // | 79 |
| 80 std::unique_ptr<ForwardErrorCorrection> ForwardErrorCorrection::CreateUlpfec() { |
| 81 std::unique_ptr<FecHeaderReader> fec_header_reader(new UlpfecHeaderReader()); |
| 82 std::unique_ptr<FecHeaderWriter> fec_header_writer(new UlpfecHeaderWriter()); |
| 83 return std::unique_ptr<ForwardErrorCorrection>(new ForwardErrorCorrection( |
| 84 std::move(fec_header_reader), std::move(fec_header_writer))); |
| 85 } |
| 86 |
| 97 int ForwardErrorCorrection::EncodeFec(const PacketList& media_packets, | 87 int ForwardErrorCorrection::EncodeFec(const PacketList& media_packets, |
| 98 uint8_t protection_factor, | 88 uint8_t protection_factor, |
| 99 int num_important_packets, | 89 int num_important_packets, |
| 100 bool use_unequal_protection, | 90 bool use_unequal_protection, |
| 101 FecMaskType fec_mask_type, | 91 FecMaskType fec_mask_type, |
| 102 std::list<Packet*>* fec_packets) { | 92 std::list<Packet*>* fec_packets) { |
| 103 const size_t num_media_packets = media_packets.size(); | 93 const size_t num_media_packets = media_packets.size(); |
| 104 | 94 |
| 105 // Sanity check arguments. | 95 // Sanity check arguments. |
| 106 RTC_DCHECK_GT(num_media_packets, 0u); | 96 RTC_DCHECK_GT(num_media_packets, 0u); |
| 107 RTC_DCHECK_GE(num_important_packets, 0); | 97 RTC_DCHECK_GE(num_important_packets, 0); |
| 108 RTC_DCHECK_LE(static_cast<size_t>(num_important_packets), num_media_packets); | 98 RTC_DCHECK_LE(static_cast<size_t>(num_important_packets), num_media_packets); |
| 109 RTC_DCHECK(fec_packets->empty()); | 99 RTC_DCHECK(fec_packets->empty()); |
| 110 | 100 const size_t max_media_packets = fec_header_writer_->MaxMediaPackets(); |
| 111 if (num_media_packets > kMaxMediaPackets) { | 101 if (num_media_packets > max_media_packets) { |
| 112 LOG(LS_WARNING) << "Can't protect " << num_media_packets | 102 LOG(LS_WARNING) << "Can't protect " << num_media_packets |
| 113 << " media packets per frame. Max is " << kMaxMediaPackets | 103 << " media packets per frame. Max is " << max_media_packets |
| 114 << "."; | 104 << "."; |
| 115 return -1; | 105 return -1; |
| 116 } | 106 } |
| 117 | 107 |
| 118 bool l_bit = (num_media_packets > 8 * kMaskSizeLBitClear); | |
| 119 int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; | |
| 120 | |
| 121 // Error check the media packets. | 108 // Error check the media packets. |
| 122 for (const auto& media_packet : media_packets) { | 109 for (const auto& media_packet : media_packets) { |
| 123 RTC_DCHECK(media_packet); | 110 RTC_DCHECK(media_packet); |
| 124 if (media_packet->length < kRtpHeaderSize) { | 111 if (media_packet->length < kRtpHeaderSize) { |
| 125 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " | 112 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " |
| 126 << "is smaller than RTP header."; | 113 << "is smaller than RTP header."; |
| 127 return -1; | 114 return -1; |
| 128 } | 115 } |
| 129 // Ensure the FEC packets will fit in a typical MTU. | 116 // Ensure the FEC packets will fit in a typical MTU. |
| 130 if (media_packet->length + MaxPacketOverhead() + kTransportOverhead > | 117 if (media_packet->length + MaxPacketOverhead() + kTransportOverhead > |
| 131 IP_PACKET_SIZE) { | 118 IP_PACKET_SIZE) { |
| 132 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " | 119 LOG(LS_WARNING) << "Media packet " << media_packet->length << " bytes " |
| 133 << "with overhead is larger than " << IP_PACKET_SIZE | 120 << "with overhead is larger than " << IP_PACKET_SIZE |
| 134 << " bytes."; | 121 << " bytes."; |
| 135 } | 122 } |
| 136 } | 123 } |
| 137 | 124 |
| 125 // Prepare generated FEC packets. |
| 138 int num_fec_packets = NumFecPackets(num_media_packets, protection_factor); | 126 int num_fec_packets = NumFecPackets(num_media_packets, protection_factor); |
| 139 if (num_fec_packets == 0) { | 127 if (num_fec_packets == 0) { |
| 140 return 0; | 128 return 0; |
| 141 } | 129 } |
| 142 | |
| 143 // Prepare generated FEC packets by setting them to 0. | |
| 144 for (int i = 0; i < num_fec_packets; ++i) { | 130 for (int i = 0; i < num_fec_packets; ++i) { |
| 145 memset(generated_fec_packets_[i].data, 0, IP_PACKET_SIZE); | 131 memset(generated_fec_packets_[i].data, 0, IP_PACKET_SIZE); |
| 146 // Use this as a marker for untouched packets. | 132 // Use this as a marker for untouched packets. |
| 147 generated_fec_packets_[i].length = 0; | 133 generated_fec_packets_[i].length = 0; |
| 148 fec_packets->push_back(&generated_fec_packets_[i]); | 134 fec_packets->push_back(&generated_fec_packets_[i]); |
| 149 } | 135 } |
| 150 | 136 |
| 151 const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); | 137 const internal::PacketMaskTable mask_table(fec_mask_type, num_media_packets); |
| 152 | 138 packet_mask_size_ = internal::PacketMaskSize(num_media_packets); |
| 153 // -- Generate packet masks -- | 139 memset(packet_masks_, 0, num_fec_packets * packet_mask_size_); |
| 154 memset(packet_mask_, 0, num_fec_packets * num_mask_bytes); | |
| 155 internal::GeneratePacketMasks(num_media_packets, num_fec_packets, | 140 internal::GeneratePacketMasks(num_media_packets, num_fec_packets, |
| 156 num_important_packets, use_unequal_protection, | 141 num_important_packets, use_unequal_protection, |
| 157 mask_table, packet_mask_); | 142 mask_table, packet_masks_); |
| 158 | 143 |
| 159 int num_mask_bits = InsertZerosInBitMasks( | 144 // Adapt packet masks to missing media packets. |
| 160 media_packets, packet_mask_, num_mask_bytes, num_fec_packets); | 145 int num_mask_bits = InsertZerosInPacketMasks(media_packets, num_fec_packets); |
| 161 | |
| 162 if (num_mask_bits < 0) { | 146 if (num_mask_bits < 0) { |
| 163 return -1; | 147 return -1; |
| 164 } | 148 } |
| 165 l_bit = (static_cast<size_t>(num_mask_bits) > 8 * kMaskSizeLBitClear); | 149 packet_mask_size_ = internal::PacketMaskSize(num_mask_bits); |
| 166 if (l_bit) { | |
| 167 num_mask_bytes = kMaskSizeLBitSet; | |
| 168 } | |
| 169 | 150 |
| 170 GenerateFecBitStrings(media_packets, packet_mask_, num_fec_packets, l_bit); | 151 // Write FEC packets to |generated_fec_packets_|. |
| 171 GenerateFecUlpHeaders(media_packets, packet_mask_, num_fec_packets, l_bit); | 152 GenerateFecPayloads(media_packets, num_fec_packets); |
| 153 // TODO(brandtr): Generalize this when multistream protection support is |
| 154 // added. |
| 155 const uint16_t seq_num_base = |
| 156 ParseSequenceNumber(media_packets.front().get()->data); |
| 157 FinalizeFecHeaders(num_fec_packets, seq_num_base); |
| 172 | 158 |
| 173 return 0; | 159 return 0; |
| 174 } | 160 } |
| 175 | 161 |
| 176 int ForwardErrorCorrection::NumFecPackets(int num_media_packets, | 162 int ForwardErrorCorrection::NumFecPackets(int num_media_packets, |
| 177 int protection_factor) { | 163 int protection_factor) { |
| 178 // Result in Q0 with an unsigned round. | 164 // Result in Q0 with an unsigned round. |
| 179 int num_fec_packets = (num_media_packets * protection_factor + (1 << 7)) >> 8; | 165 int num_fec_packets = (num_media_packets * protection_factor + (1 << 7)) >> 8; |
| 180 // Generate at least one FEC packet if we need protection. | 166 // Generate at least one FEC packet if we need protection. |
| 181 if (protection_factor > 0 && num_fec_packets == 0) { | 167 if (protection_factor > 0 && num_fec_packets == 0) { |
| 182 num_fec_packets = 1; | 168 num_fec_packets = 1; |
| 183 } | 169 } |
| 184 RTC_DCHECK_LE(num_fec_packets, num_media_packets); | 170 RTC_DCHECK_LE(num_fec_packets, num_media_packets); |
| 185 return num_fec_packets; | 171 return num_fec_packets; |
| 186 } | 172 } |
| 187 | 173 |
| 188 void ForwardErrorCorrection::GenerateFecBitStrings( | 174 void ForwardErrorCorrection::GenerateFecPayloads( |
| 189 const PacketList& media_packets, | 175 const PacketList& media_packets, |
| 190 uint8_t* packet_mask, | 176 size_t num_fec_packets) { |
| 191 int num_fec_packets, | |
| 192 bool l_bit) { | |
| 193 RTC_DCHECK(!media_packets.empty()); | 177 RTC_DCHECK(!media_packets.empty()); |
| 194 uint8_t media_payload_length[2]; | 178 for (size_t i = 0; i < num_fec_packets; ++i) { |
| 195 const int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; | 179 Packet* const fec_packet = &generated_fec_packets_[i]; |
| 196 const uint16_t ulp_header_size = | 180 size_t pkt_mask_idx = i * packet_mask_size_; |
| 197 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; | 181 const size_t min_packet_mask_size = fec_header_writer_->MinPacketMaskSize( |
| 198 const uint16_t fec_rtp_offset = | 182 &packet_masks_[pkt_mask_idx], packet_mask_size_); |
| 199 kFecHeaderSize + ulp_header_size - kRtpHeaderSize; | 183 const size_t fec_header_size = |
| 184 fec_header_writer_->FecHeaderSize(min_packet_mask_size); |
| 200 | 185 |
| 201 for (int i = 0; i < num_fec_packets; ++i) { | 186 size_t media_pkt_idx = 0; |
| 202 Packet* const fec_packet = &generated_fec_packets_[i]; | |
| 203 auto media_packets_it = media_packets.cbegin(); | 187 auto media_packets_it = media_packets.cbegin(); |
| 204 uint32_t pkt_mask_idx = i * num_mask_bytes; | |
| 205 uint32_t media_pkt_idx = 0; | |
| 206 uint16_t fec_packet_length = 0; | |
| 207 uint16_t prev_seq_num = ParseSequenceNumber((*media_packets_it)->data); | 188 uint16_t prev_seq_num = ParseSequenceNumber((*media_packets_it)->data); |
| 208 while (media_packets_it != media_packets.end()) { | 189 while (media_packets_it != media_packets.end()) { |
| 209 // Each FEC packet has a multiple byte mask. Determine if this media | 190 Packet* const media_packet = media_packets_it->get(); |
| 210 // packet should be included in FEC packet i. | 191 // Should |media_packet| be protected by |fec_packet|? |
| 211 if (packet_mask[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) { | 192 if (packet_masks_[pkt_mask_idx] & (1 << (7 - media_pkt_idx))) { |
| 212 Packet* media_packet = media_packets_it->get(); | 193 size_t media_payload_length = media_packet->length - kRtpHeaderSize; |
| 213 | 194 |
| 214 // Assign network-ordered media payload length. | 195 bool first_protected_packet = (fec_packet->length == 0); |
| 215 ByteWriter<uint16_t>::WriteBigEndian( | 196 size_t fec_packet_length = fec_header_size + media_payload_length; |
| 216 media_payload_length, media_packet->length - kRtpHeaderSize); | 197 if (fec_packet_length > fec_packet->length) { |
| 217 | 198 // Recall that XORing with zero (which the FEC packets are prefilled |
| 218 fec_packet_length = media_packet->length + fec_rtp_offset; | 199 // with) is the identity operator, thus all prior XORs are |
| 219 // On the first protected packet, we don't need to XOR. | 200 // still correct even though we expand the packet length here. |
| 220 if (fec_packet->length == 0) { | 201 fec_packet->length = fec_packet_length; |
| 221 // Copy the first 2 bytes of the RTP header. Note that the E and L | 202 } |
| 222 // bits are overwritten in GenerateFecUlpHeaders. | 203 if (first_protected_packet) { |
| 204 // Write P, X, CC, M, and PT recovery fields. |
| 205 // Note that bits 0, 1, and 16 are overwritten in FinalizeFecHeaders. |
| 223 memcpy(&fec_packet->data[0], &media_packet->data[0], 2); | 206 memcpy(&fec_packet->data[0], &media_packet->data[0], 2); |
| 224 // Copy the 5th to 8th bytes of the RTP header (timestamp). | 207 // Write length recovery field. (This is a temporary location for |
| 208 // ULPFEC.) |
| 209 ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[2], |
| 210 media_payload_length); |
| 211 // Write timestamp recovery field. |
| 225 memcpy(&fec_packet->data[4], &media_packet->data[4], 4); | 212 memcpy(&fec_packet->data[4], &media_packet->data[4], 4); |
| 226 // Copy network-ordered payload size. | 213 // Write payload. |
| 227 memcpy(&fec_packet->data[8], media_payload_length, 2); | 214 memcpy(&fec_packet->data[fec_header_size], |
| 228 | 215 &media_packet->data[kRtpHeaderSize], media_payload_length); |
| 229 // Copy RTP payload, leaving room for the ULP header. | |
| 230 memcpy(&fec_packet->data[kFecHeaderSize + ulp_header_size], | |
| 231 &media_packet->data[kRtpHeaderSize], | |
| 232 media_packet->length - kRtpHeaderSize); | |
| 233 } else { | 216 } else { |
| 234 // XOR with the first 2 bytes of the RTP header. | 217 XorHeaders(*media_packet, fec_packet); |
| 235 fec_packet->data[0] ^= media_packet->data[0]; | 218 XorPayloads(*media_packet, media_payload_length, fec_header_size, |
| 236 fec_packet->data[1] ^= media_packet->data[1]; | 219 fec_packet); |
| 237 | |
| 238 // XOR with the 5th to 8th bytes of the RTP header. | |
| 239 for (uint32_t j = 4; j < 8; ++j) { | |
| 240 fec_packet->data[j] ^= media_packet->data[j]; | |
| 241 } | |
| 242 | |
| 243 // XOR with the network-ordered payload size. | |
| 244 fec_packet->data[8] ^= media_payload_length[0]; | |
| 245 fec_packet->data[9] ^= media_payload_length[1]; | |
| 246 | |
| 247 // XOR with RTP payload, leaving room for the ULP header. | |
| 248 for (int32_t j = kFecHeaderSize + ulp_header_size; | |
| 249 j < fec_packet_length; j++) { | |
| 250 fec_packet->data[j] ^= media_packet->data[j - fec_rtp_offset]; | |
| 251 } | |
| 252 } | |
| 253 if (fec_packet_length > fec_packet->length) { | |
| 254 fec_packet->length = fec_packet_length; | |
| 255 } | 220 } |
| 256 } | 221 } |
| 257 media_packets_it++; | 222 media_packets_it++; |
| 258 if (media_packets_it != media_packets.end()) { | 223 if (media_packets_it != media_packets.end()) { |
| 259 uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data); | 224 uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data); |
| 260 media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num); | 225 media_pkt_idx += static_cast<uint16_t>(seq_num - prev_seq_num); |
| 261 prev_seq_num = seq_num; | 226 prev_seq_num = seq_num; |
| 262 } | 227 } |
| 263 pkt_mask_idx += media_pkt_idx / 8; | 228 pkt_mask_idx += media_pkt_idx / 8; |
| 264 media_pkt_idx %= 8; | 229 media_pkt_idx %= 8; |
| 265 } | 230 } |
| 266 RTC_DCHECK_GT(fec_packet->length, 0u) | 231 RTC_DCHECK_GT(fec_packet->length, 0u) |
| 267 << "Packet mask is wrong or poorly designed."; | 232 << "Packet mask is wrong or poorly designed."; |
| 268 } | 233 } |
| 269 } | 234 } |
| 270 | 235 |
| 271 int ForwardErrorCorrection::InsertZerosInBitMasks( | 236 int ForwardErrorCorrection::InsertZerosInPacketMasks( |
| 272 const PacketList& media_packets, | 237 const PacketList& media_packets, |
| 273 uint8_t* packet_mask, | 238 size_t num_fec_packets) { |
| 274 int num_mask_bytes, | 239 size_t num_media_packets = media_packets.size(); |
| 275 int num_fec_packets) { | 240 if (num_media_packets <= 1) { |
| 276 if (media_packets.size() <= 1) { | 241 return num_media_packets; |
| 277 return media_packets.size(); | |
| 278 } | 242 } |
| 279 int last_seq_num = ParseSequenceNumber(media_packets.back()->data); | 243 uint16_t last_seq_num = ParseSequenceNumber(media_packets.back()->data); |
| 280 int first_seq_num = ParseSequenceNumber(media_packets.front()->data); | 244 uint16_t first_seq_num = ParseSequenceNumber(media_packets.front()->data); |
| 281 int total_missing_seq_nums = | 245 size_t total_missing_seq_nums = |
| 282 static_cast<uint16_t>(last_seq_num - first_seq_num) - | 246 static_cast<uint16_t>(last_seq_num - first_seq_num) - num_media_packets + |
| 283 media_packets.size() + 1; | 247 1; |
| 284 if (total_missing_seq_nums == 0) { | 248 if (total_missing_seq_nums == 0) { |
| 285 // All sequence numbers are covered by the packet mask. No zero insertion | 249 // All sequence numbers are covered by the packet mask. |
| 286 // required. | 250 // No zero insertion required. |
| 287 return media_packets.size(); | 251 return num_media_packets; |
| 288 } | 252 } |
| 289 // We can only protect 8 * kMaskSizeLBitSet packets. | 253 const size_t max_media_packets = fec_header_writer_->MaxMediaPackets(); |
| 290 if (total_missing_seq_nums + media_packets.size() > 8 * kMaskSizeLBitSet) | 254 if (total_missing_seq_nums + num_media_packets > max_media_packets) { |
| 291 return -1; | 255 return -1; |
| 256 } |
| 292 // Allocate the new mask. | 257 // Allocate the new mask. |
| 293 int new_mask_bytes = kMaskSizeLBitClear; | 258 size_t tmp_packet_mask_size = |
| 294 if (media_packets.size() + | 259 internal::PacketMaskSize(total_missing_seq_nums + num_media_packets); |
| 295 total_missing_seq_nums > 8 * kMaskSizeLBitClear) { | 260 memset(tmp_packet_masks_, 0, num_fec_packets * tmp_packet_mask_size); |
| 296 new_mask_bytes = kMaskSizeLBitSet; | |
| 297 } | |
| 298 memset(tmp_packet_mask_, 0, num_fec_packets * kMaskSizeLBitSet); | |
| 299 | 261 |
| 300 auto media_packets_it = media_packets.cbegin(); | 262 auto media_packets_it = media_packets.cbegin(); |
| 301 uint16_t prev_seq_num = first_seq_num; | 263 uint16_t prev_seq_num = first_seq_num; |
| 302 ++media_packets_it; | 264 ++media_packets_it; |
| 303 | 265 |
| 304 // Insert the first column. | 266 // Insert the first column. |
| 305 internal::CopyColumn(tmp_packet_mask_, new_mask_bytes, packet_mask_, | 267 internal::CopyColumn(tmp_packet_masks_, tmp_packet_mask_size, packet_masks_, |
| 306 num_mask_bytes, num_fec_packets, 0, 0); | 268 packet_mask_size_, num_fec_packets, 0, 0); |
| 307 size_t new_bit_index = 1; | 269 size_t new_bit_index = 1; |
| 308 size_t old_bit_index = 1; | 270 size_t old_bit_index = 1; |
| 309 // Insert zeros in the bit mask for every hole in the sequence. | 271 // Insert zeros in the bit mask for every hole in the sequence. |
| 310 while (media_packets_it != media_packets.end()) { | 272 while (media_packets_it != media_packets.end()) { |
| 311 if (new_bit_index == 8 * kMaskSizeLBitSet) { | 273 if (new_bit_index == max_media_packets) { |
| 312 // We can only cover up to 48 packets. | 274 // We can only cover up to 48 packets. |
| 313 break; | 275 break; |
| 314 } | 276 } |
| 315 uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data); | 277 uint16_t seq_num = ParseSequenceNumber((*media_packets_it)->data); |
| 316 const int num_zeros_to_insert = | 278 const int num_zeros_to_insert = |
| 317 static_cast<uint16_t>(seq_num - prev_seq_num - 1); | 279 static_cast<uint16_t>(seq_num - prev_seq_num - 1); |
| 318 if (num_zeros_to_insert > 0) { | 280 if (num_zeros_to_insert > 0) { |
| 319 internal::InsertZeroColumns(num_zeros_to_insert, tmp_packet_mask_, | 281 internal::InsertZeroColumns(num_zeros_to_insert, tmp_packet_masks_, |
| 320 new_mask_bytes, num_fec_packets, | 282 tmp_packet_mask_size, num_fec_packets, |
| 321 new_bit_index); | 283 new_bit_index); |
| 322 } | 284 } |
| 323 new_bit_index += num_zeros_to_insert; | 285 new_bit_index += num_zeros_to_insert; |
| 324 internal::CopyColumn(tmp_packet_mask_, new_mask_bytes, packet_mask_, | 286 internal::CopyColumn(tmp_packet_masks_, tmp_packet_mask_size, packet_masks_, |
| 325 num_mask_bytes, num_fec_packets, new_bit_index, | 287 packet_mask_size_, num_fec_packets, new_bit_index, |
| 326 old_bit_index); | 288 old_bit_index); |
| 327 ++new_bit_index; | 289 ++new_bit_index; |
| 328 ++old_bit_index; | 290 ++old_bit_index; |
| 329 prev_seq_num = seq_num; | 291 prev_seq_num = seq_num; |
| 330 ++media_packets_it; | 292 ++media_packets_it; |
| 331 } | 293 } |
| 332 if (new_bit_index % 8 != 0) { | 294 if (new_bit_index % 8 != 0) { |
| 333 // We didn't fill the last byte. Shift bits to correct position. | 295 // We didn't fill the last byte. Shift bits to correct position. |
| 334 for (uint16_t row = 0; row < num_fec_packets; ++row) { | 296 for (uint16_t row = 0; row < num_fec_packets; ++row) { |
| 335 int new_byte_index = row * new_mask_bytes + new_bit_index / 8; | 297 int new_byte_index = row * tmp_packet_mask_size + new_bit_index / 8; |
| 336 tmp_packet_mask_[new_byte_index] <<= (7 - (new_bit_index % 8)); | 298 tmp_packet_masks_[new_byte_index] <<= (7 - (new_bit_index % 8)); |
| 337 } | 299 } |
| 338 } | 300 } |
| 339 // Replace the old mask with the new. | 301 // Replace the old mask with the new. |
| 340 memcpy(packet_mask, tmp_packet_mask_, kMaskSizeLBitSet * num_fec_packets); | 302 memcpy(packet_masks_, tmp_packet_masks_, |
| 303 num_fec_packets * tmp_packet_mask_size); |
| 341 return new_bit_index; | 304 return new_bit_index; |
| 342 } | 305 } |
| 343 | 306 |
| 344 void ForwardErrorCorrection::GenerateFecUlpHeaders( | 307 void ForwardErrorCorrection::FinalizeFecHeaders(size_t num_fec_packets, |
| 345 const PacketList& media_packets, | 308 uint16_t seq_num_base) { |
| 346 uint8_t* packet_mask, | 309 for (size_t i = 0; i < num_fec_packets; ++i) { |
| 347 int num_fec_packets, | 310 fec_header_writer_->FinalizeFecHeader( |
| 348 bool l_bit) { | 311 seq_num_base, &packet_masks_[i * packet_mask_size_], packet_mask_size_, |
| 349 // -- Generate FEC and ULP headers -- | 312 &generated_fec_packets_[i]); |
| 350 // | |
| 351 // FEC Header, 10 bytes | |
| 352 // 0 1 2 3 | |
| 353 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
| 354 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 355 // |E|L|P|X| CC |M| PT recovery | SN base | | |
| 356 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 357 // | TS recovery | | |
| 358 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 359 // | length recovery | | |
| 360 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 361 // | |
| 362 // ULP Header, 4 bytes (for L = 0) | |
| 363 // 0 1 2 3 | |
| 364 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
| 365 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 366 // | Protection Length | mask | | |
| 367 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 368 // | mask cont. (present only when L = 1) | | |
| 369 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 370 int num_mask_bytes = l_bit ? kMaskSizeLBitSet : kMaskSizeLBitClear; | |
| 371 const uint16_t ulp_header_size = | |
| 372 l_bit ? kUlpHeaderSizeLBitSet : kUlpHeaderSizeLBitClear; | |
| 373 | |
| 374 RTC_DCHECK(!media_packets.empty()); | |
| 375 Packet* first_media_packet = media_packets.front().get(); | |
| 376 RTC_DCHECK(first_media_packet); | |
| 377 uint16_t seq_num = ParseSequenceNumber(first_media_packet->data); | |
| 378 for (int i = 0; i < num_fec_packets; ++i) { | |
| 379 Packet* const fec_packet = &generated_fec_packets_[i]; | |
| 380 // -- FEC header -- | |
| 381 fec_packet->data[0] &= 0x7f; // Set E to zero. | |
| 382 if (l_bit == 0) { | |
| 383 fec_packet->data[0] &= 0xbf; // Clear the L bit. | |
| 384 } else { | |
| 385 fec_packet->data[0] |= 0x40; // Set the L bit. | |
| 386 } | |
| 387 // Sequence number from first media packet used as SN base. | |
| 388 // We use the same sequence number base for every FEC packet, | |
| 389 // but that's not required in general. | |
| 390 ByteWriter<uint16_t>::WriteBigEndian(&fec_packet->data[2], seq_num); | |
| 391 | |
| 392 // -- ULP header -- | |
| 393 // Copy the payload size to the protection length field. | |
| 394 // (We protect the entire packet.) | |
| 395 ByteWriter<uint16_t>::WriteBigEndian( | |
| 396 &fec_packet->data[10], | |
| 397 fec_packet->length - kFecHeaderSize - ulp_header_size); | |
| 398 | |
| 399 // Copy the packet mask. | |
| 400 memcpy(&fec_packet->data[12], &packet_mask[i * num_mask_bytes], | |
| 401 num_mask_bytes); | |
| 402 } | 313 } |
| 403 } | 314 } |
| 404 | 315 |
| 405 void ForwardErrorCorrection::ResetState( | 316 void ForwardErrorCorrection::ResetState( |
| 406 RecoveredPacketList* recovered_packets) { | 317 RecoveredPacketList* recovered_packets) { |
| 407 // Free the memory for any existing recovered packets, if the caller hasn't. | 318 // Free the memory for any existing recovered packets, if the caller hasn't. |
| 408 recovered_packets->clear(); | 319 recovered_packets->clear(); |
| 409 received_fec_packets_.clear(); | 320 received_fec_packets_.clear(); |
| 410 } | 321 } |
| 411 | 322 |
| 412 void ForwardErrorCorrection::InsertMediaPacket( | 323 void ForwardErrorCorrection::InsertMediaPacket( |
| 413 ReceivedPacket* received_packet, | 324 RecoveredPacketList* recovered_packets, |
| 414 RecoveredPacketList* recovered_packets) { | 325 ReceivedPacket* received_packet) { |
| 415 | |
| 416 // Search for duplicate packets. | 326 // Search for duplicate packets. |
| 417 for (const auto& recovered_packet : *recovered_packets) { | 327 for (const auto& recovered_packet : *recovered_packets) { |
| 418 if (received_packet->seq_num == recovered_packet->seq_num) { | 328 if (received_packet->seq_num == recovered_packet->seq_num) { |
| 419 // Duplicate packet, no need to add to list. | 329 // Duplicate packet, no need to add to list. |
| 420 // Delete duplicate media packet data. | 330 // Delete duplicate media packet data. |
| 421 received_packet->pkt = nullptr; | 331 received_packet->pkt = nullptr; |
| 422 return; | 332 return; |
| 423 } | 333 } |
| 424 } | 334 } |
| 425 | |
| 426 std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket()); | 335 std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket()); |
| 427 // This "recovered packet" was not recovered using parity packets. | 336 // This "recovered packet" was not recovered using parity packets. |
| 428 recovered_packet->was_recovered = false; | 337 recovered_packet->was_recovered = false; |
| 429 // This media packet has already been passed on. | 338 // This media packet has already been passed on. |
| 430 recovered_packet->returned = true; | 339 recovered_packet->returned = true; |
| 431 recovered_packet->seq_num = received_packet->seq_num; | 340 recovered_packet->seq_num = received_packet->seq_num; |
| 432 recovered_packet->pkt = received_packet->pkt; | 341 recovered_packet->pkt = received_packet->pkt; |
| 433 recovered_packet->pkt->length = received_packet->pkt->length; | 342 recovered_packet->pkt->length = received_packet->pkt->length; |
| 434 | |
| 435 RecoveredPacket* recovered_packet_ptr = recovered_packet.get(); | |
| 436 // TODO(holmer): Consider replacing this with a binary search for the right | 343 // TODO(holmer): Consider replacing this with a binary search for the right |
| 437 // position, and then just insert the new packet. Would get rid of the sort. | 344 // position, and then just insert the new packet. Would get rid of the sort. |
| 345 RecoveredPacket* recovered_packet_ptr = recovered_packet.get(); |
| 438 recovered_packets->push_back(std::move(recovered_packet)); | 346 recovered_packets->push_back(std::move(recovered_packet)); |
| 439 recovered_packets->sort(SortablePacket::LessThan()); | 347 recovered_packets->sort(SortablePacket::LessThan()); |
| 440 UpdateCoveringFecPackets(recovered_packet_ptr); | 348 UpdateCoveringFecPackets(*recovered_packet_ptr); |
| 441 } | 349 } |
| 442 | 350 |
| 443 void ForwardErrorCorrection::UpdateCoveringFecPackets(RecoveredPacket* packet) { | 351 void ForwardErrorCorrection::UpdateCoveringFecPackets( |
| 352 const RecoveredPacket& packet) { |
| 444 for (auto& fec_packet : received_fec_packets_) { | 353 for (auto& fec_packet : received_fec_packets_) { |
| 445 // Is this FEC packet protecting the media packet |packet|? | 354 // Is this FEC packet protecting the media packet |packet|? |
| 446 auto protected_it = std::lower_bound(fec_packet->protected_packets.begin(), | 355 auto protected_it = std::lower_bound(fec_packet->protected_packets.begin(), |
| 447 fec_packet->protected_packets.end(), | 356 fec_packet->protected_packets.end(), |
| 448 packet, | 357 &packet, SortablePacket::LessThan()); |
| 449 SortablePacket::LessThan()); | |
| 450 if (protected_it != fec_packet->protected_packets.end() && | 358 if (protected_it != fec_packet->protected_packets.end() && |
| 451 (*protected_it)->seq_num == packet->seq_num) { | 359 (*protected_it)->seq_num == packet.seq_num) { |
| 452 // Found an FEC packet which is protecting |packet|. | 360 // Found an FEC packet which is protecting |packet|. |
| 453 (*protected_it)->pkt = packet->pkt; | 361 (*protected_it)->pkt = packet.pkt; |
| 454 } | 362 } |
| 455 } | 363 } |
| 456 } | 364 } |
| 457 | 365 |
| 458 void ForwardErrorCorrection::InsertFecPacket( | 366 void ForwardErrorCorrection::InsertFecPacket( |
| 459 ReceivedPacket* received_packet, | 367 const RecoveredPacketList& recovered_packets, |
| 460 const RecoveredPacketList* recovered_packets) { | 368 ReceivedPacket* received_packet) { |
| 461 // Check for duplicate. | 369 // Check for duplicate. |
| 462 for (const auto& existing_fec_packet : received_fec_packets_) { | 370 for (const auto& existing_fec_packet : received_fec_packets_) { |
| 463 if (received_packet->seq_num == existing_fec_packet->seq_num) { | 371 if (received_packet->seq_num == existing_fec_packet->seq_num) { |
| 464 // Delete duplicate FEC packet data. | 372 // Delete duplicate FEC packet data. |
| 465 received_packet->pkt = nullptr; | 373 received_packet->pkt = nullptr; |
| 466 return; | 374 return; |
| 467 } | 375 } |
| 468 } | 376 } |
| 469 | |
| 470 std::unique_ptr<ReceivedFecPacket> fec_packet(new ReceivedFecPacket()); | 377 std::unique_ptr<ReceivedFecPacket> fec_packet(new ReceivedFecPacket()); |
| 471 fec_packet->pkt = received_packet->pkt; | 378 fec_packet->pkt = received_packet->pkt; |
| 472 fec_packet->seq_num = received_packet->seq_num; | 379 fec_packet->seq_num = received_packet->seq_num; |
| 473 fec_packet->ssrc = received_packet->ssrc; | 380 fec_packet->ssrc = received_packet->ssrc; |
| 474 | 381 // Parse ULPFEC/FlexFEC header specific info. |
| 475 const uint16_t seq_num_base = | 382 bool ret = fec_header_reader_->ReadFecHeader(fec_packet.get()); |
| 476 ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[2]); | 383 if (!ret) { |
| 477 const uint16_t mask_size_bytes = (fec_packet->pkt->data[0] & 0x40) | 384 LOG(LS_WARNING) << "Malformed FEC header: dropping packet."; |
| 478 ? kMaskSizeLBitSet | 385 return; |
| 479 : kMaskSizeLBitClear; // L bit set? | 386 } |
| 480 | 387 // Parse packet mask from header and represent as protected packets. |
| 481 // Parse erasure code mask from ULP header and represent as protected packets. | 388 for (uint16_t byte_idx = 0; byte_idx < fec_packet->packet_mask_size; |
| 482 for (uint16_t byte_idx = 0; byte_idx < mask_size_bytes; ++byte_idx) { | 389 ++byte_idx) { |
| 483 uint8_t packet_mask = fec_packet->pkt->data[12 + byte_idx]; | 390 uint8_t packet_mask = |
| 391 fec_packet->pkt->data[fec_packet->packet_mask_offset + byte_idx]; |
| 484 for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) { | 392 for (uint16_t bit_idx = 0; bit_idx < 8; ++bit_idx) { |
| 485 if (packet_mask & (1 << (7 - bit_idx))) { | 393 if (packet_mask & (1 << (7 - bit_idx))) { |
| 486 std::unique_ptr<ProtectedPacket> protected_packet( | 394 std::unique_ptr<ProtectedPacket> protected_packet( |
| 487 new ProtectedPacket()); | 395 new ProtectedPacket()); |
| 488 // This wraps naturally with the sequence number. | 396 // This wraps naturally with the sequence number. |
| 489 protected_packet->seq_num = | 397 protected_packet->seq_num = static_cast<uint16_t>( |
| 490 static_cast<uint16_t>(seq_num_base + (byte_idx << 3) + bit_idx); | 398 fec_packet->seq_num_base + (byte_idx << 3) + bit_idx); |
| 491 protected_packet->pkt = nullptr; | 399 protected_packet->pkt = nullptr; |
| 492 // Note that |protected_pkt_list| is sorted (according to sequence | |
| 493 // number) by construction. | |
| 494 fec_packet->protected_packets.push_back(std::move(protected_packet)); | 400 fec_packet->protected_packets.push_back(std::move(protected_packet)); |
| 495 } | 401 } |
| 496 } | 402 } |
| 497 } | 403 } |
| 498 if (fec_packet->protected_packets.empty()) { | 404 if (fec_packet->protected_packets.empty()) { |
| 499 // All-zero packet mask; we can discard this FEC packet. | 405 // All-zero packet mask; we can discard this FEC packet. |
| 500 LOG(LS_WARNING) << "Received FEC packet has an all-zero packet mask."; | 406 LOG(LS_WARNING) << "Received FEC packet has an all-zero packet mask."; |
| 501 } else { | 407 } else { |
| 502 AssignRecoveredPackets(fec_packet.get(), recovered_packets); | 408 AssignRecoveredPackets(recovered_packets, fec_packet.get()); |
| 503 // TODO(holmer): Consider replacing this with a binary search for the right | 409 // TODO(holmer): Consider replacing this with a binary search for the right |
| 504 // position, and then just insert the new packet. Would get rid of the sort. | 410 // position, and then just insert the new packet. Would get rid of the sort. |
| 505 // | 411 // |
| 506 // For correct decoding, |fec_packet_list_| does not necessarily | 412 // For correct decoding, |received_fec_packets_| does not necessarily |
| 507 // need to be sorted by sequence number (see decoding algorithm in | 413 // need to be sorted by sequence number (see decoding algorithm in |
| 508 // AttemptRecover()), but by keeping it sorted we try to recover the | 414 // AttemptRecover()). By keeping it sorted we try to recover the |
| 509 // oldest lost packets first. | 415 // oldest lost packets first, however. |
| 510 received_fec_packets_.push_back(std::move(fec_packet)); | 416 received_fec_packets_.push_back(std::move(fec_packet)); |
| 511 received_fec_packets_.sort(SortablePacket::LessThan()); | 417 received_fec_packets_.sort(SortablePacket::LessThan()); |
| 512 if (received_fec_packets_.size() > kMaxFecPackets) { | 418 const size_t max_fec_packets = fec_header_reader_->MaxFecPackets(); |
| 419 if (received_fec_packets_.size() > max_fec_packets) { |
| 513 received_fec_packets_.pop_front(); | 420 received_fec_packets_.pop_front(); |
| 514 } | 421 } |
| 515 RTC_DCHECK_LE(received_fec_packets_.size(), kMaxFecPackets); | 422 RTC_DCHECK_LE(received_fec_packets_.size(), max_fec_packets); |
| 516 } | 423 } |
| 517 } | 424 } |
| 518 | 425 |
| 519 void ForwardErrorCorrection::AssignRecoveredPackets( | 426 void ForwardErrorCorrection::AssignRecoveredPackets( |
| 520 ReceivedFecPacket* fec_packet, | 427 const RecoveredPacketList& recovered_packets, |
| 521 const RecoveredPacketList* recovered_packets) { | 428 ReceivedFecPacket* fec_packet) { |
| 522 ProtectedPacketList* protected_packets = &fec_packet->protected_packets; | 429 ProtectedPacketList* protected_packets = &fec_packet->protected_packets; |
| 523 std::vector<RecoveredPacket*> recovered_protected_packets; | 430 std::vector<RecoveredPacket*> recovered_protected_packets; |
| 524 | 431 |
| 525 // Find intersection between the (sorted) containers |protected_packets| | 432 // Find intersection between the (sorted) containers |protected_packets| |
| 526 // and |recovered_packets|, i.e. all protected packets that have already | 433 // and |recovered_packets|, i.e. all protected packets that have already |
| 527 // been recovered. Update the corresponding protected packets to point to | 434 // been recovered. Update the corresponding protected packets to point to |
| 528 // the recovered packets. | 435 // the recovered packets. |
| 529 auto it_p = protected_packets->cbegin(); | 436 auto it_p = protected_packets->cbegin(); |
| 530 auto it_r = recovered_packets->cbegin(); | 437 auto it_r = recovered_packets.cbegin(); |
| 531 SortablePacket::LessThan less_than; | 438 SortablePacket::LessThan less_than; |
| 532 while (it_p != protected_packets->end() && it_r != recovered_packets->end()) { | 439 while (it_p != protected_packets->end() && it_r != recovered_packets.end()) { |
| 533 if (less_than(*it_p, *it_r)) { | 440 if (less_than(*it_p, *it_r)) { |
| 534 ++it_p; | 441 ++it_p; |
| 535 } else if (less_than(*it_r, *it_p)) { | 442 } else if (less_than(*it_r, *it_p)) { |
| 536 ++it_r; | 443 ++it_r; |
| 537 } else { // *it_p == *it_r. | 444 } else { // *it_p == *it_r. |
| 538 // This protected packet has already been recovered. | 445 // This protected packet has already been recovered. |
| 539 (*it_p)->pkt = (*it_r)->pkt; | 446 (*it_p)->pkt = (*it_r)->pkt; |
| 540 ++it_p; | 447 ++it_p; |
| 541 ++it_r; | 448 ++it_r; |
| 542 } | 449 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 559 if (!received_fec_packets_.empty()) { | 466 if (!received_fec_packets_.empty()) { |
| 560 uint16_t seq_num_diff = | 467 uint16_t seq_num_diff = |
| 561 abs(static_cast<int>(received_packet->seq_num) - | 468 abs(static_cast<int>(received_packet->seq_num) - |
| 562 static_cast<int>(received_fec_packets_.front()->seq_num)); | 469 static_cast<int>(received_fec_packets_.front()->seq_num)); |
| 563 if (seq_num_diff > 0x3fff) { | 470 if (seq_num_diff > 0x3fff) { |
| 564 received_fec_packets_.pop_front(); | 471 received_fec_packets_.pop_front(); |
| 565 } | 472 } |
| 566 } | 473 } |
| 567 | 474 |
| 568 if (received_packet->is_fec) { | 475 if (received_packet->is_fec) { |
| 569 InsertFecPacket(received_packet, recovered_packets); | 476 InsertFecPacket(*recovered_packets, received_packet); |
| 570 } else { | 477 } else { |
| 571 InsertMediaPacket(received_packet, recovered_packets); | 478 InsertMediaPacket(recovered_packets, received_packet); |
| 572 } | 479 } |
| 573 // Delete the received packet "wrapper". | 480 // Delete the received packet "wrapper". |
| 574 received_packets->pop_front(); | 481 received_packets->pop_front(); |
| 575 } | 482 } |
| 576 RTC_DCHECK(received_packets->empty()); | 483 RTC_DCHECK(received_packets->empty()); |
| 577 DiscardOldRecoveredPackets(recovered_packets); | 484 DiscardOldRecoveredPackets(recovered_packets); |
| 578 } | 485 } |
| 579 | 486 |
| 580 bool ForwardErrorCorrection::StartPacketRecovery( | 487 bool ForwardErrorCorrection::StartPacketRecovery( |
| 581 const ReceivedFecPacket* fec_packet, | 488 const ReceivedFecPacket& fec_packet, |
| 582 RecoveredPacket* recovered_packet) { | 489 RecoveredPacket* recovered_packet) { |
| 583 // This is the first packet which we try to recover with. | 490 // Sanity check packet length. |
| 584 const uint16_t ulp_header_size = fec_packet->pkt->data[0] & 0x40 | 491 if (fec_packet.pkt->length < fec_packet.fec_header_size) { |
| 585 ? kUlpHeaderSizeLBitSet | |
| 586 : kUlpHeaderSizeLBitClear; // L bit set? | |
| 587 if (fec_packet->pkt->length < | |
| 588 static_cast<size_t>(kFecHeaderSize + ulp_header_size)) { | |
| 589 LOG(LS_WARNING) | 492 LOG(LS_WARNING) |
| 590 << "Truncated FEC packet doesn't contain room for ULP header."; | 493 << "The FEC packet is truncated: it does not contain enough room " |
| 494 << "for its own header."; |
| 591 return false; | 495 return false; |
| 592 } | 496 } |
| 497 // Initialize recovered packet data. |
| 593 recovered_packet->pkt = new Packet(); | 498 recovered_packet->pkt = new Packet(); |
| 594 memset(recovered_packet->pkt->data, 0, IP_PACKET_SIZE); | 499 memset(recovered_packet->pkt->data, 0, IP_PACKET_SIZE); |
| 595 recovered_packet->returned = false; | 500 recovered_packet->returned = false; |
| 596 recovered_packet->was_recovered = true; | 501 recovered_packet->was_recovered = true; |
| 597 uint16_t protection_length = | 502 // Copy bytes corresponding to minimum RTP header size. |
| 598 ByteReader<uint16_t>::ReadBigEndian(&fec_packet->pkt->data[10]); | 503 // Note that the sequence number and SSRC fields will be overwritten |
| 599 if (protection_length > | 504 // at the end of packet recovery. |
| 600 std::min( | 505 memcpy(&recovered_packet->pkt->data, fec_packet.pkt->data, kRtpHeaderSize); |
| 601 sizeof(recovered_packet->pkt->data) - kRtpHeaderSize, | 506 // Copy remaining FEC payload. |
| 602 sizeof(fec_packet->pkt->data) - kFecHeaderSize - ulp_header_size)) { | 507 if (fec_packet.protection_length > |
| 603 LOG(LS_WARNING) << "Incorrect FEC protection length, dropping."; | 508 std::min(sizeof(recovered_packet->pkt->data) - kRtpHeaderSize, |
| 509 sizeof(fec_packet.pkt->data) - fec_packet.fec_header_size)) { |
| 510 LOG(LS_WARNING) << "Incorrect protection length, dropping FEC packet."; |
| 604 return false; | 511 return false; |
| 605 } | 512 } |
| 606 // Copy FEC payload, skipping the ULP header. | |
| 607 memcpy(&recovered_packet->pkt->data[kRtpHeaderSize], | 513 memcpy(&recovered_packet->pkt->data[kRtpHeaderSize], |
| 608 &fec_packet->pkt->data[kFecHeaderSize + ulp_header_size], | 514 &fec_packet.pkt->data[fec_packet.fec_header_size], |
| 609 protection_length); | 515 fec_packet.protection_length); |
| 610 // Copy the length recovery field. | |
| 611 memcpy(recovered_packet->length_recovery, &fec_packet->pkt->data[8], 2); | |
| 612 // Copy the first 2 bytes of the FEC header. | |
| 613 memcpy(recovered_packet->pkt->data, fec_packet->pkt->data, 2); | |
| 614 // Copy the 5th to 8th bytes of the FEC header. | |
| 615 memcpy(&recovered_packet->pkt->data[4], &fec_packet->pkt->data[4], 4); | |
| 616 // Set the SSRC field. | |
| 617 ByteWriter<uint32_t>::WriteBigEndian(&recovered_packet->pkt->data[8], | |
| 618 fec_packet->ssrc); | |
| 619 return true; | 516 return true; |
| 620 } | 517 } |
| 621 | 518 |
| 622 bool ForwardErrorCorrection::FinishPacketRecovery( | 519 bool ForwardErrorCorrection::FinishPacketRecovery( |
| 520 const ReceivedFecPacket& fec_packet, |
| 623 RecoveredPacket* recovered_packet) { | 521 RecoveredPacket* recovered_packet) { |
| 624 // Set the RTP version to 2. | 522 // Set the RTP version to 2. |
| 625 recovered_packet->pkt->data[0] |= 0x80; // Set the 1st bit. | 523 recovered_packet->pkt->data[0] |= 0x80; // Set the 1st bit. |
| 626 recovered_packet->pkt->data[0] &= 0xbf; // Clear the 2nd bit. | 524 recovered_packet->pkt->data[0] &= 0xbf; // Clear the 2nd bit. |
| 627 | 525 // Recover the packet length, from temporary location. |
| 526 recovered_packet->pkt->length = |
| 527 ByteReader<uint16_t>::ReadBigEndian(&recovered_packet->pkt->data[2]) + |
| 528 kRtpHeaderSize; |
| 529 if (recovered_packet->pkt->length > |
| 530 sizeof(recovered_packet->pkt->data) - kRtpHeaderSize) { |
| 531 LOG(LS_WARNING) << "The recovered packet had a length larger than a " |
| 532 << "typical IP packet, and is thus dropped."; |
| 533 return false; |
| 534 } |
| 628 // Set the SN field. | 535 // Set the SN field. |
| 629 ByteWriter<uint16_t>::WriteBigEndian(&recovered_packet->pkt->data[2], | 536 ByteWriter<uint16_t>::WriteBigEndian(&recovered_packet->pkt->data[2], |
| 630 recovered_packet->seq_num); | 537 recovered_packet->seq_num); |
| 631 // Recover the packet length. | 538 // Set the SSRC field. |
| 632 recovered_packet->pkt->length = | 539 ByteWriter<uint32_t>::WriteBigEndian(&recovered_packet->pkt->data[8], |
| 633 ByteReader<uint16_t>::ReadBigEndian(recovered_packet->length_recovery) + | 540 fec_packet.protected_ssrc); |
| 634 kRtpHeaderSize; | |
| 635 if (recovered_packet->pkt->length > | |
| 636 sizeof(recovered_packet->pkt->data) - kRtpHeaderSize) { | |
| 637 return false; | |
| 638 } | |
| 639 | |
| 640 return true; | 541 return true; |
| 641 } | 542 } |
| 642 | 543 |
| 643 void ForwardErrorCorrection::XorPackets(const Packet* src, | 544 void ForwardErrorCorrection::XorHeaders(const Packet& src, Packet* dst) { |
| 644 RecoveredPacket* dst) { | 545 // XOR the first 2 bytes of the header: V, P, X, CC, M, PT fields. |
| 645 // XOR with the first 2 bytes of the RTP header. | 546 dst->data[0] ^= src.data[0]; |
| 646 for (uint32_t i = 0; i < 2; ++i) { | 547 dst->data[1] ^= src.data[1]; |
| 647 dst->pkt->data[i] ^= src->data[i]; | |
| 648 } | |
| 649 // XOR with the 5th to 8th bytes of the RTP header. | |
| 650 for (uint32_t i = 4; i < 8; ++i) { | |
| 651 dst->pkt->data[i] ^= src->data[i]; | |
| 652 } | |
| 653 // XOR with the network-ordered payload size. | |
| 654 uint8_t media_payload_length[2]; | |
| 655 ByteWriter<uint16_t>::WriteBigEndian(media_payload_length, | |
| 656 src->length - kRtpHeaderSize); | |
| 657 dst->length_recovery[0] ^= media_payload_length[0]; | |
| 658 dst->length_recovery[1] ^= media_payload_length[1]; | |
| 659 | 548 |
| 660 // XOR with RTP payload. | 549 // XOR the length recovery field. |
| 661 // TODO(marpan/ajm): Are we doing more XORs than required here? | 550 uint8_t src_payload_length_network_order[2]; |
| 662 for (size_t i = kRtpHeaderSize; i < src->length; ++i) { | 551 ByteWriter<uint16_t>::WriteBigEndian(src_payload_length_network_order, |
| 663 dst->pkt->data[i] ^= src->data[i]; | 552 src.length - kRtpHeaderSize); |
| 553 dst->data[2] ^= src_payload_length_network_order[0]; |
| 554 dst->data[3] ^= src_payload_length_network_order[1]; |
| 555 |
| 556 // XOR the 5th to 8th bytes of the header: the timestamp field. |
| 557 dst->data[4] ^= src.data[4]; |
| 558 dst->data[5] ^= src.data[5]; |
| 559 dst->data[6] ^= src.data[6]; |
| 560 dst->data[7] ^= src.data[7]; |
| 561 |
| 562 // Skip the 9th to 12th bytes of the header. |
| 563 } |
| 564 |
| 565 void ForwardErrorCorrection::XorPayloads(const Packet& src, |
| 566 size_t payload_length, |
| 567 size_t dst_offset, |
| 568 Packet* dst) { |
| 569 // XOR the payload. |
| 570 RTC_DCHECK_LE(kRtpHeaderSize + payload_length, sizeof(src.data)); |
| 571 RTC_DCHECK_LE(dst_offset + payload_length, sizeof(dst->data)); |
| 572 for (size_t i = 0; i < payload_length; ++i) { |
| 573 dst->data[dst_offset + i] ^= src.data[kRtpHeaderSize + i]; |
| 664 } | 574 } |
| 665 } | 575 } |
| 666 | 576 |
| 667 bool ForwardErrorCorrection::RecoverPacket( | 577 bool ForwardErrorCorrection::RecoverPacket(const ReceivedFecPacket& fec_packet, |
| 668 const ReceivedFecPacket* fec_packet, | 578 RecoveredPacket* recovered_packet) { |
| 669 RecoveredPacket* rec_packet_to_insert) { | 579 if (!StartPacketRecovery(fec_packet, recovered_packet)) { |
| 670 if (!StartPacketRecovery(fec_packet, rec_packet_to_insert)) | |
| 671 return false; | 580 return false; |
| 672 for (const auto& protected_packet : fec_packet->protected_packets) { | 581 } |
| 582 for (const auto& protected_packet : fec_packet.protected_packets) { |
| 673 if (protected_packet->pkt == nullptr) { | 583 if (protected_packet->pkt == nullptr) { |
| 674 // This is the packet we're recovering. | 584 // This is the packet we're recovering. |
| 675 rec_packet_to_insert->seq_num = protected_packet->seq_num; | 585 recovered_packet->seq_num = protected_packet->seq_num; |
| 676 } else { | 586 } else { |
| 677 XorPackets(protected_packet->pkt, rec_packet_to_insert); | 587 XorHeaders(*protected_packet->pkt, recovered_packet->pkt); |
| 588 XorPayloads(*protected_packet->pkt, protected_packet->pkt->length, |
| 589 kRtpHeaderSize, recovered_packet->pkt); |
| 678 } | 590 } |
| 679 } | 591 } |
| 680 if (!FinishPacketRecovery(rec_packet_to_insert)) | 592 if (!FinishPacketRecovery(fec_packet, recovered_packet)) { |
| 681 return false; | 593 return false; |
| 594 } |
| 682 return true; | 595 return true; |
| 683 } | 596 } |
| 684 | 597 |
| 685 void ForwardErrorCorrection::AttemptRecover( | 598 void ForwardErrorCorrection::AttemptRecovery( |
| 686 RecoveredPacketList* recovered_packets) { | 599 RecoveredPacketList* recovered_packets) { |
| 687 auto fec_packet_it = received_fec_packets_.begin(); | 600 auto fec_packet_it = received_fec_packets_.begin(); |
| 688 while (fec_packet_it != received_fec_packets_.end()) { | 601 while (fec_packet_it != received_fec_packets_.end()) { |
| 689 // Search for each FEC packet's protected media packets. | 602 // Search for each FEC packet's protected media packets. |
| 690 int packets_missing = NumCoveredPacketsMissing(fec_packet_it->get()); | 603 int packets_missing = NumCoveredPacketsMissing(**fec_packet_it); |
| 691 | 604 |
| 692 // We can only recover one packet with an FEC packet. | 605 // We can only recover one packet with an FEC packet. |
| 693 if (packets_missing == 1) { | 606 if (packets_missing == 1) { |
| 694 // Recovery possible. | 607 // Recovery possible. |
| 695 std::unique_ptr<RecoveredPacket> packet_to_insert(new RecoveredPacket()); | 608 std::unique_ptr<RecoveredPacket> recovered_packet(new RecoveredPacket()); |
| 696 packet_to_insert->pkt = nullptr; | 609 recovered_packet->pkt = nullptr; |
| 697 if (!RecoverPacket(fec_packet_it->get(), packet_to_insert.get())) { | 610 if (!RecoverPacket(**fec_packet_it, recovered_packet.get())) { |
| 698 // Can't recover using this packet, drop it. | 611 // Can't recover using this packet, drop it. |
| 699 fec_packet_it = received_fec_packets_.erase(fec_packet_it); | 612 fec_packet_it = received_fec_packets_.erase(fec_packet_it); |
| 700 continue; | 613 continue; |
| 701 } | 614 } |
| 702 | 615 |
| 703 auto packet_to_insert_ptr = packet_to_insert.get(); | 616 auto recovered_packet_ptr = recovered_packet.get(); |
| 704 // Add recovered packet to the list of recovered packets and update any | 617 // Add recovered packet to the list of recovered packets and update any |
| 705 // FEC packets covering this packet with a pointer to the data. | 618 // FEC packets covering this packet with a pointer to the data. |
| 706 // TODO(holmer): Consider replacing this with a binary search for the | 619 // TODO(holmer): Consider replacing this with a binary search for the |
| 707 // right position, and then just insert the new packet. Would get rid of | 620 // right position, and then just insert the new packet. Would get rid of |
| 708 // the sort. | 621 // the sort. |
| 709 recovered_packets->push_back(std::move(packet_to_insert)); | 622 recovered_packets->push_back(std::move(recovered_packet)); |
| 710 recovered_packets->sort(SortablePacket::LessThan()); | 623 recovered_packets->sort(SortablePacket::LessThan()); |
| 711 UpdateCoveringFecPackets(packet_to_insert_ptr); | 624 UpdateCoveringFecPackets(*recovered_packet_ptr); |
| 712 DiscardOldRecoveredPackets(recovered_packets); | 625 DiscardOldRecoveredPackets(recovered_packets); |
| 713 fec_packet_it = received_fec_packets_.erase(fec_packet_it); | 626 fec_packet_it = received_fec_packets_.erase(fec_packet_it); |
| 714 | 627 |
| 715 // A packet has been recovered. We need to check the FEC list again, as | 628 // A packet has been recovered. We need to check the FEC list again, as |
| 716 // this may allow additional packets to be recovered. | 629 // this may allow additional packets to be recovered. |
| 717 // Restart for first FEC packet. | 630 // Restart for first FEC packet. |
| 718 fec_packet_it = received_fec_packets_.begin(); | 631 fec_packet_it = received_fec_packets_.begin(); |
| 719 } else if (packets_missing == 0) { | 632 } else if (packets_missing == 0) { |
| 720 // Either all protected packets arrived or have been recovered. We can | 633 // Either all protected packets arrived or have been recovered. We can |
| 721 // discard this FEC packet. | 634 // discard this FEC packet. |
| 722 fec_packet_it = received_fec_packets_.erase(fec_packet_it); | 635 fec_packet_it = received_fec_packets_.erase(fec_packet_it); |
| 723 } else { | 636 } else { |
| 724 fec_packet_it++; | 637 fec_packet_it++; |
| 725 } | 638 } |
| 726 } | 639 } |
| 727 } | 640 } |
| 728 | 641 |
| 729 int ForwardErrorCorrection::NumCoveredPacketsMissing( | 642 int ForwardErrorCorrection::NumCoveredPacketsMissing( |
| 730 const ReceivedFecPacket* fec_packet) { | 643 const ReceivedFecPacket& fec_packet) { |
| 731 int packets_missing = 0; | 644 int packets_missing = 0; |
| 732 for (const auto& protected_packet : fec_packet->protected_packets) { | 645 for (const auto& protected_packet : fec_packet.protected_packets) { |
| 733 if (protected_packet->pkt == nullptr) { | 646 if (protected_packet->pkt == nullptr) { |
| 734 ++packets_missing; | 647 ++packets_missing; |
| 735 if (packets_missing > 1) { | 648 if (packets_missing > 1) { |
| 736 break; // We can't recover more than one packet. | 649 break; // We can't recover more than one packet. |
| 737 } | 650 } |
| 738 } | 651 } |
| 739 } | 652 } |
| 740 return packets_missing; | 653 return packets_missing; |
| 741 } | 654 } |
| 742 | 655 |
| 743 void ForwardErrorCorrection::DiscardOldRecoveredPackets( | 656 void ForwardErrorCorrection::DiscardOldRecoveredPackets( |
| 744 RecoveredPacketList* recovered_packets) { | 657 RecoveredPacketList* recovered_packets) { |
| 745 while (recovered_packets->size() > kMaxMediaPackets) { | 658 const size_t max_media_packets = fec_header_reader_->MaxMediaPackets(); |
| 659 while (recovered_packets->size() > max_media_packets) { |
| 746 recovered_packets->pop_front(); | 660 recovered_packets->pop_front(); |
| 747 } | 661 } |
| 748 RTC_DCHECK_LE(recovered_packets->size(), kMaxMediaPackets); | 662 RTC_DCHECK_LE(recovered_packets->size(), max_media_packets); |
| 749 } | 663 } |
| 750 | 664 |
| 751 uint16_t ForwardErrorCorrection::ParseSequenceNumber(uint8_t* packet) { | 665 uint16_t ForwardErrorCorrection::ParseSequenceNumber(uint8_t* packet) { |
| 752 return (packet[2] << 8) + packet[3]; | 666 return (packet[2] << 8) + packet[3]; |
| 753 } | 667 } |
| 754 | 668 |
| 669 uint32_t ForwardErrorCorrection::ParseSsrc(uint8_t* packet) { |
| 670 return (packet[8] << 24) + (packet[9] << 16) + (packet[10] << 8) + packet[11]; |
| 671 } |
| 672 |
| 755 int ForwardErrorCorrection::DecodeFec( | 673 int ForwardErrorCorrection::DecodeFec( |
| 756 ReceivedPacketList* received_packets, | 674 ReceivedPacketList* received_packets, |
| 757 RecoveredPacketList* recovered_packets) { | 675 RecoveredPacketList* recovered_packets) { |
| 758 // TODO(marpan/ajm): can we check for multiple ULP headers, and return an | 676 // TODO(marpan/ajm): can we check for multiple ULP headers, and return an |
| 759 // error? | 677 // error? |
| 760 if (recovered_packets->size() == kMaxMediaPackets) { | 678 const size_t max_media_packets = fec_header_reader_->MaxMediaPackets(); |
| 679 if (recovered_packets->size() == max_media_packets) { |
| 761 const unsigned int seq_num_diff = | 680 const unsigned int seq_num_diff = |
| 762 abs(static_cast<int>(received_packets->front()->seq_num) - | 681 abs(static_cast<int>(received_packets->front()->seq_num) - |
| 763 static_cast<int>(recovered_packets->back()->seq_num)); | 682 static_cast<int>(recovered_packets->back()->seq_num)); |
| 764 if (seq_num_diff > kMaxMediaPackets) { | 683 if (seq_num_diff > max_media_packets) { |
| 765 // A big gap in sequence numbers. The old recovered packets | 684 // A big gap in sequence numbers. The old recovered packets |
| 766 // are now useless, so it's safe to do a reset. | 685 // are now useless, so it's safe to do a reset. |
| 767 ResetState(recovered_packets); | 686 ResetState(recovered_packets); |
| 768 } | 687 } |
| 769 } | 688 } |
| 770 InsertPackets(received_packets, recovered_packets); | 689 InsertPackets(received_packets, recovered_packets); |
| 771 AttemptRecover(recovered_packets); | 690 AttemptRecovery(recovered_packets); |
| 772 return 0; | 691 return 0; |
| 773 } | 692 } |
| 774 | 693 |
| 775 size_t ForwardErrorCorrection::MaxPacketOverhead() const { | 694 size_t ForwardErrorCorrection::MaxPacketOverhead() const { |
| 776 return kFecHeaderSize + kUlpHeaderSizeLBitSet; | 695 return fec_header_writer_->MaxPacketOverhead(); |
| 777 } | 696 } |
| 697 |
| 698 FecHeaderReader::FecHeaderReader(size_t max_media_packets, |
| 699 size_t max_fec_packets) |
| 700 : max_media_packets_(max_media_packets), |
| 701 max_fec_packets_(max_fec_packets) {} |
| 702 |
| 703 FecHeaderReader::~FecHeaderReader() = default; |
| 704 |
| 705 size_t FecHeaderReader::MaxMediaPackets() const { |
| 706 return max_media_packets_; |
| 707 } |
| 708 |
| 709 size_t FecHeaderReader::MaxFecPackets() const { |
| 710 return max_fec_packets_; |
| 711 } |
| 712 |
| 713 FecHeaderWriter::FecHeaderWriter(size_t max_media_packets, |
| 714 size_t max_fec_packets, |
| 715 size_t max_packet_overhead) |
| 716 : max_media_packets_(max_media_packets), |
| 717 max_fec_packets_(max_fec_packets), |
| 718 max_packet_overhead_(max_packet_overhead) {} |
| 719 |
| 720 FecHeaderWriter::~FecHeaderWriter() = default; |
| 721 |
| 722 size_t FecHeaderWriter::MaxMediaPackets() const { |
| 723 return max_media_packets_; |
| 724 } |
| 725 |
| 726 size_t FecHeaderWriter::MaxFecPackets() const { |
| 727 return max_fec_packets_; |
| 728 } |
| 729 |
| 730 size_t FecHeaderWriter::MaxPacketOverhead() const { |
| 731 return max_packet_overhead_; |
| 732 } |
| 733 |
| 778 } // namespace webrtc | 734 } // namespace webrtc |
| OLD | NEW |