Verify RX drain and explicit decoder rejection semantics

This commit is contained in:
evgeny committed 2026-10-19 17:37:24 +02:00
1 parent 943f9f2646
commit 5f1985f9ab
2 files changed
+15 -8

No files matched your search

+1 -1
View File
@@ -725,7 +725,7 @@ static void call_tick(void* arg) {
if (call_video_port_status(t->call_id, &status) || status.decoded_generation != 1 || status.decoded_accepted) break; 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. if (++t->phase_ticks < 10) break; // Регулятор не должен отменять запрет decoder на следующем tick.
struct call_video_frame f = video_test_frame(t->call_id, 1); f.frame_id = 4; f.pts_us += 99999; struct call_video_frame f = video_test_frame(t->call_id, 1); f.frame_id = 4; f.pts_us += 99999;
if (call_video_send_frame(B, &f) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video ignored decoder rejection"); t->result = 2; break; } if (call_video_send_frame(B, &f) != -1) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video ignored decoder rejection"); t->result = 2; break; }
// Все команды попадут в uasync после синхронного ENDED; TX ещё принадлежит mailbox. // Все команды попадут в uasync после синхронного ENDED; TX ещё принадлежит mailbox.
struct call_video_frame closing[2] = {f, f}; ++closing[1].frame_id; closing[1].pts_us += 33333; struct call_video_frame closing[2] = {f, f}; ++closing[1].frame_id; closing[1].pts_us += 33333;
if (call_video_port_format(t->call_id, &f.format, 500000) if (call_video_port_format(t->call_id, &f.format, 500000)
+14 -7
View File
@@ -44,7 +44,7 @@ int main(void) {
session = (struct call_session){.ctx = &ctx, .call_id = 7, .state = CALL_ST_ACTIVE}; session = (struct call_session){.ctx = &ctx, .call_id = 7, .state = CALL_ST_ACTIVE};
assert(!call_video_port_attach(&inst)); assert(!call_video_port_attach(&inst));
struct call_video_caps caps = {0}; struct call_video_caps caps = {0};
assert(!call_video_port_open(7, &caps)); uasync_drain_immediate(ua); assert(!call_video_port_open(7, &caps)); uasync_poll(ua, 0);
assert(callbacks && callbacks->writable); callbacks->writable(callback_arg, 1); assert(callbacks && callbacks->writable); callbacks->writable(callback_arg, 1);
uint8_t data[8][16]; struct call_video_frame frames[8]; uint8_t data[8][16]; struct call_video_frame frames[8];
for (unsigned i = 0; i < 8; ++i) { for (unsigned i = 0; i < 8; ++i) {
@@ -56,20 +56,27 @@ int main(void) {
extra = frames[7]; concurrent = 1; allowance = 2; extra = frames[7]; concurrent = 1; allowance = 2;
assert(call_video_port_send(frames, 8) == 1); assert(call_video_port_send(frames, 8) == 1);
memset(data, 0, sizeof(data)); // Порт обязан владеть собственной копией. memset(data, 0, sizeof(data)); // Порт обязан владеть собственной копией.
uasync_drain_immediate(ua); uasync_poll(ua, 0);
assert(accepted == 2 && port.tx_count == 6 && !port.tx_processing && !port.pending); assert(accepted == 2 && port.tx_count == 6 && !port.tx_processing && !port.pending);
unsigned before = offered; uasync_drain_immediate(ua); assert(offered == before); // Нет busy loop. unsigned before = offered; uasync_poll(ua, 0); assert(offered == before); // Нет busy loop.
struct call_video_port_status status; struct call_video_port_status status;
assert(!call_video_port_status(7, &status) && !status.can_encode && !status.key_serial); assert(!call_video_port_status(7, &status) && !status.can_encode && !status.key_serial);
for (unsigned i = 0; i < 3; ++i) { for (unsigned i = 0; i < 3; ++i) {
callbacks->writable(callback_arg, 0); uasync_drain_immediate(ua); callbacks->writable(callback_arg, 0); uasync_poll(ua, 0);
assert(accepted == 2 && port.tx_count == 6 && !port.pending); assert(accepted == 2 && port.tx_count == 6 && !port.pending);
} }
allowance = 8; callbacks->writable(callback_arg, 1); uasync_drain_immediate(ua); allowance = 8; callbacks->writable(callback_arg, 1); uasync_poll(ua, 0);
assert(accepted == 8 && !port.tx_count); assert(accepted == 8 && !port.tx_count);
assert(!call_video_port_status(7, &status) && status.can_encode && !status.key_serial); assert(!call_video_port_status(7, &status) && status.can_encode && !status.key_serial);
DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS video port: all 8 frames preserved across partial send and repeated busy; no KEY or spin"); DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS video port: all 8 frames preserved across partial send and repeated busy; no KEY or spin");
call_video_port_close(7); uasync_drain_immediate(ua); for (unsigned i = 0; i < 8; ++i) { assert(callbacks->receive_ready(callback_arg, 16)); callbacks->frame(callback_arg, &frames[i]); }
call_video_port_detach(&inst); uasync_drain_immediate(ua); assert(!callbacks->receive_ready(callback_arg, 16));
for (unsigned i = 0; i < 8; ++i) {
struct call_video_frame f; assert(call_video_port_pull(7, &f) == 1 && f.frame_id == i + 1); u_free((void *)f.data);
assert(callbacks->receive_ready(callback_arg, 16) == (i == 7));
}
DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS video port: full RX drains completely before resuming producer admission");
call_video_port_close(7); uasync_poll(ua, 0);
call_video_port_detach(&inst); uasync_poll(ua, 0);
uasync_destroy(ua, 0); return 0; uasync_destroy(ua, 0); return 0;
} }