70 lines
4.0 KiB
C
70 lines
4.0 KiB
C
/* Управляемое время: весь поток сохраняется при паузах сети/CPU и ускорении аудио. */
|
|
#include <stdlib.h>
|
|
#include "../src/call/call_video_playout.h"
|
|
#include "../lib/debug_config.h"
|
|
|
|
#define CHECK(x) do { if (!(x)) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "playout test line=%d: %s", __LINE__, #x); exit(1); } } while (0)
|
|
static const int64_t origin = 1000000;
|
|
|
|
static void simulate(unsigned pause_ms, int cpu, int64_t quantum, int accelerated_audio) {
|
|
struct call_video_playout p; call_video_playout_init(&p, 7);
|
|
enum { COUNT = 480 };
|
|
struct call_video_playout_frame frames[COUNT];
|
|
for (int i = 0; i < COUNT; ++i) {
|
|
int64_t arrival = origin + i * 33333ll;
|
|
if (!cpu && arrival >= origin + 1000000 && arrival < origin + 1000000 + pause_ms * 1000ll)
|
|
arrival = origin + 1000000 + pause_ms * 1000ll;
|
|
frames[i] = (struct call_video_playout_frame){origin + i * 33333ll, arrival};
|
|
}
|
|
unsigned shown = 0, accelerated = 0;
|
|
int64_t last_show = 0, recovered_lag = INT64_MAX, audio_pts = origin - (accelerated_audio ? 150000 : 0);
|
|
for (int64_t now = origin; now < origin + 20000000 && shown < COUNT; now += quantum) {
|
|
uint32_t rate = accelerated_audio && now >= origin + 1500000 && now < origin + 2500000 ? 1100000 : 1000000;
|
|
if (now > origin) audio_pts += quantum * rate / 1000000;
|
|
if (cpu && now >= origin + 1000000 && now < origin + 1000000 + pause_ms * 1000ll) continue;
|
|
struct call_clock_snapshot audio = {.pts_us = audio_pts, .rate_ppm = rate,
|
|
.valid = !(now >= origin + 4000000 && now < origin + 4100000)};
|
|
struct call_video_playout_frame *f = frames + shown;
|
|
int action = call_video_playout_poll(&p, f->received_us <= now ? f : NULL, NULL, now, &audio);
|
|
if (action == CALL_VIDEO_PLAYOUT_WAIT) continue;
|
|
CHECK(action == CALL_VIDEO_PLAYOUT_SHOW && audio.valid);
|
|
CHECK(!last_show || now > last_show);
|
|
CHECK(f->pts_us - audio.pts_us <= 40000);
|
|
if (p.speed_ppm > 1050000) accelerated++;
|
|
if (now >= origin + 6000000) recovered_lag = audio.pts_us - f->pts_us;
|
|
last_show = now; shown++;
|
|
// Даже готовая очередь после фриза не выдаётся целиком за один вызов worker.
|
|
if (shown < COUNT && frames[shown].received_us <= now)
|
|
CHECK(call_video_playout_poll(&p, frames + shown, NULL, now, &audio) == CALL_VIDEO_PLAYOUT_WAIT);
|
|
}
|
|
DEBUG_INFO(DEBUG_CATEGORY_CALL, "sequential recovery pause_ms=%u cpu=%d quantum_us=%lld audio_fast=%d shown=%u/%u lag_us=%lld",
|
|
pause_ms, cpu, (long long)quantum, accelerated_audio, shown, COUNT, (long long)recovered_lag);
|
|
CHECK(shown == COUNT && accelerated && recovered_lag < 50000);
|
|
}
|
|
|
|
static void order_and_clock(void) {
|
|
struct call_video_playout p; call_video_playout_init(&p, 9);
|
|
struct call_video_playout_frame f = {origin, origin};
|
|
struct call_clock_snapshot audio = {.pts_us = origin, .rate_ppm = 1000000};
|
|
CHECK(call_video_playout_poll(&p, &f, NULL, origin, &audio) == CALL_VIDEO_PLAYOUT_WAIT);
|
|
audio.valid = 1;
|
|
CHECK(call_video_playout_poll(&p, &f, NULL, origin, &audio) == CALL_VIDEO_PLAYOUT_SHOW);
|
|
CHECK(call_video_playout_poll(&p, &f, NULL, origin + 1000, &audio) == CALL_VIDEO_PLAYOUT_DROP_ORDER);
|
|
f.pts_us += 33333;
|
|
audio.valid = 0;
|
|
CHECK(call_video_playout_poll(&p, &f, NULL, origin + 200000, &audio) == CALL_VIDEO_PLAYOUT_WAIT);
|
|
audio.valid = 1; audio.pts_us += 200000;
|
|
CHECK(call_video_playout_poll(&p, &f, NULL, origin + 200000, &audio) == CALL_VIDEO_PLAYOUT_SHOW);
|
|
}
|
|
|
|
int main(void) {
|
|
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
|
|
const unsigned pauses[] = {50, 100, 200, 500};
|
|
for (unsigned i = 0; i < sizeof(pauses) / sizeof(pauses[0]); ++i)
|
|
for (int cpu = 0; cpu <= 1; ++cpu) {
|
|
simulate(pauses[i], cpu, 1000, 0);
|
|
simulate(pauses[i], cpu, 15625, 1);
|
|
}
|
|
order_and_clock(); return 0;
|
|
}
|