41 double da = *(
const double*)a;
42 double db = *(
const double*)b;
43 if (da < db)
return -1;
44 if (da > db)
return 1;
49static double median_of(
const double* samples,
int count) {
50 if (count <= 0)
return 0.0;
54 memcpy(tmp, samples, (
size_t)n *
sizeof(
double));
55 qsort(tmp, (
size_t)n,
sizeof(
double),
cmp_double);
60 return (tmp[n / 2 - 1] + tmp[n / 2]) / 2.0;
96 u = u * u * (3.0 - 2.0 * u);
139 double rtt = local_now - client_send_time;
141 n_log(
LOG_ERR,
"n_clock_sync: negative RTT (%.4f), ignoring sample", rtt);
159 double one_way = rtt / 2.0;
160 double offset = server_time + one_way - local_now;
164 n_log(
LOG_DEBUG,
"n_clock_sync: sample %d, offset=%.4f rtt=%.4f (best offset=%.4f median rtt=%.4f)",
172 if (rtt < 0.0) rtt = 0.0;
181 n_log(
LOG_DEBUG,
"n_clock_sync: seeded offset=%.4f (synthetic rtt=%.4f)", offset, rtt);
int sample_index
current write position in circular buffer
double last_sync_time
local time of last sync request sent
double estimated_offset
add to local time to get estimated server time (raw best-RTT target — n_clock_sync_server_time applie...
double estimated_rtt
current estimated round-trip time
double offset_change_time
local time at which estimated_offset last changed
int synthetic
TRUE while the buffer holds only a synthetic n_clock_sync_seed sample — flushed wholesale by the firs...
int sample_count
number of samples collected so far
double offset_prev
effective offset at the moment estimated_offset last changed — the slew blends offset_prev → estimate...
double rtt_samples[11]
circular buffer of RTT values
double offset_samples[11]
circular buffer of offset estimates
#define N_CLOCK_SYNC_SAMPLE_COUNT
number of samples for the median filter
N_CLOCK_SYNC * n_clock_sync_new(void)
allocate and initialize a new clock sync estimator
#define N_CLOCK_SYNC_INTERVAL
default interval between sync requests in seconds
static int cmp_double(const void *a, const void *b)
comparison function for qsort on doubles
int n_clock_sync_should_send(const N_CLOCK_SYNC *cs, double local_now)
check if it's time to send a new sync request (returns TRUE/FALSE).
double n_clock_sync_server_time(const N_CLOCK_SYNC *cs, double local_now)
get estimated server time given a local time value.
void n_clock_sync_seed(N_CLOCK_SYNC *cs, double offset, double rtt)
Inject a synthetic (offset, rtt) sample, e.g.
static double clock_sync_effective_offset(const N_CLOCK_SYNC *cs, double local_now)
effective (slewed) offset at local_now — pure function of the stored state so the const getter needs ...
#define N_CLOCK_SYNC_BURST_SAMPLES
number of REAL samples below which the burst interval applies
#define N_CLOCK_SYNC_SLEW_SECONDS
seconds over which n_clock_sync_server_time slews from the previous offset estimate to a new one (smo...
void n_clock_sync_delete(N_CLOCK_SYNC **cs)
free a clock sync estimator
void n_clock_sync_mark_sent(N_CLOCK_SYNC *cs, double local_now)
mark that a sync request was just sent
int n_clock_sync_process_response(N_CLOCK_SYNC *cs, double client_send_time, double server_time, double local_now)
record a sync response: client_send_time is the local time the request was sent, server_time is the s...
#define N_CLOCK_SYNC_BURST_INTERVAL
accelerated interval used until N_CLOCK_SYNC_BURST_SAMPLES real responses have been collected — a fre...
#define N_CLOCK_SYNC_MAX_RTT
responses with an RTT above this are rejected outright (retransmit storms / suspend-resume artefacts ...
static double median_of(const double *samples, int count)
compute the median of an array of doubles
static void clock_sync_store_sample(N_CLOCK_SYNC *cs, double offset, double rtt, double local_now)
store one (offset, rtt) sample and recompute the estimates.
clock synchronization estimator
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define __n_assert(__ptr, __ret)
macro to assert things
#define Free(__ptr)
Free Handler to get errors.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
#define LOG_WARNING
warning conditions
Clock synchronization estimator for networked games.
Common headers and low-level functions & define.