|
|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|
|