Browse Source

Bound video send debt and test decoder acceptance and rejection

master
evgeny 5 days ago
parent
commit
005d891fb4
  1. 14
      src/call/call_video_transport.c
  2. 18
      tests/test_call.c

14
src/call/call_video_transport.c

@ -81,6 +81,14 @@ static uint64_t media_bytes(uint64_t bytes, uint64_t packets) {
uint64_t headers = packets * CALL_VIDEO_HEADER_BYTES;
return bytes >= headers ? bytes - headers : 0;
}
/* Ограничиваем накопление полусекундой целевого потока плюс базовый RTT.
* 64 KiB оставляем для всплеска IDR; абсолютный предел — защита памяти. */
static uint64_t debt_limit(const struct call_video_transport *v, uint32_t rtt_us) {
uint64_t rtt = rtt_us < 2000000 ? rtt_us : 2000000;
uint64_t limit = (uint64_t)(v->applied_bps ? v->applied_bps : 1000000) * (rtt + 500000) / 8000000;
if (limit < 65536) limit = 65536;
return limit < CALL_VIDEO_MAX_FRAME ? limit : CALL_VIDEO_MAX_FRAME;
}
static void update_rate(struct call_video_transport *v) {
if (!v->rate_format.generation || !v->applied_bps) return;
struct call_session *s = v->session;
@ -128,7 +136,7 @@ static void update_rate(struct call_video_transport *v) {
sample.applied_bps = v->applied_bps; sample.minimum_bps = minimum; sample.maximum_bps = maximum;
sample.baseline_rtt_us = net.baseline_rtt_us; sample.rtt_us = net.rtt_us;
sample.frame_interval_us = v->tx.format.fps ? 1000000 / v->tx.format.fps : 33333;
sample.debt_limit_bytes = CALL_VIDEO_MAX_FRAME;
sample.debt_limit_bytes = debt_limit(v, net.baseline_rtt_us);
sample.valid = found && net.window.valid && produced.valid && net.window.end_us == produced.end_us;
// Первый KEY должен создать логический канал; до этого нет транспортных измерений.
sample.ready = found ? net.ready : 1;
@ -158,6 +166,10 @@ static void flush(struct call_video_transport *v) {
uint8_t wire[CALL_VIDEO_HEADER_BYTES + CALL_VIDEO_FRAGMENT_BYTES];
// Ограниченный burst одного вызова; повторяется по audio send и таймеру 50мс.
for (unsigned budget = 0; v->data && budget < 16; budget++) {
struct ETCP_ROUTER_TX_STATS net;
if (!etcp_router_tx_stats(s->ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL_VIDEO, get_time_us(), &net)
&& media_bytes(net.queued_bytes + net.inflight_bytes, (uint64_t)net.queued_packets + net.inflight_packets)
>= debt_limit(v, net.baseline_rtt_us)) return;
if (!etcp_router_send_q_has_room(s->ctx->inst, s->group_id, s->peer_node_id, ETCP_RT_ID_CALL_VIDEO)
|| queue_entry_count(conn->send_q) >= ROUTER_MAX_SEND_Q_PACKETS) return;
uint32_t remaining = v->tx.size - v->tx.offset;

18
tests/test_call.c

@ -65,6 +65,7 @@ enum call_phase {
P_WAIT_MEDIA, /* B: media_recv_cb получил кадр */
P_VIDEO_CONFIG, P_VIDEO_SEND, P_VIDEO_HOLD, P_VIDEO_BUSY, P_VIDEO_RESUME, P_VIDEO_RANGE_WAIT, P_VIDEO_SWITCH, P_VIDEO_SWITCH_WAIT,
P_VIDEO_SHRINK_WAIT, P_VIDEO_PORT_OPEN, P_VIDEO_PORT_RECEIVE, P_VIDEO_PORT_SEND, P_VIDEO_PORT_ACK,
P_VIDEO_DECODE_OK, P_VIDEO_DECODE_REJECT,
P_HANGUP, /* A: call_hangup */
P_WAIT_ENDED1, /* обе ENDED */
P_CALL2_START, /* A: call_start (2-й звонок) */
@ -650,10 +651,25 @@ static void call_tick(void* arg) {
case P_VIDEO_PORT_ACK: {
if (!g_port_frame) break;
if (g_port_frame != 1) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video port TX payload mismatch"); t->result = 2; break; }
if (call_video_decode_result(A, t->call_id, 1, 1)
|| call_video_decode_result(A, t->call_id, 2, 0) != -1) { t->result = 2; break; }
t->phase = P_VIDEO_DECODE_OK; break;
}
case P_VIDEO_DECODE_OK: {
struct call_video_port_status status;
if (call_video_port_status(t->call_id, &status) || status.decoded_generation != 1) break;
if (!status.decoded_accepted || call_video_decode_result(A, t->call_id, 1, 0)) { t->result = 2; break; }
t->phase_ticks = 0; t->phase = P_VIDEO_DECODE_REJECT; break;
}
case P_VIDEO_DECODE_REJECT: {
struct call_video_port_status status;
if (call_video_port_status(t->call_id, &status) || status.decoded_generation != 1 || status.decoded_accepted) break;
if (++t->phase_ticks < 10) break; // Регулятор не должен отменять запрет decoder на следующем tick.
struct call_video_frame f = video_test_frame(t->call_id, 1); f.frame_id = 2; f.pts_us += 33333;
if (call_video_send_frame(B, &f) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video ignored decoder rejection"); t->result = 2; break; }
call_video_port_request_key(t->call_id);
call_video_port_close(t->call_id);
call_video_port_detach(B); // Отменяет уже поставленный post до destroy ядра.
struct call_video_port_status status;
if (call_video_port_status(t->call_id, &status) != -1) { t->result = 2; break; }
t->phase = P_HANGUP; break;
}

Loading…
Cancel
Save