view src/rtp_tx.c @ 32:aa97e77e7de6

implement RTCP Tx
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 08 Jul 2024 07:17:38 +0000
parents defe58aa537c
children e70e7b266f89
line wrap: on
line source

/*
 * Here we implement RTP Tx functionality.
 */

#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>	/* for network byte order functions */

#include <osmocom/core/msgb.h>
#include <osmocom/core/osmo_io.h>
#include <osmocom/core/timer.h>

#include <themwi/rtp/endp.h>
#include <themwi/rtp/rtp_basic_hdr.h>
#include <themwi/rtp/twjit.h>

static uint32_t gen_timestamp(struct timespec *now,
			      struct twrtp_jibuf_inst *twjit)
{
	uint32_t ts;

	ts = now->tv_sec * twjit->ts_units_per_sec +
	     now->tv_nsec / twjit->ns_to_ts_units;
	return ts;
}

int twrtp_endp_tx_quantum(struct twrtp_endp *endp, const uint8_t *payload,
			  unsigned payload_len, uint8_t payload_type,
			  bool marker, bool auto_marker, bool send_rtcp)
{
	uint32_t ts_quantum = endp->twjit->ts_quantum;
	struct msgb *msg;
	struct timespec now;
	uint32_t restart_ts;
	int32_t ts_delta;
	struct rtp_basic_hdr *rtph;
	uint8_t *pl_out;
	int rc;

	if (!endp->register_done || !endp->remote_set)
		return -EINVAL;
	msg = msgb_alloc_c(endp, sizeof(struct rtp_basic_hdr) + payload_len,
			   "ThemWi-RTP-Tx");
	if (!msg) {
		twrtp_endp_tx_skip(endp);
		return -ENOMEM;
	}

	/* timestamp generation is where we do some trickery */
	osmo_clock_gettime(CLOCK_REALTIME, &now);
	if (!endp->tx.started) {
		endp->tx.ts = gen_timestamp(&now, endp->twjit);
		endp->tx.started = true;
		endp->tx.restart = false;
		if (auto_marker)
			marker = true;
	} else if (endp->tx.restart) {
		restart_ts = gen_timestamp(&now, endp->twjit);
		ts_delta = (int32_t)(restart_ts - endp->tx.ts);
		if (ts_delta <= 0) {
			/* shouldn't happen, unless something funky w/clock */
			endp->tx.ts++;
		} else {
			if (ts_delta % ts_quantum == 0)
				restart_ts++;
			endp->tx.ts = restart_ts;
		}
		endp->tx.restart = false;
		if (auto_marker)
			marker = true;
	}

	rtph = (struct rtp_basic_hdr *)
			msgb_put(msg, sizeof(struct rtp_basic_hdr));
	rtph->v_p_x_cc = 0x80;
	rtph->m_pt = payload_type;
	if (marker)
		rtph->m_pt |= 0x80;
	rtph->ssrc = htonl(endp->tx.ssrc);
	rtph->seq = htons(endp->tx.seq);
	rtph->tstamp = htonl(endp->tx.ts);
	pl_out = msgb_put(msg, payload_len);
	memcpy(pl_out, payload, payload_len);
	endp->tx.seq++;
	endp->tx.ts += ts_quantum;

	rc = osmo_iofd_sendto_msgb(endp->iofd_rtp, msg, 0, &endp->rtp_remote);
	if (rc < 0) {
		msgb_free(msg);
		return rc;
	}
	endp->stats.tx_rtp_pkt++;
	endp->stats.tx_rtp_bytes += payload_len;

	/* TODO: send RTCP if requested */

	return 0;
}

void twrtp_endp_tx_skip(struct twrtp_endp *endp)
{
	if (!endp->tx.started || endp->tx.restart)
		return;
	endp->tx.ts += endp->twjit->ts_quantum;
}