diff --git a/src/call/call_video_playout.c b/src/call/call_video_playout.c index 491c28ea..80345013 100644 --- a/src/call/call_video_playout.c +++ b/src/call/call_video_playout.c @@ -58,7 +58,8 @@ enum call_video_playout_action call_video_playout_poll(struct call_video_playout p->audio_valid = !!audio_valid; } if (!audio_valid) { p->anchored = 0; p->clock_wait++; return CALL_VIDEO_PLAYOUT_WAIT; } - if (!f) return CALL_VIDEO_PLAYOUT_WAIT; + // Ожидание новых данных уже прошло в реальном времени: повторно добавлять этот интервал нельзя. + if (!f) { p->anchored = 0; return CALL_VIDEO_PLAYOUT_WAIT; } if (f->pts_us <= p->last_pts || f->received_us < 0 || f->received_us > now) { DEBUG_WARN(DEBUG_CATEGORY_CALL, "video playout invalid/order call=%llu pts=%lld last=%lld received=%lld now=%lld", (unsigned long long)p->call_id, (long long)f->pts_us, (long long)p->last_pts, diff --git a/src/call/call_video_port.c b/src/call/call_video_port.c index ff897831..1c919285 100644 --- a/src/call/call_video_port.c +++ b/src/call/call_video_port.c @@ -30,6 +30,7 @@ static struct { int64_t tx_wait_started; unsigned tx_retries; unsigned count, bytes; + int64_t rx_wait_started; // Полный FIFO возобновляет приём после drain, а не по одному освободившемуся месту. uint64_t decoded_generation; int decoded_pending, decoded_accepted; } port; @@ -48,6 +49,7 @@ static void clear_frames(void) { port.tx_wait_started = 0; port.tx_retries = 0; for (unsigned i = 0; i < port.count; ++i) u_free((void *)port.rx[i].data); port.count = port.bytes = 0; + port.rx_wait_started = 0; } static void peer(void *arg, const struct call_video_caps *caps) { pthread_mutex_lock(&lock); @@ -56,7 +58,20 @@ static void peer(void *arg, const struct call_video_caps *caps) { } static int ready(void *arg, uint32_t bytes) { pthread_mutex_lock(&lock); - int result = port.id == (uint64_t)(uintptr_t)arg && port.count < 8 && bytes <= 4u * 1024u * 1024u - port.bytes; + int result = 0; + if (port.id == (uint64_t)(uintptr_t)arg) { + if (port.rx_wait_started && !port.count) { + DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "video port RX drained call=%llu wait_us=%lld; admission resumed", + (unsigned long long)port.id, (long long)(call_video_playout_now_us() - port.rx_wait_started)); + port.rx_wait_started = 0; + } + result = !port.rx_wait_started && port.count < 8 && bytes <= 4u * 1024u * 1024u - port.bytes; + if (!result && !port.rx_wait_started) { + port.rx_wait_started = call_video_playout_now_us(); + DEBUG_WARN(DEBUG_CATEGORY_CALL, "video port RX full call=%llu frames=%u bytes=%u next_bytes=%u; drain before resume", + (unsigned long long)port.id, port.count, port.bytes, bytes); + } + } pthread_mutex_unlock(&lock); return result; } static void frame(void *arg, const struct call_video_frame *f) {