Avoid wrong parsing of padding length and its use in NetEq simulation.
Bug: b/113648474, webrtc:9730
Change-Id: Ieff7ab8697f5c8742548897a9b452a20b0bd2e7c
Reviewed-on: https://webrtc-review.googlesource.com/98461
Commit-Queue: Minyue Li <minyue@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24703}
diff --git a/logging/rtc_event_log/rtc_event_log_parser_new.cc b/logging/rtc_event_log/rtc_event_log_parser_new.cc
index bb5b1b2..9fbf0d0 100644
--- a/logging/rtc_event_log/rtc_event_log_parser_new.cc
+++ b/logging/rtc_event_log/rtc_event_log_parser_new.cc
@@ -584,6 +584,7 @@
event, &direction, header, &header_length, &total_length, nullptr);
RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
RTPHeader parsed_header;
+
if (extension_map != nullptr) {
rtp_parser.Parse(&parsed_header, extension_map);
} else {
@@ -595,6 +596,15 @@
// Tracking bug: webrtc:6399
rtp_parser.Parse(&parsed_header, &default_extension_map_);
}
+
+ // Since we give the parser only a header, there is no way for it to know
+ // the padding length. The best solution would be to log the padding
+ // length in RTC event log. In absence of it, we assume the RTP packet to
+ // contain only padding, if the padding bit is set.
+ // TODO(webrtc:9730): Use a generic way to obtain padding length.
+ if ((header[0] & 0x20) != 0)
+ parsed_header.paddingLength = total_length - header_length;
+
RTC_CHECK(event.has_timestamp_us());
uint64_t timestamp_us = event.timestamp_us();
if (direction == kIncomingPacket) {
diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
index 273539c..7a6573f 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.cc
@@ -262,7 +262,8 @@
}
void EventGenerator::RandomizeRtpPacket(
- size_t packet_size,
+ size_t payload_size,
+ size_t padding_size,
uint32_t ssrc,
const RtpHeaderExtensionMap& extension_map,
RtpPacket* rtp_packet) {
@@ -291,27 +292,40 @@
if (extension_map.IsRegistered(TransportSequenceNumber::kId))
rtp_packet->SetExtension<TransportSequenceNumber>(prng_.Rand<uint16_t>());
- RTC_DCHECK_GE(packet_size, rtp_packet->headers_size());
- size_t payload_size = packet_size - rtp_packet->headers_size();
RTC_CHECK_LE(rtp_packet->headers_size() + payload_size, IP_PACKET_SIZE);
+
uint8_t* payload = rtp_packet->AllocatePayload(payload_size);
RTC_DCHECK(payload != nullptr);
for (size_t i = 0; i < payload_size; i++) {
payload[i] = prng_.Rand<uint8_t>();
}
+ RTC_CHECK(rtp_packet->SetPadding(padding_size, &prng_));
}
std::unique_ptr<RtcEventRtpPacketIncoming> EventGenerator::NewRtpPacketIncoming(
uint32_t ssrc,
const RtpHeaderExtensionMap& extension_map) {
+ constexpr size_t kMaxPaddingLength = 224;
+ const bool padding = prng_.Rand(0, 9) == 0; // Let padding be 10% probable.
+ const size_t padding_size = !padding ? 0u : prng_.Rand(0u, kMaxPaddingLength);
+
// 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC.
constexpr size_t kMaxHeaderSize =
16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions;
- size_t packet_size =
- prng_.Rand(kMaxHeaderSize, static_cast<uint32_t>(IP_PACKET_SIZE - 1));
+
+ // In principle, a packet can contain both padding and other payload.
+ // Currently, RTC eventlog encoder-parser can only maintain padding length if
+ // packet is full padding.
+ // TODO(webrtc:9730): Remove the deterministic logic for padding_size > 0.
+ size_t payload_size =
+ padding_size > 0 ? 0
+ : prng_.Rand(0u, static_cast<uint32_t>(IP_PACKET_SIZE -
+ 1 - padding_size -
+ kMaxHeaderSize));
RtpPacketReceived rtp_packet(&extension_map);
- RandomizeRtpPacket(packet_size, ssrc, extension_map, &rtp_packet);
+ RandomizeRtpPacket(payload_size, padding_size, ssrc, extension_map,
+ &rtp_packet);
return absl::make_unique<RtcEventRtpPacketIncoming>(rtp_packet);
}
@@ -319,14 +333,28 @@
std::unique_ptr<RtcEventRtpPacketOutgoing> EventGenerator::NewRtpPacketOutgoing(
uint32_t ssrc,
const RtpHeaderExtensionMap& extension_map) {
+ constexpr size_t kMaxPaddingLength = 224;
+ const bool padding = prng_.Rand(0, 9) == 0; // Let padding be 10% probable.
+ const size_t padding_size = !padding ? 0u : prng_.Rand(0u, kMaxPaddingLength);
+
// 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC.
constexpr size_t kMaxHeaderSize =
16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions;
- size_t packet_size =
- prng_.Rand(kMaxHeaderSize, static_cast<uint32_t>(IP_PACKET_SIZE - 1));
- RtpPacketToSend rtp_packet(&extension_map, packet_size);
- RandomizeRtpPacket(packet_size, ssrc, extension_map, &rtp_packet);
+ // In principle,a packet can contain both padding and other payload.
+ // Currently, RTC eventlog encoder-parser can only maintain padding length if
+ // packet is full padding.
+ // TODO(webrtc:9730): Remove the deterministic logic for padding_size > 0.
+ size_t payload_size =
+ padding_size > 0 ? 0
+ : prng_.Rand(0u, static_cast<uint32_t>(IP_PACKET_SIZE -
+ 1 - padding_size -
+ kMaxHeaderSize));
+
+ RtpPacketToSend rtp_packet(&extension_map,
+ kMaxHeaderSize + payload_size + padding_size);
+ RandomizeRtpPacket(payload_size, padding_size, ssrc, extension_map,
+ &rtp_packet);
int probe_cluster_id = prng_.Rand(0, 100000);
return absl::make_unique<RtcEventRtpPacketOutgoing>(rtp_packet,
@@ -619,8 +647,6 @@
return false;
}
- if (original_header.padding_size() != logged_header.paddingLength)
- return false;
if (original_header.headers_size() != logged_header.headerLength)
return false;
@@ -698,6 +724,16 @@
if (original_event.packet_length_ != logged_event.rtp.total_length)
return false;
+ if ((original_event.header_.data()[0] & 0x20) != 0 && // has padding
+ original_event.packet_length_ - original_event.header_.headers_size() !=
+ logged_event.rtp.header.paddingLength) {
+ // Currently, RTC eventlog encoder-parser can only maintain padding length
+ // if packet is full padding.
+ // TODO(webrtc:9730): Change the condition to something like
+ // original_event.padding_length_ != logged_event.rtp.header.paddingLength.
+ return false;
+ }
+
if (!VerifyLoggedRtpHeader(original_event.header_, logged_event.rtp.header))
return false;
@@ -716,6 +752,16 @@
if (original_event.packet_length_ != logged_event.rtp.total_length)
return false;
+ if ((original_event.header_.data()[0] & 0x20) != 0 && // has padding
+ original_event.packet_length_ - original_event.header_.headers_size() !=
+ logged_event.rtp.header.paddingLength) {
+ // Currently, RTC eventlog encoder-parser can only maintain padding length
+ // if packet is full padding.
+ // TODO(webrtc:9730): Change the condition to something like
+ // original_event.padding_length_ != logged_event.rtp.header.paddingLength.
+ return false;
+ }
+
// TODO(terelius): Probe cluster ID isn't parsed, used or tested. Unless
// someone has a strong reason to keep it, it'll be removed.
diff --git a/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
index d67469c..f4d1876 100644
--- a/logging/rtc_event_log/rtc_event_log_unittest_helper.h
+++ b/logging/rtc_event_log/rtc_event_log_unittest_helper.h
@@ -70,7 +70,8 @@
std::unique_ptr<RtcEventRtcpPacketOutgoing> NewRtcpPacketOutgoing();
- void RandomizeRtpPacket(size_t packet_size,
+ void RandomizeRtpPacket(size_t payload_size,
+ size_t padding_size,
uint32_t ssrc,
const RtpHeaderExtensionMap& extension_map,
RtpPacket* rtp_packet);
diff --git a/modules/audio_coding/neteq/tools/neteq_replacement_input.cc b/modules/audio_coding/neteq/tools/neteq_replacement_input.cc
index 362eb89..ffd114a 100644
--- a/modules/audio_coding/neteq/tools/neteq_replacement_input.cc
+++ b/modules/audio_coding/neteq/tools/neteq_replacement_input.cc
@@ -42,7 +42,15 @@
std::unique_ptr<NetEqInput::PacketData> NetEqReplacementInput::PopPacket() {
std::unique_ptr<PacketData> to_return = std::move(packet_);
- packet_ = source_->PopPacket();
+ while (true) {
+ packet_ = source_->PopPacket();
+ if (!packet_)
+ break;
+ if (packet_->payload.size() > packet_->header.paddingLength) {
+ // Not padding only. Good to go. Skip this packet otherwise.
+ break;
+ }
+ }
ReplacePacket();
return to_return;
}
diff --git a/modules/audio_coding/neteq/tools/neteq_test.cc b/modules/audio_coding/neteq/tools/neteq_test.cc
index ff60048..e51ee47 100644
--- a/modules/audio_coding/neteq/tools/neteq_test.cc
+++ b/modules/audio_coding/neteq/tools/neteq_test.cc
@@ -95,16 +95,23 @@
if (input_->NextPacketTime() && time_now_ms >= *input_->NextPacketTime()) {
std::unique_ptr<NetEqInput::PacketData> packet_data = input_->PopPacket();
RTC_CHECK(packet_data);
- int error = neteq_->InsertPacket(
- packet_data->header,
- rtc::ArrayView<const uint8_t>(packet_data->payload),
- static_cast<uint32_t>(packet_data->time_ms * sample_rate_hz_ / 1000));
- if (error != NetEq::kOK && callbacks_.error_callback) {
- callbacks_.error_callback->OnInsertPacketError(*packet_data);
- }
- if (callbacks_.post_insert_packet) {
- callbacks_.post_insert_packet->AfterInsertPacket(*packet_data,
- neteq_.get());
+ const size_t payload_data_length =
+ packet_data->payload.size() - packet_data->header.paddingLength;
+ if (payload_data_length != 0) {
+ int error = neteq_->InsertPacket(
+ packet_data->header,
+ rtc::ArrayView<const uint8_t>(packet_data->payload),
+ static_cast<uint32_t>(packet_data->time_ms * sample_rate_hz_ /
+ 1000));
+ if (error != NetEq::kOK && callbacks_.error_callback) {
+ callbacks_.error_callback->OnInsertPacketError(*packet_data);
+ }
+ if (callbacks_.post_insert_packet) {
+ callbacks_.post_insert_packet->AfterInsertPacket(*packet_data,
+ neteq_.get());
+ }
+ } else {
+ neteq_->InsertEmptyPacket(packet_data->header);
}
if (last_packet_time_ms_) {
current_state_.packet_iat_ms.push_back(time_now_ms -
diff --git a/modules/rtp_rtcp/source/rtp_utility.cc b/modules/rtp_rtcp/source/rtp_utility.cc
index 5f5b3dc0..228572f 100644
--- a/modules/rtp_rtcp/source/rtp_utility.cc
+++ b/modules/rtp_rtcp/source/rtp_utility.cc
@@ -197,7 +197,9 @@
header->timestamp = RTPTimestamp;
header->ssrc = SSRC;
header->numCSRCs = CC;
- header->paddingLength = P ? *(_ptrRTPDataEnd - 1) : 0;
+ if (!P) {
+ header->paddingLength = 0;
+ }
for (uint8_t i = 0; i < CC; ++i) {
uint32_t CSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
@@ -276,6 +278,21 @@
}
header->headerLength += XLen;
}
+ if (header->headerLength > static_cast<size_t>(length))
+ return false;
+
+ if (P) {
+ // Packet has padding.
+ if (header->headerLength != static_cast<size_t>(length)) {
+ // Packet is not header only. We can parse padding length now.
+ header->paddingLength = *(_ptrRTPDataEnd - 1);
+ } else {
+ RTC_LOG(LS_WARNING) << "Cannot parse padding length.";
+ // Packet is header only. We have no clue of the padding length.
+ return false;
+ }
+ }
+
if (header->headerLength + header->paddingLength >
static_cast<size_t>(length))
return false;