changeset 32:aa97e77e7de6

implement RTCP Tx
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 08 Jul 2024 07:17:38 +0000
parents 284fcb5868e2
children e70e7b266f89
files include/endp.h src/Makefile src/endp_internal.h src/rtcp_tx.c
diffstat 4 files changed, 155 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/include/endp.h	Mon Jul 08 04:56:50 2024 +0000
+++ b/include/endp.h	Mon Jul 08 07:17:38 2024 +0000
@@ -34,6 +34,12 @@
 	bool got_rr;
 };
 
+struct twrtp_endp_rtcp_tx {
+	uint32_t last_received;
+	uint32_t last_expected;
+	uint16_t auto_rtcp_count;
+};
+
 struct twrtp_endp_stats {
 	uint32_t rx_rtp_pkt;
 	uint32_t rx_rtp_badsrc;
@@ -56,8 +62,9 @@
 	struct osmo_sockaddr rtcp_remote;
 	/* Rx and Tx state */
 	struct twrtp_jibuf_inst *twjit;
+	struct twrtp_endp_tx tx;
 	struct twrtp_endp_rtcp_rx rtcp_rx;
-	struct twrtp_endp_tx tx;
+	struct twrtp_endp_rtcp_tx rtcp_tx;
 	uint8_t *sdes_buf;
 	uint16_t sdes_len;
 	uint16_t auto_rtcp_interval;
--- a/src/Makefile	Mon Jul 08 04:56:50 2024 +0000
+++ b/src/Makefile	Mon Jul 08 07:17:38 2024 +0000
@@ -1,5 +1,5 @@
 OBJS=	bind_fdpair.o endp_bind.o endp_create.o endp_register.o rtcp_rx.o \
-	rtp_rx.o rtp_tx.o set_remote.o set_sdes.o twjit.o twjit_in.o \
+	rtcp_tx.o rtp_rx.o rtp_tx.o set_remote.o set_sdes.o twjit.o twjit_in.o \
 	twjit_out.o twjit_vty.o
 LIB=	libtwrtp.a
 
--- a/src/endp_internal.h	Mon Jul 08 04:56:50 2024 +0000
+++ b/src/endp_internal.h	Mon Jul 08 07:17:38 2024 +0000
@@ -4,7 +4,16 @@
 
 #pragma once
 
+#include <stdint.h>
+#include <stdbool.h>
+
 #include <osmocom/core/osmo_io.h>
+#include <osmocom/core/timer.h>
+
+#include <themwi/rtp/endp.h>
 
 extern const struct osmo_io_ops _twrtp_endp_iops_rtp;
 extern const struct osmo_io_ops _twrtp_endp_iops_rtcp;
+
+int _twrtp_endp_send_rtcp(struct twrtp_endp *endp, bool send_sr,
+			  const struct timespec *utc, uint32_t rtp_ts);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/rtcp_tx.c	Mon Jul 08 07:17:38 2024 +0000
@@ -0,0 +1,137 @@
+/*
+ * Here we implement RTCP 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/rtcp_defs.h>
+#include <themwi/rtp/twjit.h>
+#include "endp_internal.h"
+
+#define	NTP_EPOCH_MJD	15020
+#define	UNIX_EPOCH_MJD	40587
+
+#define	NTP_UNIX_EPOCH_DIFF	((UNIX_EPOCH_MJD-NTP_EPOCH_MJD) * 86400UL)
+#define	TWO_TO_32_DOUBLE	4294967296.0
+
+static void fill_rr_block(struct twrtp_endp *endp, struct rtcp_rr_block *rr)
+{
+	struct twrtp_jibuf_inst *twjit = endp->twjit;
+	struct twrtp_jibuf_rr_info *rri = &twjit->rr_info;
+	struct twrtp_endp_rtcp_rx *rxs = &endp->rtcp_rx;
+	struct twrtp_endp_rtcp_tx *txs = &endp->rtcp_tx;
+	uint32_t delta_expect, delta_rcvd;
+	int32_t cumulative_lost, newly_lost;
+	uint32_t lost_fract, lost_word;
+	struct timespec now, time_delta;
+
+	cumulative_lost = (int32_t)(rri->expected_pkt - rri->rx_packets);
+	if (cumulative_lost > 0x7FFFFF)
+		cumulative_lost = 0x7FFFFF;
+	else if (cumulative_lost < -0x800000)
+		cumulative_lost = -0x800000;
+	delta_expect = rri->expected_pkt - txs->last_expected;
+	txs->last_expected = rri->expected_pkt;
+	delta_rcvd = rri->rx_packets - txs->last_received;
+	txs->last_received = rri->rx_packets;
+	newly_lost = (int32_t)(delta_expect - delta_rcvd);
+	if (delta_expect == 0 || newly_lost <= 0)
+		lost_fract = 0;
+	else
+		lost_fract = (newly_lost << 8) / delta_expect;
+	lost_word = (lost_fract << 8) | (cumulative_lost & 0xFFFFFF);
+
+	rr->ssrc = htonl(twjit->last_ssrc);
+	rr->lost_word = htonl(lost_word);
+	rr->max_seq_ext = htonl(rri->max_seq_ext);
+	rr->jitter = htonl(rri->jitter_accum >> 4);
+
+	if (rxs->got_sr && rxs->sr_ssrc == twjit->last_ssrc) {
+		osmo_clock_gettime(CLOCK_MONOTONIC, &now);
+		time_delta.tv_sec = now.tv_sec - rxs->sr_rx_time.tv_sec;
+		time_delta.tv_nsec = now.tv_nsec - rxs->sr_rx_time.tv_nsec;
+		if (time_delta.tv_nsec < 0) {
+			time_delta.tv_sec--;
+			time_delta.tv_nsec += 1000000000;
+		}
+		rr->lsr_sec = htons(rxs->sr_ntp_sec);
+		rr->lsr_fract = htons(rxs->sr_ntp_fract);
+		rr->dlsr_sec = htons(time_delta.tv_sec);
+		rr->dlsr_fract = htons(time_delta.tv_nsec / 1000000000.0f *
+					65536.0f);
+	} else {
+		rr->lsr_sec = 0;
+		rr->lsr_fract = 0;
+		rr->dlsr_sec = 0;
+		rr->dlsr_fract = 0;
+	}
+}
+
+int _twrtp_endp_send_rtcp(struct twrtp_endp *endp, bool send_sr,
+			  const struct timespec *utc, uint32_t rtp_ts)
+{
+	bool send_rr = endp->twjit->got_first_packet;
+	struct msgb *msg;
+	struct rtcp_sr_rr_hdr *hdr;
+	struct rtcp_sr_block *sr;
+	struct rtcp_rr_block *rr;
+	uint8_t *sdes_out;
+	int rc;
+
+	if (!endp->register_done || !endp->remote_set || !endp->sdes_buf)
+		return -EINVAL;
+	if (!send_sr && !send_rr)
+		return -ENODATA;	/* nothing to send, neither SR nor RR */
+	msg = msgb_alloc_c(endp, sizeof(struct rtcp_sr_rr_hdr) +
+			   sizeof(struct rtcp_sr_block) +
+			   sizeof(struct rtcp_rr_block) + endp->sdes_len,
+			   "ThemWi-RTCP-Tx");
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = (struct rtcp_sr_rr_hdr *)
+			msgb_put(msg, sizeof(struct rtcp_sr_rr_hdr));
+	hdr->v_p_rc = send_rr ? 0x81 : 0x80;
+	if (send_sr) {
+		hdr->pt = RTCP_PT_SR;
+		hdr->len = htons(send_rr ? 12 : 6);
+	} else {
+		hdr->pt = RTCP_PT_RR;
+		hdr->len = htons(7);
+	}
+	hdr->ssrc = htonl(endp->tx.ssrc);
+	if (send_sr) {
+		sr = (struct rtcp_sr_block *)
+				msgb_put(msg, sizeof(struct rtcp_sr_block));
+		sr->ntp_sec = htonl(utc->tv_sec + NTP_UNIX_EPOCH_DIFF);
+		sr->ntp_fract = htonl(utc->tv_nsec / 1000000000.0 *
+					TWO_TO_32_DOUBLE);
+		sr->rtp_ts = htonl(rtp_ts);
+		sr->pkt_count = htonl(endp->stats.tx_rtp_pkt);
+		sr->octet_count = htonl(endp->stats.tx_rtp_bytes);
+	}
+	if (send_rr) {
+		rr = (struct rtcp_rr_block *)
+				msgb_put(msg, sizeof(struct rtcp_rr_block));
+		fill_rr_block(endp, rr);
+	}
+	sdes_out = msgb_put(msg, endp->sdes_len);
+	memcpy(sdes_out, endp->sdes_buf, endp->sdes_len);
+
+	rc = osmo_iofd_sendto_msgb(endp->iofd_rtcp, msg, 0, &endp->rtcp_remote);
+	if (rc < 0) {
+		msgb_free(msg);
+		return rc;
+	}
+	endp->stats.tx_rtcp_pkt++;
+	return 0;
+}