view src/twjit.c @ 43:8cdfef36d9db default tip

twrtp_endp_create: make config argument const This argument is passed through to twrtp_jibuf_create(). We made it const in the latter function, now do the same with the wrapper.
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 20 Dec 2024 23:01:06 +0000
parents 334d883b96ba
children
line wrap: on
line source

/*
 * Themyscira Wireless jitter buffer implementation: main body.
 */

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include <osmocom/core/linuxlist.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>

#include <themwi/rtp/twjit.h>

void twrtp_jibuf_init_defaults(struct twrtp_jibuf_config *config)
{
	memset(config, 0, sizeof(struct twrtp_jibuf_config));

	/* While the theoretical minimum starting fill level is 1, the
	 * practically useful minimum (achieving lowest latency, but not
	 * incurring underruns in normal healthy operation) is 2 for typical
	 * network configurations that combine elements with "perfect" 20 ms
	 * timing (T1/E1 interfaces, external IP-PSTN links, software
	 * transcoders timed by system clock etc) and GSM-to-IP OsmoBTS
	 * whose 20 ms timing contains the small inherent jitter of TDMA. */
	config->bd_start = 2;

	/* The high water mark setting determines when the standing queue
	 * thinning mechanism kicks in.  A standing queue that is longer
	 * than the starting fill level will occur when the flow starts
	 * during a network latency spike, but then the network latency
	 * goes down.  If this setting is too high, deep standing queues
	 * will persist, adding needless latency to speech or CSD.
	 * If this setting is too low, the thinning mechanism will be
	 * too invasive, needlessly and perhaps frequently deleting a quantum
	 * of speech or data from the stream and incurring a phase shift.
	 * Starting fill level plus 2 seems like a good default. */
	config->bd_hiwat = 4;

	/* When the standing queue thinning mechanism does kick in,
	 * it drops every Nth packet, where N is the thinning interval.
	 * Given that this mechanism forcibly deletes a quantum of speech
	 * or data from the stream, these induced disruptions should be
	 * spaced out, and the managing operator should also keep in mind
	 * that the incurred phase shift may be a problem for some
	 * applications, particularly CSD.  Our current default is
	 * a prime number, reducing the probability that the thinning
	 * mechanism will interfere badly with intrinsic features of the
	 * stream being thinned.  17 quantum units at 20 ms per quantum
	 * is 340 ms, which should be sufficiently long spacing to make
	 * speech quantum deletions tolerable. */
	config->thinning_int = 17;

	/* With RTP timestamps being 32 bits and with the usual RTP
	 * clock rate of 8000 timestamp units per second, a packet may
	 * arrive that claims to be as far as 3 days into the future.
	 * Such aberrant RTP packets are jocularly referred to as
	 * time travelers.  Assuming that actual time travel either
	 * does not exist at all or at least does not happen in the
	 * present context, we reason that when such "time traveler" RTP
	 * packets do arrive, we must be dealing with the effect of a
	 * software bug or misdesign or misconfiguration in whatever
	 * foreign network element is sending us RTP.  In any case,
	 * irrespective of the cause, we must be prepared for the
	 * possibility of seeming "time travel" in the incoming RTP stream.
	 * We implement an arbitrary threshold: if the received RTP ts
	 * is too far into the future, we treat that packet as the
	 * beginning of a new stream, same as SSRC change or non-quantum
	 * ts increment.  This threshold has 1 s granularity, which is
	 * sufficient for its intended purpose of catching gross errors.
	 * The minimum setting of this threshold is 1 s, but let's
	 * default to 10 s, being generous to networks with really bad
	 * latency. */
	config->max_future_sec = 10;
}

/* create and destroy functions */

struct twrtp_jibuf_inst *
twrtp_jibuf_create(void *ctx, const struct twrtp_jibuf_config *config)
{
	struct twrtp_jibuf_inst *twjit;

	twjit = talloc_zero(ctx, struct twrtp_jibuf_inst);
	if (!twjit)
		return NULL;

	twjit->ext_config = config;
	twjit->state = TWJIT_STATE_EMPTY;
	INIT_LLIST_HEAD(&twjit->sb[0].queue);
	INIT_LLIST_HEAD(&twjit->sb[1].queue);
	/* default of 8 kHz clock, 20 ms quantum */
	twrtp_jibuf_set_ts_quant(twjit, 8, 20);

	return twjit;
}

void twrtp_jibuf_destroy(struct twrtp_jibuf_inst *twjit)
{
	msgb_queue_free(&twjit->sb[0].queue);
	msgb_queue_free(&twjit->sb[1].queue);
	talloc_free(twjit);
}

/* basic housekeeping */

void twrtp_jibuf_set_ts_quant(struct twrtp_jibuf_inst *twjit,
			      uint16_t clock_khz, uint16_t quantum_ms)
{
	twjit->ts_quantum = (uint32_t) quantum_ms * clock_khz;
	twjit->quanta_per_sec = 1000 / quantum_ms;
	twjit->ts_units_per_ms = clock_khz;
	twjit->ts_units_per_sec = (uint32_t) clock_khz * 1000;
	twjit->ns_to_ts_units = 1000000 / clock_khz;
}

void twrtp_jibuf_reset(struct twrtp_jibuf_inst *twjit)
{
	msgb_queue_free(&twjit->sb[0].queue);
	msgb_queue_free(&twjit->sb[1].queue);
	twjit->state = TWJIT_STATE_EMPTY;
	twjit->sb[0].depth = 0;
	twjit->sb[1].depth = 0;
	twjit->got_first_packet = false;
}