From e7563b19b667791ac161cfdd5be574159067b12c Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Thu, 12 Feb 2026 20:45:23 +0100 Subject: [PATCH] module-rtp: Add calculate_seqnum_delta() utility function --- src/modules/module-rtp/rtp.h | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/modules/module-rtp/rtp.h b/src/modules/module-rtp/rtp.h index 24111dc67..d5bde369e 100644 --- a/src/modules/module-rtp/rtp.h +++ b/src/modules/module-rtp/rtp.h @@ -9,6 +9,9 @@ extern "C" { #endif +#include +#include + struct rtp_header { #if __BYTE_ORDER == __LITTLE_ENDIAN unsigned cc:4; @@ -85,6 +88,49 @@ struct rtp_midi_journal { uint16_t checkpoint_seqnum; } __attribute__ ((packed)); +static inline int16_t calculate_seqnum_delta(uint16_t seqnum_a, uint16_t seqnum_b) +{ + /* In RTP, sequence numbers are 16-bit unsigned integers. These + * can realistically reach the limit of that data type's range. + * In unsigned integer arithmetic, trying to increment past the + * range causes a wrap around. 65535 incremented by 1 becomes + * 0, for example. + * + * This matters when calculating deltas between sequence numbers. + * Straightforward cases like (500-450) are just like normal + * (the result would be 50 in this example). Same goes for + * reverse sequence numbers; 450-500 => -50. But when the first + * sequence number is something like 65535, and the second + * sequence number is something like 0, the straightforward + * method would result in something incorrect (a delta of + * -65535, when actually, the correct delta is 1). + * + * This code uses unsigned integer wrap-around arithmetic to + * handle such special sequence number wrap-around cases implicitly. + * A subtraction that normally would result in a negative value + * wraps around; subtracting 1 from 0, which normally would + * result in -1, becomes 65535 for example. + * + * By treating unsigned deltas below 32768 as positive deltas, and + * those >= 32768 as negative deltas, that arithmetic does the job + * for us. With two's complement, the cast directly reinterprets + * the bit pattern to produce the signed delta. (For example, uint16 + * 65535 -> int16 -1). In the very rare case of a non-2-complement + * machine, an alternative code is used that handles the >=32768 + * unsigned delta case separately. + * + * This allows for positive sequence number deltas of up to 32767 and + * negative ones of up to -32768 to be handled correctly. Such vast + * deltas between sequence numbers are highly anomalous in RTP, so + * this covers all real world use cases well. */ + +#ifdef SPA_MACHINE_USES_TWOS_COMPLEMENT + return (int16_t)(seqnum_b - seqnum_a); +#else + uint16_t udelta = seqnum_b - seqnum_a; + return (udelta < 32768) ? ((int32_t)udelta) : ((int32_t)udelta - 65536); +#endif +} #ifdef __cplusplus }