changeset 29:3e01a71b7c7c

implement RTCP Rx
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 08 Jul 2024 02:55:32 +0000
parents defe58aa537c
children 9fd693f234f8
files include/endp.h include/rtcp_defs.h src/Makefile src/rtcp_rx.c
diffstat 4 files changed, 146 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/include/endp.h	Mon Jul 08 01:59:49 2024 +0000
+++ b/include/endp.h	Mon Jul 08 02:55:32 2024 +0000
@@ -11,6 +11,7 @@
 
 #include <osmocom/core/osmo_io.h>
 #include <osmocom/core/socket.h>
+#include <osmocom/core/timer.h>
 
 #include <themwi/rtp/twjit.h>
 
@@ -22,11 +23,24 @@
 	bool restart;
 };
 
+struct twrtp_endp_rtcp_rx {
+	uint32_t sr_ssrc;
+	uint16_t sr_ntp_sec;
+	uint16_t sr_ntp_fract;
+	struct timespec sr_rx_time;
+	uint32_t rr_lost_word;
+	uint32_t rr_jitter;
+	bool got_sr;
+	bool got_rr;
+};
+
 struct twrtp_endp_stats {
 	uint32_t rx_rtp_pkt;
 	uint32_t rx_rtp_badsrc;
 	uint32_t rx_rtcp_pkt;
 	uint32_t rx_rtcp_badsrc;
+	uint32_t rx_rtcp_invalid;
+	uint32_t rx_rtcp_wrong_ssrc;
 	uint32_t tx_rtp_pkt;
 	uint32_t tx_rtp_bytes;
 	uint32_t tx_rtcp_pkt;
@@ -42,7 +56,7 @@
 	struct osmo_sockaddr rtcp_remote;
 	/* Rx and Tx state */
 	struct twrtp_jibuf_inst *twjit;
-	/* RTCP Rx structure to be inserted here */
+	struct twrtp_endp_rtcp_rx rtcp_rx;
 	struct twrtp_endp_tx tx;
 	/* always have to have stats */
 	struct twrtp_endp_stats stats;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/rtcp_defs.h	Mon Jul 08 02:55:32 2024 +0000
@@ -0,0 +1,38 @@
+/*
+ * Some definitions for RTCP, just enough to implement the subset
+ * planned for libtwrtp.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+struct rtcp_sr_rr_hdr {
+	uint8_t		v_p_rc;
+	uint8_t		pt;
+	uint16_t	len;
+	uint32_t	ssrc;
+};
+
+struct rtcp_sr_block {
+	uint32_t	ntp_sec;
+	uint32_t	ntp_fract;
+	uint32_t	rtp_ts;
+	uint32_t	pkt_count;
+	uint32_t	octet_count;
+};
+
+struct rtcp_rr_block {
+	uint32_t	ssrc;
+	uint32_t	lost_word;
+	uint32_t	max_seq_ext;
+	uint32_t	jitter;
+	uint16_t	lsr_sec;
+	uint16_t	lsr_fract;
+	uint16_t	dlsr_sec;
+	uint16_t	dlsr_fract;
+};
+
+#define	RTCP_PT_SR	200
+#define	RTCP_PT_RR	201
+#define	RTCP_PT_SDES	202
--- a/src/Makefile	Mon Jul 08 01:59:49 2024 +0000
+++ b/src/Makefile	Mon Jul 08 02:55:32 2024 +0000
@@ -1,5 +1,6 @@
-OBJS=	bind_fdpair.o endp_bind.o endp_create.o endp_register.o rtp_rx.o \
-	rtp_tx.o set_remote.o twjit.o twjit_in.o twjit_out.o twjit_vty.o
+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 twjit.o twjit_in.o twjit_out.o \
+	twjit_vty.o
 LIB=	libtwrtp.a
 
 include ../config.defs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/rtcp_rx.c	Mon Jul 08 02:55:32 2024 +0000
@@ -0,0 +1,90 @@
+/*
+ * Here we implement RTCP Rx path via osmo_io callback.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <arpa/inet.h>	/* for network byte order functions */
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/osmo_io.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/timer.h>
+
+#include <themwi/rtp/endp.h>
+#include <themwi/rtp/rtcp_defs.h>
+#include "endp_internal.h"
+
+static void parse_rtcp(struct twrtp_endp *endp, struct msgb *msg)
+{
+	struct twrtp_endp_rtcp_rx *rxs = &endp->rtcp_rx;
+	struct rtcp_sr_rr_hdr *base_hdr;
+	struct rtcp_sr_block *sr;
+	struct rtcp_rr_block *rr;
+	unsigned rc, i;
+
+	if (msg->len < sizeof(struct rtcp_sr_rr_hdr)) {
+invalid:	endp->stats.rx_rtcp_invalid++;
+		return;
+	}
+	base_hdr = (struct rtcp_sr_rr_hdr *)
+			msgb_pull(msg, sizeof(struct rtcp_sr_rr_hdr));
+	if ((base_hdr->v_p_rc & 0xC0) != 0x80)
+		goto invalid;
+	switch (base_hdr->pt) {
+	case RTCP_PT_SR:
+		if (msg->len < sizeof(struct rtcp_sr_block))
+			goto invalid;
+		sr = (struct rtcp_sr_block *)
+				msgb_pull(msg, sizeof(struct rtcp_sr_block));
+		rxs->got_sr = true;
+		osmo_clock_gettime(CLOCK_MONOTONIC, &rxs->sr_rx_time);
+		rxs->sr_ssrc = ntohl(base_hdr->ssrc);
+		rxs->sr_ntp_sec = ntohl(sr->ntp_sec);
+		rxs->sr_ntp_fract = ntohl(sr->ntp_fract) >> 16;
+		break;
+	case RTCP_PT_RR:
+		break;
+	default:
+		goto invalid;
+	}
+	rc = base_hdr->v_p_rc & 0x1F;
+	if (msg->len < sizeof(struct rtcp_rr_block) * rc)
+		goto invalid;
+	for (i = 0; i < rc; i++) {
+		rr = (struct rtcp_rr_block *)
+				msgb_pull(msg, sizeof(struct rtcp_rr_block));
+		if (ntohl(rr->ssrc) != endp->tx.ssrc) {
+			endp->stats.rx_rtcp_wrong_ssrc++;
+			continue;
+		}
+		rxs->got_rr = true;
+		rxs->rr_lost_word = ntohl(rr->lost_word);
+		rxs->rr_jitter = ntohl(rr->jitter);
+	}
+}
+
+static void rtcp_rx_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
+			const struct osmo_sockaddr *saddr)
+{
+	struct twrtp_endp *endp = osmo_iofd_get_data(iofd);
+
+	if (!msg)
+		return;
+	if (!endp->remote_set) {
+		msgb_free(msg);
+		return;
+	}
+	if (osmo_sockaddr_cmp(saddr, &endp->rtcp_remote)) {
+		endp->stats.rx_rtcp_badsrc++;
+		msgb_free(msg);
+		return;
+	}
+	endp->stats.rx_rtcp_pkt++;
+	parse_rtcp(endp, msg);
+	msgb_free(msg);
+}
+
+const struct osmo_io_ops _twrtp_endp_iops_rtcp = {
+	.recvfrom_cb = rtcp_rx_cb,
+};