Merge pull request #13692 from alvaroelpob/feat/libwebrtc-rtcp-common-header

feat(libwebrtc): implement webrtc::rtcp::CommonHeader::Parse
This commit is contained in:
Adrià authored and GitHub committed 2026-10-31 21:40:00 +01:00
commit 9fe758d752
7 files changed
+259 -7

No files matched your search

+11
View File
@@ -3,6 +3,7 @@ target_include_directories(libwebrtc PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libwebrtc)
target_sources(libwebrtc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/ExpFilter.cpp)
target_sources(libwebrtc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/RtcpCommonHeader.cpp)
if(BUILD_TESTING)
add_test_executable(guest_webrtc_fast_int_to_buffer_tests ${CMAKE_CURRENT_SOURCE_DIR}/tests/FastIntToBuffer.cpp)
@@ -25,4 +26,14 @@ if(BUILD_TESTING)
set_tests_properties(guest_webrtc_exp_filter PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libwebrtc>")
endif()
add_test_executable(guest_webrtc_rtcp_common_header_tests ${CMAKE_CURRENT_SOURCE_DIR}/tests/RtcpCommonHeader.cpp)
target_include_directories(guest_webrtc_rtcp_common_header_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_webrtc_rtcp_common_header_tests PRIVATE libwebrtc libc)
configure_windows_unwind(guest_webrtc_rtcp_common_header_tests)
add_test(NAME guest_webrtc_rtcp_common_header COMMAND guest_webrtc_rtcp_common_header_tests)
set_tests_properties(guest_webrtc_rtcp_common_header PROPERTIES TIMEOUT 20)
if(WIN32)
set_tests_properties(guest_webrtc_rtcp_common_header PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libwebrtc>")
endif()
endif()
-5
View File
@@ -1128,11 +1128,6 @@ int APS5_VABI _ZN6webrtc4rtcp3AppD1Ev_nid_postfix(void) {
return 0;
}
int APS5_VABI _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(void) {
NotImplemented_nid_no_patch(__func__);
return 0;
}
APS5_EXPORT("PEV9t77ljzc", libwebrtcUnknown34);
int APS5_VABI libwebrtcUnknown34(void) {
NotImplemented_nid_no_patch("PEV9t77ljzc");
+2 -1
View File
@@ -2,6 +2,7 @@
#include "SceTypes.hpp"
#include "prx/libwebrtc/include/ExpFilter.hpp"
#include "prx/libwebrtc/include/RtcpCommonHeader.hpp"
extern "C" {
@@ -222,7 +223,7 @@ int APS5_VABI _ZNK6webrtc4rtcp10RtcpPacket5BuildEv_nid_postfix(void);
int APS5_VABI _ZN6webrtc4rtcp3App5ParseERKNS0_12CommonHeaderE_nid_postfix(void);
int APS5_VABI _ZN6webrtc4rtcp3AppC1Ev_nid_postfix(void);
int APS5_VABI _ZN6webrtc4rtcp3AppD1Ev_nid_postfix(void);
int APS5_VABI _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(void);
bool APS5_VABI _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(WebRtcRtcpCommonHeader* header, const std::uint8_t* buffer, std::size_t size);
int APS5_VABI libwebrtcUnknown34(void);
int APS5_VABI _ZN6webrtc4rtcp14CompoundPacketC1Ev_nid_postfix(void);
int APS5_VABI _ZN6webrtc4rtcp14CompoundPacketD1Ev_nid_postfix(void);
@@ -0,0 +1,19 @@
#pragma once
#include <cstddef>
#include <cstdint>
constexpr std::size_t WebRtcRtcpCommonHeaderSize = 4;
struct WebRtcRtcpCommonHeader {
std::uint8_t packetType;
std::uint8_t countOrFormat;
std::uint8_t paddingSize;
std::uint32_t payloadSize;
const std::uint8_t* payload;
};
static_assert(sizeof(WebRtcRtcpCommonHeader) == 16);
static_assert(offsetof(WebRtcRtcpCommonHeader, paddingSize) == 2);
static_assert(offsetof(WebRtcRtcpCommonHeader, payloadSize) == 4);
static_assert(offsetof(WebRtcRtcpCommonHeader, payload) == 8);
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* Copyright (c) 2011, The WebRTC project authors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Google nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "prx/libwebrtc/libwebrtc.hpp"
#include <cstddef>
#include <cstdint>
#include <stdexcept>
extern "C" {
bool APS5_VABI _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(WebRtcRtcpCommonHeader* header, const std::uint8_t* buffer, std::size_t size) {
if (!header)
throw std::invalid_argument("CommonHeader::Parse requires a header");
if (size < WebRtcRtcpCommonHeaderSize)
return false;
if (!buffer)
throw std::invalid_argument("CommonHeader::Parse requires a buffer");
if ((buffer[0] >> 6) != 2)
return false;
bool hasPadding = (buffer[0] & 0x20) != 0;
header->countOrFormat = buffer[0] & 0x1F;
header->packetType = buffer[1];
header->payloadSize = ((static_cast<std::uint32_t>(buffer[2]) << 8) | buffer[3]) * 4u;
header->payload = buffer + WebRtcRtcpCommonHeaderSize;
header->paddingSize = 0;
if (size < WebRtcRtcpCommonHeaderSize + header->payloadSize)
return false;
if (hasPadding) {
if (header->payloadSize == 0)
return false;
header->paddingSize = header->payload[header->payloadSize - 1];
if (header->paddingSize == 0)
return false;
if (header->paddingSize > header->payloadSize)
return false;
header->payloadSize -= header->paddingSize;
}
return true;
}
}
@@ -0,0 +1,144 @@
#include "prx/libwebrtc/libwebrtc.hpp"
#include <array>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <source_location>
#include <stdexcept>
#include <vector>
namespace {
void Require(bool condition, std::source_location location = std::source_location::current()) {
if (condition) return;
std::fprintf(stderr, "libwebrtc rtcp::CommonHeader check failed at line %u\n", location.line());
std::abort();
}
template<typename TAction> void RequireInvalidArgument(TAction action, std::source_location location = std::source_location::current()) {
try {
action();
} catch (const std::invalid_argument&) {
return;
}
Require(false, location);
}
WebRtcRtcpCommonHeader Filled() {
WebRtcRtcpCommonHeader header;
std::memset(&header, 0xA5, sizeof(header));
return header;
}
bool Parse(WebRtcRtcpCommonHeader& header, const std::vector<std::uint8_t>& packet, std::size_t size) {
return _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(&header, packet.data(), size);
}
bool Unchanged(const WebRtcRtcpCommonHeader& header) {
WebRtcRtcpCommonHeader filled = Filled();
return header.packetType == filled.packetType && header.countOrFormat == filled.countOrFormat && header.paddingSize == filled.paddingSize &&
header.payloadSize == filled.payloadSize && header.payload == filled.payload;
}
void TestReceiverReport() {
std::vector<std::uint8_t> packet {0x81, 201, 0x00, 0x07};
packet.resize(32, 0x11);
WebRtcRtcpCommonHeader header = Filled();
Require(Parse(header, packet, packet.size()));
Require(header.countOrFormat == 1);
Require(header.packetType == 201);
Require(header.payloadSize == 28);
Require(header.paddingSize == 0);
Require(header.payload == packet.data() + 4);
}
void TestFeedbackFormatAndEmptyPayload() {
std::vector<std::uint8_t> packet {0x9F, 206, 0x00, 0x00};
WebRtcRtcpCommonHeader header = Filled();
Require(Parse(header, packet, packet.size()));
Require(header.countOrFormat == 31);
Require(header.packetType == 206);
Require(header.payloadSize == 0);
Require(header.paddingSize == 0);
}
void TestPadding() {
std::vector<std::uint8_t> packet {0xA0, 200, 0x00, 0x02, 1, 2, 3, 4, 5, 0, 0, 3};
WebRtcRtcpCommonHeader header = Filled();
Require(Parse(header, packet, packet.size()));
Require(header.countOrFormat == 0);
Require(header.paddingSize == 3);
Require(header.payloadSize == 5);
Require(header.payload == packet.data() + 4);
packet[11] = 8;
header = Filled();
Require(Parse(header, packet, packet.size()));
Require(header.paddingSize == 8);
Require(header.payloadSize == 0);
}
void TestRejectsBeforeReading() {
std::vector<std::uint8_t> packet {0x80, 200, 0x00, 0x00};
WebRtcRtcpCommonHeader header = Filled();
Require(!Parse(header, packet, 3));
Require(Unchanged(header));
Require(!_ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(&header, nullptr, 3));
Require(Unchanged(header));
for (std::uint8_t first : {0x00, 0x41, 0xC1}) {
packet[0] = first;
Require(!Parse(header, packet, packet.size()));
Require(Unchanged(header));
}
}
void TestRejectsAfterReading() {
std::vector<std::uint8_t> packet {0x81, 201, 0x00, 0x02, 1, 2, 3, 4, 5, 6, 7};
WebRtcRtcpCommonHeader header = Filled();
Require(!Parse(header, packet, packet.size()));
Require(header.countOrFormat == 1);
Require(header.packetType == 201);
Require(header.payloadSize == 8);
Require(header.paddingSize == 0);
Require(header.payload == packet.data() + 4);
std::vector<std::uint8_t> empty {0xA0, 200, 0x00, 0x00};
header = Filled();
Require(!Parse(header, empty, empty.size()));
Require(header.payloadSize == 0);
Require(header.paddingSize == 0);
std::vector<std::uint8_t> zeroPadding {0xA0, 200, 0x00, 0x01, 1, 2, 3, 0};
header = Filled();
Require(!Parse(header, zeroPadding, zeroPadding.size()));
Require(header.payloadSize == 4);
Require(header.paddingSize == 0);
std::vector<std::uint8_t> tooMuchPadding {0xA0, 200, 0x00, 0x01, 1, 2, 3, 5};
header = Filled();
Require(!Parse(header, tooMuchPadding, tooMuchPadding.size()));
Require(header.payloadSize == 4);
Require(header.paddingSize == 5);
}
void TestNullArguments() {
std::array<std::uint8_t, 4> packet {0x80, 200, 0x00, 0x00};
RequireInvalidArgument([&] { _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(nullptr, packet.data(), packet.size()); });
WebRtcRtcpCommonHeader header = Filled();
RequireInvalidArgument([&] { _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(&header, nullptr, 4); });
Require(Unchanged(header));
}
}
int main() {
TestReceiverReport();
TestFeedbackFormatAndEmptyPayload();
TestPadding();
TestRejectsBeforeReading();
TestRejectsAfterReading();
TestNullArguments();
std::puts("libwebrtc rtcp::CommonHeader tests passed");
}
+2 -1
View File
@@ -2,7 +2,7 @@
### Unknown function info
- [409 exports (60 without a known name, bound by NID)](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - every function export of `libwebrtc.sprx` from the firmware 13.60 export table that the next section does not implement, names from aerolib.csv only where `tools/nid_names.py` `compute_nid` reproduces the NID. Signatures, parameter layouts and behaviour are unknown; every export throws through `NotImplemented_nid_no_patch`
- [408 exports (60 without a known name, bound by NID)](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - every function export of `libwebrtc.sprx` from the firmware 13.60 export table that the next section does not implement, names from aerolib.csv only where `tools/nid_names.py` `compute_nid` reproduces the NID. Signatures, parameter layouts and behaviour are unknown; every export throws through `NotImplemented_nid_no_patch`
- [31 data exports](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - the module also exports 31 data objects (+qcl2IzxTzg, -ix-knPYqWA, 00mefEErs+Y, 5FM0YOa3NWc, 67nsSkXmJ7E, 7I2xDnqfDV4, 8Dzy4JayJSU, CVCDyAzGrhI, HpbtuVdvO-w, PGIpx6NnFLE, Q+xnDp4KI-s, QXDv9OpZNvM, aOOjLmup+u4, g5USRJNh3bU, hvpHGXjlpbk, iU6+qODNSjU, jpkYoOv34AM, lHLJlq3NEqE, lQJvoyxHov4, nUaORqH85DQ, o6LS+08kOUs, oh8srl3AcNE, oslHzys1vV0, sp5NqvqDdHw, t66Gw3OIpSo, tr8vseK8-ro, uSis0q+bv6k, uTz5pEKL+hM, uxkudCJIYJA, whHm70jlRXw, yW0sV3sCdPA); they are not defined, so imports of them stay unresolved until their layout is known
### Public source implementations
@@ -10,3 +10,4 @@
- [Source revision](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - the module's exact WebRTC revision is not identified. Its `rtc::` names and `InterleavedView` resampler overloads place it between M127 ([branch-heads/6533](https://webrtc.googlesource.com/src/+/e0b28a6a81a989c1f5c89e30fcd247870047390d)) and M134 ([branch-heads/6998](https://webrtc.googlesource.com/src/+/8d78f5de6c27b2c793039989ea381f1428fb0100)), so the exports below follow code that is the same at both. Nothing is checked on the console. Closes when: the revision is identified and the exports are compared with the console.
- [absl::numbers_internal::FastIntToBuffer(int, char*)](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - follows the abseil both branches pin, [65ef38d368](https://chromium.googlesource.com/chromium/src/third_party/+/65ef38d36813d1ad9d4cbf8a18b32ac3691f418b/abseil-cpp/absl/strings/numbers.cc) and [d212a71416](https://chromium.googlesource.com/chromium/src/third_party/+/d212a71416ad7c6ceca04d6d27dfdd84fd00c04c/abseil-cpp/absl/strings/numbers.cc): the decimal text and a NUL, returning a pointer to the NUL. For magnitudes from 10 to 99999999 its 8-byte store also zeroes the bytes after the digits up to 8 from the first digit. A null buffer, which abseil writes through, throws. Closes when: compared with the console.
- [rtc::ExpFilter::Reset and Apply](../../../core/libs/prx/libwebrtc/src/ExpFilter.cpp) (libwebrtc) - adapted from [exp_filter.cc](https://webrtc.googlesource.com/src/+/8d78f5de6c27b2c793039989ea381f1428fb0100/rtc_base/numerics/exp_filter.cc), with its WebRTC copyright notice and BSD licence at the top of the file, on the 12-byte `alpha_`, `filtered_` and `max_` layout of `exp_filter.h`. -1 marks both an unset output and no maximum, so an output that lands on exactly -1 restarts the filter on the next sample, as upstream does. The last bit of a result can differ if the console build fuses the multiply-adds. A null filter throws. Closes when: compared with the console.
- [webrtc::rtcp::CommonHeader::Parse](../../../core/libs/prx/libwebrtc/src/RtcpCommonHeader.cpp) (libwebrtc) - adapted from [common_header.cc](https://webrtc.googlesource.com/src/+/8d78f5de6c27b2c793039989ea381f1428fb0100/modules/rtp_rtcp/source/rtcp_packet/common_header.cc), with its WebRTC copyright notice and BSD licence at the top of the file, on the 16-byte layout of `common_header.h`: packet type, count or format and padding size at 0 to 2, payload size at 4 and payload pointer at 8. Its checks run in the same order, so a short buffer or a wrong version leaves the header untouched and the later failures leave the fields already parsed. The `RTC_LOG(LS_WARNING)` message each failure logs upstream is not emitted. A null header, or a null buffer of 4 bytes or more, which upstream reads, throws. Closes when: the warnings are logged through libwebrtc's logging and the parse is compared with the console.