Browse Source

Measure call jitter from media delivery timestamps

master
evgeny 3 days ago
parent
commit
d8745fd303
  1. 6
      src/call/call_jitter.h
  2. 20
      src/call/call_jitter_window.h

6
src/call/call_jitter.h

@ -7,7 +7,7 @@
extern "C" {
#endif
/* Звонок: FIFO Opus, адаптивный запас 60мс..max_reserve_ms (max-min за 10 секунд) и догон без сброса после паузы устройства.
/* Звонок: FIFO Opus, запас 60мс..max_reserve_ms по изменению задержки доставки за 10 секунд и догон после паузы устройства.
* push — сетевой поток, pull/decode/SoundTouch — единственный аудиопоток.
* destroy — после остановки обоих потребителей. get_stats — любой поток. */
#define CALL_JITTER_FRAME_MS 20
@ -17,7 +17,9 @@ struct call_jitter_range { int min_ms, max_ms, reserve_ms; };
struct call_jitter;
struct call_jitter* call_jitter_create(call_jitter_decode_fn decode, void* arg, int max_reserve_ms);
void call_jitter_destroy(struct call_jitter* j);
void call_jitter_push(struct call_jitter* j, const uint8_t* enc, int len);
/* sent_ms — timestamp кадра на проводе (uint32 с переполнением), received_ms — локальные монотонные часы.
* Абсолютное смещение часов пиров не влияет на оценку джиттера. */
void call_jitter_push(struct call_jitter* j, const uint8_t* enc, int len, uint32_t sent_ms, int64_t received_ms);
int call_jitter_pull(struct call_jitter* j, int16_t* out, int max_samples);
void call_jitter_get_stats(struct call_jitter* j, int* depth_ms, int* tempo_x100,
uint32_t* dropped, uint32_t* underruns, struct call_jitter_range* range);

20
src/call/call_jitter_window.h

@ -2,12 +2,15 @@
#include <algorithm>
#include <cstdint>
// Десять секундных интервалов. Время передаёт аудиопоток из монотонных часов.
// Десять секундных интервалов. Отдельные экземпляры для глубины очереди и задержки доставки.
struct call_jitter_window {
struct bucket { int64_t second = -1; int low = 0, high = 0; } buckets[10];
int low = 0, high = 0, reserve = 60;
struct bucket { int64_t second = -1, low = 0, high = 0; } buckets[10];
int64_t low = 0, high = 0;
int reserve = 60;
int max_reserve = 1000;
bool observe(int64_t now_ms, int depth) {
int64_t last_received_ms = -1, transit_ms = 0;
uint32_t last_sent_ms = 0;
bool observe(int64_t now_ms, int64_t depth) {
int64_t second = now_ms / 1000;
auto& b = buckets[second % 10];
bool changed_second = b.second != second;
@ -18,7 +21,14 @@ struct call_jitter_window {
if (item.second < 0 || item.second > second || second - item.second >= 10) continue;
low = std::min(low, item.low); high = std::max(high, item.high);
}
reserve = std::max(60, std::min(max_reserve, high - low));
reserve = (int)std::max<int64_t>(60, std::min<int64_t>(max_reserve, high - low));
return changed_second;
}
// Разность интервалов прихода и отправки: смещение часов исключается, uint32 timestamp разворачивается.
bool observe_arrival(int64_t received_ms, uint32_t sent_ms) {
if (last_received_ms >= 0) transit_ms += received_ms - last_received_ms - (int32_t)(sent_ms - last_sent_ms);
last_received_ms = received_ms; last_sent_ms = sent_ms;
return observe(received_ms, transit_ms);
}
};

Loading…
Cancel
Save