module-rtp: Add calculate_seqnum_delta() utility function

This commit is contained in:
Carlos Rafael Giani 2026-02-12 20:45:23 +01:00
parent fbe0d37649
commit e7563b19b6

View file

@ -9,6 +9,9 @@
extern "C" { extern "C" {
#endif #endif
#include <stdint.h>
#include <spa/utils/defs.h>
struct rtp_header { struct rtp_header {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned cc:4; unsigned cc:4;
@ -85,6 +88,49 @@ struct rtp_midi_journal {
uint16_t checkpoint_seqnum; uint16_t checkpoint_seqnum;
} __attribute__ ((packed)); } __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 #ifdef __cplusplus
} }