diff --git a/src/call/call_clock.h b/src/call/call_clock.h index 3cccb0f2..58f63ae3 100644 --- a/src/call/call_clock.h +++ b/src/call/call_clock.h @@ -16,6 +16,7 @@ struct call_clock_snapshot { uint64_t epoch, source_epoch, played_samples, written_samples; int64_t pts_us; uint32_t held_back_us; + uint32_t rate_ppm; // Фактический шаг source PTS в текущем PCM-участке; 1000000 = 1x, 0 = удержание. int valid, measured; }; #endif diff --git a/src/call/call_timeline.cpp b/src/call/call_timeline.cpp index 500fc44c..7cb2fb30 100644 --- a/src/call/call_timeline.cpp +++ b/src/call/call_timeline.cpp @@ -169,5 +169,6 @@ call_clock_snapshot CallTimeline::clock(int64_t nowUs) { result.held_back_us = pts < lastPts ? (uint32_t)(lastPts - pts) : 0; lastPts = std::max(pts, lastPts); result.pts_us = lastPts; result.valid = 1; + result.rate_ppm = (uint32_t)std::llround(std::max(0.0, (s.end - s.pts) / (s.count * sampleUs)) * 1000000); return result; } diff --git a/src/call/call_video_playout.h b/src/call/call_video_playout.h index 78609970..6916a960 100644 --- a/src/call/call_video_playout.h +++ b/src/call/call_video_playout.h @@ -1,20 +1,20 @@ /* Общий таймер показа видео, один владелец — RX worker. Изображениями не владеет. * poll вызывается для первого готового decoded кадра; next — следующий готовый кадр или NULL. - * SHOW/DROP потребляют первый кадр, WAIT сохраняет его. Подача decoder продолжается независимо от WAIT. + * SHOW/DROP_ORDER потребляют первый кадр, WAIT сохраняет его. Decoder работает по свободным output-буферам. * received_us ставится на входе RX port, до ожидания worker; все локальные времена — MONOTONIC, не BOOTTIME. - * Поздний poll не сдвигает расписание. Сдвиги разрешены только доступностью данных и границами A/V. + * После паузы расписание продолжается от фактического показа; долг снимается ускорением без пропусков. * Невалидные аудиочасы снимают привязку, но не очищают decoder/очередь и не меняют порядок PTS. */ #ifndef CALL_VIDEO_PLAYOUT_H #define CALL_VIDEO_PLAYOUT_H #include +#include "call_clock.h" #ifdef __cplusplus extern "C" { #endif struct call_video_playout_frame { int64_t pts_us, received_us; }; enum call_video_playout_action { - CALL_VIDEO_PLAYOUT_WAIT, CALL_VIDEO_PLAYOUT_SHOW, CALL_VIDEO_PLAYOUT_DROP_LATE, - CALL_VIDEO_PLAYOUT_DROP_SCHEDULE, CALL_VIDEO_PLAYOUT_DROP_ORDER + CALL_VIDEO_PLAYOUT_WAIT, CALL_VIDEO_PLAYOUT_SHOW, CALL_VIDEO_PLAYOUT_DROP_ORDER }; struct call_video_playout { uint64_t call_id; @@ -22,8 +22,8 @@ struct call_video_playout { int64_t last_pts, last_deadline, deadline_us; int64_t report_us, last_show_us, interval_min, interval_max, av_min, av_max, dispatch_max, data_shift; int64_t last_show_pts, last_received, gap_pts, gap_received, gap_dispatch; - int64_t late_av_min, late_av_max, late_age_min, late_age_max; // A/V и возраст от RX до пропуска за окно сводки. - unsigned shown, late, skipped, order, audio_wait, clock_wait; + uint32_t speed_ppm; // Темп аудио + коррекция отставания, максимум 1.6x. + unsigned shown, order, audio_wait, clock_wait; }; int64_t call_video_playout_now_us(void); @@ -33,7 +33,7 @@ void call_video_playout_init(struct call_video_playout *p, uint64_t call_id); * source_epoch не участвует: коррекция аудио не означает разрыв видеокодека. */ enum call_video_playout_action call_video_playout_poll(struct call_video_playout *p, const struct call_video_playout_frame *frame, const struct call_video_playout_frame *next, - int64_t now_us, int audio_valid, int64_t audio_pts_us); + int64_t now_us, const struct call_clock_snapshot *audio); #ifdef __cplusplus } #endif