stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 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 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 11 | #include "modules/rtp_rtcp/source/fec_test_helper.h" |
stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 12 | |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 13 | #include <memory> |
| 14 | #include <utility> |
| 15 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 16 | #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" |
| 17 | #include "modules/rtp_rtcp/source/byte_io.h" |
Danil Chapovalov | 04fd215 | 2019-09-20 11:40:12 +0200 | [diff] [blame^] | 18 | #include "modules/rtp_rtcp/source/rtp_packet.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 19 | #include "modules/rtp_rtcp/source/rtp_utility.h" |
| 20 | #include "rtc_base/checks.h" |
stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 21 | |
| 22 | namespace webrtc { |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 23 | namespace test { |
| 24 | namespace fec { |
| 25 | |
| 26 | namespace { |
| 27 | constexpr uint8_t kFecPayloadType = 96; |
| 28 | constexpr uint8_t kRedPayloadType = 97; |
| 29 | constexpr uint8_t kVp8PayloadType = 120; |
brandtr | 8d02ea7 | 2016-10-03 23:47:05 -0700 | [diff] [blame] | 30 | |
| 31 | constexpr int kPacketTimestampIncrement = 3000; |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 32 | } // namespace |
stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 33 | |
Danil Chapovalov | dd7e284 | 2018-03-09 15:37:03 +0000 | [diff] [blame] | 34 | MediaPacketGenerator::MediaPacketGenerator(uint32_t min_packet_size, |
| 35 | uint32_t max_packet_size, |
| 36 | uint32_t ssrc, |
| 37 | Random* random) |
| 38 | : min_packet_size_(min_packet_size), |
| 39 | max_packet_size_(max_packet_size), |
| 40 | ssrc_(ssrc), |
| 41 | random_(random) {} |
| 42 | |
| 43 | MediaPacketGenerator::~MediaPacketGenerator() = default; |
| 44 | |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 45 | ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets( |
| 46 | int num_media_packets, |
| 47 | uint16_t start_seq_num) { |
| 48 | RTC_DCHECK_GT(num_media_packets, 0); |
| 49 | uint16_t seq_num = start_seq_num; |
| 50 | int time_stamp = random_->Rand<int>(); |
| 51 | |
| 52 | ForwardErrorCorrection::PacketList media_packets; |
| 53 | |
| 54 | for (int i = 0; i < num_media_packets; ++i) { |
| 55 | std::unique_ptr<ForwardErrorCorrection::Packet> media_packet( |
| 56 | new ForwardErrorCorrection::Packet()); |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 57 | media_packet->data.SetSize( |
| 58 | random_->Rand(min_packet_size_, max_packet_size_)); |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 59 | |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 60 | uint8_t* data = media_packet->data.data(); |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 61 | // Generate random values for the first 2 bytes |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 62 | data[0] = random_->Rand<uint8_t>(); |
| 63 | data[1] = random_->Rand<uint8_t>(); |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 64 | |
| 65 | // The first two bits are assumed to be 10 by the FEC encoder. |
| 66 | // In fact the FEC decoder will set the two first bits to 10 regardless of |
| 67 | // what they actually were. Set the first two bits to 10 so that a memcmp |
| 68 | // can be performed for the whole restored packet. |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 69 | data[0] |= 0x80; |
| 70 | data[0] &= 0xbf; |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 71 | |
| 72 | // FEC is applied to a whole frame. |
| 73 | // A frame is signaled by multiple packets without the marker bit set |
| 74 | // followed by the last packet of the frame for which the marker bit is set. |
| 75 | // Only push one (fake) frame to the FEC. |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 76 | data[1] &= 0x7f; |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 77 | |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 78 | webrtc::ByteWriter<uint16_t>::WriteBigEndian(&data[2], seq_num); |
| 79 | webrtc::ByteWriter<uint32_t>::WriteBigEndian(&data[4], time_stamp); |
| 80 | webrtc::ByteWriter<uint32_t>::WriteBigEndian(&data[8], ssrc_); |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 81 | |
| 82 | // Generate random values for payload. |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 83 | for (size_t j = 12; j < media_packet->data.size(); ++j) |
| 84 | data[j] = random_->Rand<uint8_t>(); |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 85 | seq_num++; |
| 86 | media_packets.push_back(std::move(media_packet)); |
| 87 | } |
| 88 | // Last packet, set marker bit. |
| 89 | ForwardErrorCorrection::Packet* media_packet = media_packets.back().get(); |
| 90 | RTC_DCHECK(media_packet); |
| 91 | media_packet->data[1] |= 0x80; |
| 92 | |
brandtr | d726a3f | 2017-06-29 02:45:35 -0700 | [diff] [blame] | 93 | next_seq_num_ = seq_num; |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 94 | |
| 95 | return media_packets; |
| 96 | } |
| 97 | |
| 98 | ForwardErrorCorrection::PacketList MediaPacketGenerator::ConstructMediaPackets( |
| 99 | int num_media_packets) { |
| 100 | return ConstructMediaPackets(num_media_packets, random_->Rand<uint16_t>()); |
| 101 | } |
| 102 | |
brandtr | d726a3f | 2017-06-29 02:45:35 -0700 | [diff] [blame] | 103 | uint16_t MediaPacketGenerator::GetNextSeqNum() { |
| 104 | return next_seq_num_; |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 105 | } |
| 106 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 107 | AugmentedPacketGenerator::AugmentedPacketGenerator(uint32_t ssrc) |
| 108 | : num_packets_(0), ssrc_(ssrc), seq_num_(0), timestamp_(0) {} |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 109 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 110 | void AugmentedPacketGenerator::NewFrame(size_t num_packets) { |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 111 | num_packets_ = num_packets; |
brandtr | 8d02ea7 | 2016-10-03 23:47:05 -0700 | [diff] [blame] | 112 | timestamp_ += kPacketTimestampIncrement; |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 113 | } |
| 114 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 115 | uint16_t AugmentedPacketGenerator::NextPacketSeqNum() { |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 116 | return ++seq_num_; |
| 117 | } |
| 118 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 119 | std::unique_ptr<AugmentedPacket> AugmentedPacketGenerator::NextPacket( |
| 120 | size_t offset, |
| 121 | size_t length) { |
| 122 | std::unique_ptr<AugmentedPacket> packet(new AugmentedPacket()); |
| 123 | |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 124 | packet->data.SetSize(length + kRtpHeaderSize); |
| 125 | uint8_t* data = packet->data.data(); |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 126 | for (size_t i = 0; i < length; ++i) |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 127 | data[i + kRtpHeaderSize] = offset + i; |
| 128 | packet->data.SetSize(length + kRtpHeaderSize); |
Niels Möller | 70a8394 | 2019-03-12 09:54:30 +0100 | [diff] [blame] | 129 | packet->header.headerLength = kRtpHeaderSize; |
| 130 | packet->header.markerBit = (num_packets_ == 1); |
| 131 | packet->header.payloadType = kVp8PayloadType; |
| 132 | packet->header.sequenceNumber = seq_num_; |
| 133 | packet->header.timestamp = timestamp_; |
| 134 | packet->header.ssrc = ssrc_; |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 135 | WriteRtpHeader(packet->header, packet->data.data()); |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 136 | ++seq_num_; |
| 137 | --num_packets_; |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 138 | |
| 139 | return packet; |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 140 | } |
| 141 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 142 | void AugmentedPacketGenerator::WriteRtpHeader(const RTPHeader& header, |
| 143 | uint8_t* data) { |
| 144 | data[0] = 0x80; // Version 2. |
| 145 | data[1] = header.payloadType; |
| 146 | data[1] |= (header.markerBit ? kRtpMarkerBitMask : 0); |
| 147 | ByteWriter<uint16_t>::WriteBigEndian(data + 2, header.sequenceNumber); |
| 148 | ByteWriter<uint32_t>::WriteBigEndian(data + 4, header.timestamp); |
| 149 | ByteWriter<uint32_t>::WriteBigEndian(data + 8, header.ssrc); |
| 150 | } |
| 151 | |
brandtr | 8d02ea7 | 2016-10-03 23:47:05 -0700 | [diff] [blame] | 152 | FlexfecPacketGenerator::FlexfecPacketGenerator(uint32_t media_ssrc, |
| 153 | uint32_t flexfec_ssrc) |
| 154 | : AugmentedPacketGenerator(media_ssrc), |
| 155 | flexfec_ssrc_(flexfec_ssrc), |
| 156 | flexfec_seq_num_(0), |
| 157 | flexfec_timestamp_(0) {} |
| 158 | |
| 159 | std::unique_ptr<AugmentedPacket> FlexfecPacketGenerator::BuildFlexfecPacket( |
| 160 | const ForwardErrorCorrection::Packet& packet) { |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 161 | RTC_DCHECK_LE(packet.data.size(), |
brandtr | 8d02ea7 | 2016-10-03 23:47:05 -0700 | [diff] [blame] | 162 | static_cast<size_t>(IP_PACKET_SIZE - kRtpHeaderSize)); |
| 163 | |
| 164 | RTPHeader header; |
| 165 | header.sequenceNumber = flexfec_seq_num_; |
| 166 | ++flexfec_seq_num_; |
| 167 | header.timestamp = flexfec_timestamp_; |
| 168 | flexfec_timestamp_ += kPacketTimestampIncrement; |
| 169 | header.ssrc = flexfec_ssrc_; |
| 170 | |
| 171 | std::unique_ptr<AugmentedPacket> packet_with_rtp_header( |
| 172 | new AugmentedPacket()); |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 173 | packet_with_rtp_header->data.SetSize(kRtpHeaderSize + packet.data.size()); |
| 174 | WriteRtpHeader(header, packet_with_rtp_header->data.data()); |
| 175 | memcpy(packet_with_rtp_header->data.data() + kRtpHeaderSize, |
| 176 | packet.data.cdata(), packet.data.size()); |
brandtr | 8d02ea7 | 2016-10-03 23:47:05 -0700 | [diff] [blame] | 177 | |
| 178 | return packet_with_rtp_header; |
| 179 | } |
| 180 | |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 181 | UlpfecPacketGenerator::UlpfecPacketGenerator(uint32_t ssrc) |
| 182 | : AugmentedPacketGenerator(ssrc) {} |
| 183 | |
Danil Chapovalov | 04fd215 | 2019-09-20 11:40:12 +0200 | [diff] [blame^] | 184 | RtpPacket UlpfecPacketGenerator::BuildMediaRedPacket( |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 185 | const AugmentedPacket& packet) { |
Danil Chapovalov | 04fd215 | 2019-09-20 11:40:12 +0200 | [diff] [blame^] | 186 | RtpPacket red_packet; |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 187 | // Copy RTP header. |
Danil Chapovalov | 04fd215 | 2019-09-20 11:40:12 +0200 | [diff] [blame^] | 188 | const size_t kHeaderLength = packet.header.headerLength; |
| 189 | red_packet.Parse(packet.data.cdata(), kHeaderLength); |
| 190 | RTC_DCHECK_EQ(red_packet.headers_size(), kHeaderLength); |
| 191 | uint8_t* rtp_payload = |
| 192 | red_packet.AllocatePayload(packet.data.size() + 1 - kHeaderLength); |
| 193 | // Move payload type into rtp payload. |
| 194 | rtp_payload[0] = red_packet.PayloadType(); |
| 195 | red_packet.SetPayloadType(kRedPayloadType); |
| 196 | // Copy the payload. |
| 197 | memcpy(rtp_payload + 1, packet.data.cdata() + kHeaderLength, |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 198 | packet.data.size() - kHeaderLength); |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 199 | |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 200 | return red_packet; |
| 201 | } |
| 202 | |
Danil Chapovalov | 04fd215 | 2019-09-20 11:40:12 +0200 | [diff] [blame^] | 203 | RtpPacket UlpfecPacketGenerator::BuildUlpfecRedPacket( |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 204 | const ForwardErrorCorrection::Packet& packet) { |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 205 | // Create a fake media packet to get a correct header. 1 byte RED header. |
| 206 | ++num_packets_; |
Danil Chapovalov | 04fd215 | 2019-09-20 11:40:12 +0200 | [diff] [blame^] | 207 | std::unique_ptr<AugmentedPacket> fake_packet = |
Ilya Nikolaevskiy | a5d952f | 2019-09-03 11:07:37 +0200 | [diff] [blame] | 208 | NextPacket(0, packet.data.size() + 1); |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 209 | |
Danil Chapovalov | 04fd215 | 2019-09-20 11:40:12 +0200 | [diff] [blame^] | 210 | RtpPacket red_packet; |
| 211 | red_packet.Parse(fake_packet->data); |
| 212 | red_packet.SetMarker(false); |
| 213 | uint8_t* rtp_payload = red_packet.AllocatePayload(packet.data.size() + 1); |
| 214 | rtp_payload[0] = kFecPayloadType; |
| 215 | red_packet.SetPayloadType(kRedPayloadType); |
| 216 | |
| 217 | memcpy(rtp_payload + 1, packet.data.cdata(), packet.data.size()); |
brandtr | 0aabdac | 2016-10-03 06:36:43 -0700 | [diff] [blame] | 218 | |
brandtr | a4545ee | 2016-10-03 02:58:45 -0700 | [diff] [blame] | 219 | return red_packet; |
| 220 | } |
| 221 | |
brandtr | ece4aba | 2016-09-20 23:16:28 -0700 | [diff] [blame] | 222 | } // namespace fec |
| 223 | } // namespace test |
stefan@webrtc.org | e0d6fa4 | 2012-03-20 22:10:56 +0000 | [diff] [blame] | 224 | } // namespace webrtc |