diff --git a/tests/Makefile.am b/tests/Makefile.am index ed81c412..403b80a9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -12,6 +12,7 @@ check_PROGRAMS = \ test_route_tx_stats \ test_call_video_rate \ test_call_video_playout \ + test_call_video_port \ test_call_video \ test_call_video_flush \ test_memory_pool_and_config \ @@ -718,6 +719,9 @@ test_call_video_rate_LDADD = $(LIBUTUN) $(COMMON_LIBS) test_call_video_playout_SOURCES = test_call_video_playout.c test_call_video_playout_LDADD = $(LIBUTUN) $(COMMON_LIBS) +test_call_video_port_SOURCES = test_call_video_port.c +test_call_video_port_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS) + test_call_video_SOURCES = test_call_video.c test_call_video_LDADD = $(LIBUTUN) $(COMMON_LIBS) diff --git a/tests/test_call_video_port.c b/tests/test_call_video_port.c new file mode 100644 index 00000000..31eb8e1c --- /dev/null +++ b/tests/test_call_video_port.c @@ -0,0 +1,75 @@ +/* Реальные mailbox/mutex/post: частичная передача, повторная занятость, конкурентный producer и отмена. */ +#define call_video_send_frame test_video_send +#define call_video_configure test_video_configure +#define call_session_find test_session_find +#define chat_setting_get test_setting_get +#include "../src/call/call_video_port.c" +#undef call_video_send_frame +#undef call_video_configure +#undef call_session_find +#undef chat_setting_get +#include + +static struct call_session session; +static const struct call_video_ops *callbacks; +static void *callback_arg; +static unsigned accepted, allowance, offered; +static int concurrent; +static struct call_video_frame extra; + +struct call_session *test_session_find(struct call_ctx *ctx, uint64_t id) { + return ctx == session.ctx && id == session.call_id ? &session : NULL; +} +const char *test_setting_get(struct UTUN_INSTANCE *inst, const char *name) { + (void)inst; (void)name; return "300:4000"; +} +int test_video_configure(struct UTUN_INSTANCE *inst, uint64_t id, const struct call_video_caps *caps, + const struct call_video_ops *ops, void *arg) { + (void)inst; (void)id; (void)caps; callbacks = ops; callback_arg = arg; return 0; +} +int test_video_send(struct UTUN_INSTANCE *inst, const struct call_video_frame *f) { + (void)inst; offered++; + if (concurrent) { assert(call_video_port_send(&extra, 1) == 0); concurrent = 0; } + if (accepted == allowance) return 0; + assert(f->frame_id == accepted + 1 && f->pts_us == (int64_t)f->frame_id * 33333); + assert(f->size == 16); + for (unsigned i = 0; i < f->size; ++i) assert(f->data[i] == f->frame_id); + accepted++; return 1; +} + +int main(void) { + debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); + struct UASYNC *ua = uasync_create(); assert(ua); + struct UTUN_INSTANCE inst = {.ua = ua}; struct call_ctx ctx = {.inst = &inst}; inst.call = &ctx; + session = (struct call_session){.ctx = &ctx, .call_id = 7, .state = CALL_ST_ACTIVE}; + assert(!call_video_port_attach(&inst)); + struct call_video_caps caps = {0}; + assert(!call_video_port_open(7, &caps)); uasync_drain_immediate(ua); + assert(callbacks && callbacks->writable); callbacks->writable(callback_arg, 1); + uint8_t data[8][16]; struct call_video_frame frames[8]; + for (unsigned i = 0; i < 8; ++i) { + memset(data[i], i + 1, sizeof(data[i])); + frames[i] = (struct call_video_frame){.call_id = 7, .frame_id = i + 1, .pts_us = (i + 1) * 33333, + .format = {1, 640, 480, 30, 0, CALL_VIDEO_H264, 31, 4000000, CALL_VIDEO_BASELINE}, + .size = 16, .length = 16, .data = data[i]}; + } + extra = frames[7]; concurrent = 1; allowance = 2; + assert(call_video_port_send(frames, 8) == 1); + memset(data, 0, sizeof(data)); // Порт обязан владеть собственной копией. + uasync_drain_immediate(ua); + assert(accepted == 2 && port.tx_count == 6 && !port.tx_processing && !port.pending); + unsigned before = offered; uasync_drain_immediate(ua); assert(offered == before); // Нет busy loop. + struct call_video_port_status status; + assert(!call_video_port_status(7, &status) && !status.can_encode && !status.key_serial); + for (unsigned i = 0; i < 3; ++i) { + callbacks->writable(callback_arg, 0); uasync_drain_immediate(ua); + assert(accepted == 2 && port.tx_count == 6 && !port.pending); + } + allowance = 8; callbacks->writable(callback_arg, 1); uasync_drain_immediate(ua); + assert(accepted == 8 && !port.tx_count); + 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"); + call_video_port_close(7); uasync_drain_immediate(ua); + call_video_port_detach(&inst); uasync_drain_immediate(ua); + uasync_destroy(ua, 0); return 0; +}