8da9e7f737
When a receiver flow is carried by more than one RTCP-capable peer,
send_nack_group historically sent every NACK to the eligible peer
with the lowest RTT. That is wrong when the lowest-RTT peer cannot
actually retransmit: e.g. a duplicate/relay feed that delivers the
same packets but keeps no retransmit buffer. NACKs go to it, the
peer that holds the buffer never hears them, and recovery stalls.
Add a per-peer recovery_priority (new ?recovery-priority=<n> URL
parameter, rist_peer_config.recovery_priority). NACK groups now go
to the eligible peer with the highest recovery_priority, ties broken
by lowest RTT. The default of 0 on every peer reduces exactly to the
prior lowest-RTT selection, so existing deployments are unchanged.
The selection predicate is factored into src/rist-nack-select.h
(rist_nack_peer_preferred) so it can be unit-tested without building
peers or starting threads.
Also name the weight=0 duplicate sentinel: new public macro
RIST_PEER_WEIGHT_DUPLICATE makes the load-balancer's "duplicate to
all peers" branch read as intent rather than a magic 0.
ABI: RIST_PEER_CONFIG_VERSION 4 -> 5 (one new trailing field,
defaulted to 0 by rist_peer_config_defaults_set; zero-initialised
configs keep legacy behaviour).
Tests:
- test/rist/unit/test_url_recovery_priority_parse.c: ?recovery-priority=
parsing through the public rist_parse_address2 API.
- test/rist/unit/test_nack_peer_select.c: priority/RTT selection,
tie-breaks, legacy-equivalence and unmeasured-RTT edge cases.
- meson test --suite unit: 8/8 OK.
- meson test (full): 51 OK, 11 Expected Fail, 0 unexpected.