Browse Source

Test video adaptation from poor connectivity to the 4 Mbps ceiling

master
evgeny 5 days ago
parent
commit
03d8f71be4
  1. 2
      src/call/call_video_rate.c
  2. 54
      tests/test_call_video_rate.c

2
src/call/call_video_rate.c

@ -84,7 +84,7 @@ int call_video_rate_step(struct call_video_rate *rate, const struct call_video_r
uint32_t floor = s->applied_bps / 2;
if (floor < s->minimum_bps) floor = s->minimum_bps;
if (candidate < floor) candidate = floor;
if (candidate < s->applied_bps * 95ull / 100) {
if (candidate < s->applied_bps * 95ull / 100 || (candidate == s->minimum_bps && candidate < s->applied_bps)) {
result.target_bps = (uint32_t)candidate; result.reason = CALL_VIDEO_RATE_DRAIN;
}
} else if (!result.excess_bytes && result.admit && s->produced_bytes && s->delivered_bytes

54
tests/test_call_video_rate.c

@ -40,6 +40,58 @@ static void test_gates(void) {
DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS rate: cap, pending, no route, queue bound, warmup, probe and local hold");
}
static void test_range(void) {
uint32_t minimum = 0, maximum = 0;
CHECK(!call_video_rate_parse_range(CALL_VIDEO_RATE_DEFAULT_RANGE, &minimum, &maximum));
CHECK(minimum == 300000 && maximum == 4000000);
CHECK(!call_video_rate_parse_range("500:1500", &minimum, &maximum));
CHECK(minimum == 500000 && maximum == 1500000);
const char *invalid[] = {"", "299:4000", "300:4001", "4000:300", "300", "300:4000x",
"-300:4000", "300:+4000", "300: 4000", "999999999999999999999999:4000"};
for (unsigned i = 0; i < sizeof(invalid) / sizeof(invalid[0]); i++) {
CHECK(call_video_rate_parse_range(invalid[i], &minimum, &maximum) < 0);
CHECK(minimum == 500000 && maximum == 1500000);
}
CHECK(!call_video_rate_parse_range("300:300", &minimum, &maximum));
CHECK(minimum == maximum && minimum == 300000);
DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS rate: atomic range, default, fixed bitrate and malformed settings");
}
/* Сначала связь слабее нижней границы; после восстановления должны достичь потолка. */
static void test_poor_then_good(void) {
struct call_video_rate rate;
struct call_video_rate_sample s = sample(0);
struct call_video_rate_result out = {.admit = 1};
CHECK(!call_video_rate_parse_range(CALL_VIDEO_RATE_DEFAULT_RANGE, &s.minimum_bps, &s.maximum_bps));
s.applied_bps = s.maximum_bps;
uint64_t produced[10] = {0}, delivered[10] = {0}, flight[2] = {0};
uint64_t queue = 0, debt = 0, peak = 0;
int reached_floor = 0, paused = 0;
call_video_rate_init(&rate, 0);
for (unsigned i = 0; i < 2400; i++) {
uint64_t generated = out.admit ? s.applied_bps / 160 : 0;
queue += generated; debt += generated;
uint64_t acked = flight[i % 2]; debt -= acked;
uint64_t capacity = (i < 800 ? 1500000 / 10 : 6000000) / 160;
uint64_t sent = queue < capacity ? queue : capacity;
queue -= sent; flight[i % 2] = sent;
produced[i % 10] = generated; delivered[i % 10] = acked;
s.produced_bytes = s.delivered_bytes = 0;
for (unsigned j = 0; j < 10; j++) { s.produced_bytes += produced[j]; s.delivered_bytes += delivered[j]; }
s.now_us = s.window_end_us = (uint64_t)(i + 1) * 50000;
s.valid = i >= 9; s.debt_bytes = debt;
CHECK(!call_video_rate_step(&rate, &s, &out));
s.applied_bps = out.target_bps;
CHECK(s.applied_bps >= 300000 && s.applied_bps <= 4000000);
if (i < 800 && s.applied_bps == 300000) reached_floor = 1;
if (!out.admit) paused = 1;
if (debt > peak) peak = debt;
}
CHECK(reached_floor && paused && s.applied_bps == 4000000 && peak <= s.debt_limit_bytes + 25000);
DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS rate: 150kbps -> 6Mbps floor=300000 final=%u peak_debt=%llu",
s.applied_bps, (unsigned long long)peak);
}
/* Нормальный inflight на длинном RTT не должен выглядеть как перегрузка. */
static void test_long_rtt(void) {
struct call_video_rate rate;
@ -97,6 +149,6 @@ static void test_channel(int static_scene) {
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
test_gates(); test_long_rtt(); test_channel(0); test_channel(1);
test_range(); test_gates(); test_long_rtt(); test_channel(0); test_channel(1); test_poor_then_good();
return 0;
}

Loading…
Cancel
Save