falconia has uploaded this change for review. (
https://gerrit.osmocom.org/c/libosmo-netif/+/39281?usp=email )
Change subject: bring twrtp into libosmo-netif
......................................................................
bring twrtp into libosmo-netif
twrtp is the top layer of Themyscira Wireless RTP endpoint
implementation, an alternative to Belledonne libortp.
Unlike Belledonne software, ThemWi RTP library was developed
specifically for use in Osmocom-based GSM, ISDN and IP-PSTN
network elements, and is built on top of libosmocore primitives -
thus it can function more natively in Osmocom universe than ortp.
This ThemWi library was initially developed externally to Osmocom,
but is now being brought into libosmo-netif so it can be used by
native Osmocom projects, particularly OsmoBTS.
Related: OS#6474
Change-Id: Ib63215aaf13ef8ab8f2e0c8d310164cd5c8824eb
---
M include/osmocom/netif/Makefile.am
A include/osmocom/netif/rtcp_defs.h
A include/osmocom/netif/twrtp.h
A include/osmocom/netif/twrtp_private.h
M src/Makefile.am
A src/twrtp_base.c
A src/twrtp_bind.c
A src/twrtp_misc.c
A src/twrtp_remote.c
A src/twrtp_rtcp_rx.c
A src/twrtp_rtcp_tx.c
A src/twrtp_rtp_rx.c
A src/twrtp_rtp_tx.c
A src/twrtp_twjit.c
14 files changed, 1,288 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-netif refs/changes/81/39281/1
diff --git a/include/osmocom/netif/Makefile.am b/include/osmocom/netif/Makefile.am
index d06adda..a3cfcdd 100644
--- a/include/osmocom/netif/Makefile.am
+++ b/include/osmocom/netif/Makefile.am
@@ -1,6 +1,8 @@
noinst_HEADERS = \
+ rtcp_defs.h \
stream_private.h \
twjit_private.h \
+ twrtp_private.h \
$(NULL)
osmonetif_HEADERS = amr.h \
@@ -14,6 +16,7 @@
rtp.h \
stream.h \
twjit.h \
+ twrtp.h \
$(NULL)
if ENABLE_LIBSCTP
diff --git a/include/osmocom/netif/rtcp_defs.h b/include/osmocom/netif/rtcp_defs.h
new file mode 100644
index 0000000..744be35
--- /dev/null
+++ b/include/osmocom/netif/rtcp_defs.h
@@ -0,0 +1,49 @@
+/*
+ * Some definitions for RTCP, just enough to implement SR and RR
+ * generation and parsing in twrtp.
+ */
+
+#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
+#define RTCP_PT_BYE 203
+#define RTCP_PT_APP 204
+
+#define SDES_ITEM_CNAME 1
+#define SDES_ITEM_NAME 2
+#define SDES_ITEM_EMAIL 3
+#define SDES_ITEM_PHONE 4
+#define SDES_ITEM_LOC 5
+#define SDES_ITEM_TOOL 6
+#define SDES_ITEM_NOTE 7
+#define SDES_ITEM_PRIV 8
diff --git a/include/osmocom/netif/twrtp.h b/include/osmocom/netif/twrtp.h
new file mode 100644
index 0000000..c6fa9af
--- /dev/null
+++ b/include/osmocom/netif/twrtp.h
@@ -0,0 +1,139 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation:
+ * public API definition for Osmocom-integrated version.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <osmocom/core/socket.h>
+
+/*
+ * Each instance of twrtp in the present version exists as struct osmo_twrtp.
+ * This structure is opaque, and always constitutes a talloc context.
+ */
+struct osmo_twrtp;
+
+/*
+ * Stats collected during the lifetime of a twrtp instance.
+ */
+struct osmo_twrtp_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;
+};
+
+/* declare structs that are used in our API */
+
+struct msgb;
+struct osmo_twjit_config;
+struct osmo_twjit_stats;
+struct osmo_twjit_rr_info;
+
+/* public API functions: create & destroy, local and remote addresses */
+
+struct osmo_twrtp *
+osmo_twrtp_create(void *ctx, uint16_t clock_khz, uint16_t quantum_ms,
+ bool random_ts_seq,
+ const struct osmo_twjit_config *twjit_config);
+void osmo_twrtp_destroy(struct osmo_twrtp *endp);
+
+int osmo_twrtp_supply_fds(struct osmo_twrtp *endp, int rtp_fd, int rtcp_fd);
+
+int osmo_twrtp_bind_local_ipv4(struct osmo_twrtp *endp,
+ const struct in_addr *ip, uint16_t port);
+int osmo_twrtp_bind_local_ipv6(struct osmo_twrtp *endp,
+ const struct in6_addr *ip6, uint16_t port);
+int osmo_twrtp_bind_local_sin(struct osmo_twrtp *endp,
+ const struct sockaddr_in *sin);
+int osmo_twrtp_bind_local_sin6(struct osmo_twrtp *endp,
+ const struct sockaddr_in6 *sin6);
+
+void osmo_twrtp_set_remote_ipv4(struct osmo_twrtp *endp,
+ const struct in_addr *ip, uint16_t port);
+void osmo_twrtp_set_remote_ipv6(struct osmo_twrtp *endp,
+ const struct in6_addr *ip6, uint16_t port);
+void osmo_twrtp_set_remote_sin(struct osmo_twrtp *endp,
+ const struct sockaddr_in *sin);
+void osmo_twrtp_set_remote_sin6(struct osmo_twrtp *endp,
+ const struct sockaddr_in6 *sin6);
+
+/* receiving incoming RTP via twjit */
+
+void osmo_twrtp_twjit_rx_enable(struct osmo_twrtp *endp);
+void osmo_twrtp_twjit_rx_disable(struct osmo_twrtp *endp);
+
+/* output function, to be called by TDM/GSM/etc fixed-timing side */
+struct msgb *osmo_twrtp_twjit_rx_poll(struct osmo_twrtp *endp);
+
+void osmo_twrtp_new_twjit_config(struct osmo_twrtp *endp,
+ const struct osmo_twjit_config *config);
+
+/* receiving incoming RTP without twjit */
+
+/* callback function takes ownership of msgb! */
+typedef void (*osmo_twrtp_raw_rx_cb)(struct osmo_twrtp *endp, void *user_data,
+ struct msgb *msg);
+
+void osmo_twrtp_set_raw_rx_cb(struct osmo_twrtp *endp, osmo_twrtp_raw_rx_cb cb,
+ void *user_data);
+
+/* RTP Tx direction */
+
+int osmo_twrtp_tx_quantum(struct osmo_twrtp *endp, const uint8_t *payload,
+ unsigned payload_len, uint8_t payload_type,
+ bool marker, bool auto_marker, bool send_rtcp);
+void osmo_twrtp_tx_skip(struct osmo_twrtp *endp);
+void osmo_twrtp_tx_restart(struct osmo_twrtp *endp);
+
+int osmo_twrtp_tx_forward(struct osmo_twrtp *endp, struct msgb *msg);
+
+/* support for emitting RTCP SR & RR */
+
+int osmo_twrtp_set_sdes(struct osmo_twrtp *endp, const char *cname,
+ const char *name, const char *email, const char *phone,
+ const char *loc, const char *tool, const char *note);
+void osmo_twrtp_set_auto_rtcp_interval(struct osmo_twrtp *endp,
+ uint16_t interval);
+
+int osmo_twrtp_send_rtcp_rr(struct osmo_twrtp *endp);
+
+/* stats retrieval: valid with or without twjit */
+
+const struct osmo_twrtp_stats *osmo_twrtp_get_stats(struct osmo_twrtp *endp);
+
+/* have we received at least one RTCP RR matching our RTP Tx output? */
+bool osmo_twrtp_got_rtcp_rr(struct osmo_twrtp *endp);
+
+/* retrieving RTCP RR info: valid only if above function returned true */
+uint32_t osmo_twrtp_rr_lost_word(struct osmo_twrtp *endp);
+int32_t osmo_twrtp_rr_lost_cumulative(struct osmo_twrtp *endp);
+uint32_t osmo_twrtp_rr_jitter_last(struct osmo_twrtp *endp);
+uint32_t osmo_twrtp_rr_jitter_max(struct osmo_twrtp *endp);
+
+/* retrieving additional info from twjit layer */
+
+const struct osmo_twjit_stats *
+osmo_twrtp_get_twjit_stats(struct osmo_twrtp *endp);
+
+const struct osmo_twjit_rr_info *
+osmo_twrtp_get_twjit_rr_info(struct osmo_twrtp *endp);
+
+bool osmo_twrtp_twjit_got_input(struct osmo_twrtp *endp);
+
+/* socket-related miscellany */
+
+int osmo_twrtp_set_dscp(struct osmo_twrtp *endp, uint8_t dscp);
+int osmo_twrtp_set_socket_prio(struct osmo_twrtp *endp, int prio);
diff --git a/include/osmocom/netif/twrtp_private.h
b/include/osmocom/netif/twrtp_private.h
new file mode 100644
index 0000000..d565495
--- /dev/null
+++ b/include/osmocom/netif/twrtp_private.h
@@ -0,0 +1,88 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation:
+ * internal definitions confined to twrtp code inside libosmo-netif.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/core/osmo_io.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/timer.h>
+
+#include <osmocom/netif/twrtp.h>
+
+struct twrtp_endp_tx {
+ uint32_t ssrc;
+ uint32_t ts;
+ uint32_t ts_addend;
+ uint16_t seq;
+ bool started;
+ 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;
+ uint32_t rr_jitter_max;
+ bool got_sr;
+ bool got_rr;
+};
+
+struct twrtp_endp_rtcp_tx {
+ uint32_t last_received;
+ uint32_t last_expected;
+};
+
+struct osmo_twjit;
+
+struct osmo_twrtp {
+ /* the root of the matter: the two sockets */
+ struct osmo_io_fd *iofd_rtp;
+ struct osmo_io_fd *iofd_rtcp;
+ struct osmo_sockaddr rtp_remote;
+ struct osmo_sockaddr rtcp_remote;
+ /* count of RTP timestamp units per quantum */
+ uint32_t ts_quantum;
+ /* scaling factors for RTP Tx timestamp computation */
+ uint32_t ts_units_per_sec;
+ uint32_t ns_to_ts_units;
+ /* RTP Rx path: twjit and raw options */
+ struct osmo_twjit *twjit;
+ osmo_twrtp_raw_rx_cb raw_rx_cb;
+ void *raw_rx_cb_data;
+ /* RTP Tx state */
+ struct twrtp_endp_tx tx;
+ /* RTCP info */
+ struct twrtp_endp_rtcp_rx rtcp_rx;
+ struct twrtp_endp_rtcp_tx rtcp_tx;
+ uint8_t *sdes_buf;
+ uint16_t sdes_len;
+ uint16_t auto_rtcp_interval;
+ uint16_t auto_rtcp_count;
+ /* always have to have stats */
+ struct osmo_twrtp_stats stats;
+ /* bool flags at the end for structure packing optimization */
+ bool register_done;
+ bool remote_set;
+ bool twjit_rx_enable;
+};
+
+/* internal linkage */
+
+extern const struct osmo_io_ops _osmo_twrtp_iops_rtp;
+extern const struct osmo_io_ops _osmo_twrtp_iops_rtcp;
+
+int _osmo_twrtp_send_rtcp(struct osmo_twrtp *endp, bool send_sr,
+ const struct timespec *utc, uint32_t rtp_ts);
diff --git a/src/Makefile.am b/src/Makefile.am
index 171b879..1b563ee 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,6 +32,15 @@
twjit_in.c \
twjit_out.c \
twjit_vty.c \
+ twrtp_base.c \
+ twrtp_bind.c \
+ twrtp_misc.c \
+ twrtp_remote.c \
+ twrtp_rtcp_rx.c \
+ twrtp_rtcp_tx.c \
+ twrtp_rtp_rx.c \
+ twrtp_rtp_tx.c \
+ twrtp_twjit.c \
$(NULL)
if ENABLE_LIBSCTP
diff --git a/src/twrtp_base.c b/src/twrtp_base.c
new file mode 100644
index 0000000..bec9a4e
--- /dev/null
+++ b/src/twrtp_base.c
@@ -0,0 +1,160 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation: basic functions,
+ * everything that isn't factored out into other modules.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/osmo_io.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/netif/twrtp.h>
+#include <osmocom/netif/twrtp_private.h>
+#include <osmocom/netif/twjit.h>
+#include <osmocom/netif/rtp.h>
+#include <osmocom/netif/rtcp_defs.h>
+
+/* We need to know maximum expected sizes of RTP and RTCP Rx packets
+ * for osmo_io msgb allocation. For RTP, the largest packet size in
+ * 3GPP and IP-PSTN applications is 176 bytes: 12 bytes of RTP header
+ * plus 160 bytes of payload for 20 ms of uncompressed G.711 audio
+ * or CSData. Of course there may be other applications that use
+ * larger RTP packets, in which case we may have to add an API function
+ * that overrides our default msgb alloc size setting - but let's
+ * cross that bridge if and when we actually have such users.
+ *
+ * In case of RTCP, we fully process all received packets inside
+ * the present library, hence we can set osmo_io msgb alloc size
+ * based on what our RTCP Rx code can parse and make use of. Any
+ * additional RTCP Rx data, such as very long SDES strings, will
+ * simply be truncated at osmo_io level - but the subsequent parsing
+ * code will never get to those bits anyway.
+ */
+
+#define MAX_RTP_RX_PACKET (sizeof(struct rtp_hdr) + 160)
+#define MAX_RTCP_RX_PACKET (sizeof(struct rtcp_sr_rr_hdr) + \
+ sizeof(struct rtcp_sr_block) + \
+ sizeof(struct rtcp_rr_block) * 31)
+
+struct osmo_twrtp *
+osmo_twrtp_create(void *ctx, uint16_t clock_khz, uint16_t quantum_ms,
+ bool random_ts_seq,
+ const struct osmo_twjit_config *twjit_config)
+{
+ struct osmo_twrtp *endp;
+
+ endp = talloc_zero(ctx, struct osmo_twrtp);
+ if (!endp)
+ return NULL;
+
+ endp->iofd_rtp = osmo_iofd_setup(endp, -1, NULL,
+ OSMO_IO_FD_MODE_RECVFROM_SENDTO,
+ &_osmo_twrtp_iops_rtp, endp);
+ if (!endp->iofd_rtp) {
+ talloc_free(endp);
+ return NULL;
+ }
+ osmo_iofd_set_alloc_info(endp->iofd_rtp, MAX_RTP_RX_PACKET, 0);
+
+ endp->iofd_rtcp = osmo_iofd_setup(endp, -1, NULL,
+ OSMO_IO_FD_MODE_RECVFROM_SENDTO,
+ &_osmo_twrtp_iops_rtcp, endp);
+ if (!endp->iofd_rtcp) {
+ osmo_iofd_free(endp->iofd_rtp);
+ talloc_free(endp);
+ return NULL;
+ }
+ osmo_iofd_set_alloc_info(endp->iofd_rtcp, MAX_RTCP_RX_PACKET, 0);
+
+ if (twjit_config) {
+ endp->twjit = osmo_twjit_create(endp, clock_khz, quantum_ms,
+ twjit_config);
+ if (!endp->twjit) {
+ osmo_iofd_free(endp->iofd_rtp);
+ osmo_iofd_free(endp->iofd_rtcp);
+ talloc_free(endp);
+ return NULL;
+ }
+ }
+
+ endp->ts_quantum = (uint32_t) quantum_ms * clock_khz;
+ endp->ts_units_per_sec = (uint32_t) clock_khz * 1000;
+ endp->ns_to_ts_units = 1000000 / clock_khz;
+
+ endp->tx.ssrc = random();
+ if (random_ts_seq) {
+ endp->tx.ts_addend = random();
+ endp->tx.seq = random();
+ }
+
+ return endp;
+}
+
+void osmo_twrtp_destroy(struct osmo_twrtp *endp)
+{
+ osmo_iofd_free(endp->iofd_rtp);
+ osmo_iofd_free(endp->iofd_rtcp);
+ if (endp->twjit)
+ osmo_twjit_destroy(endp->twjit);
+ talloc_free(endp);
+}
+
+/* This function equips a newly created twrtp endpoint with file descriptors
+ * for RTP and RTCP sockets. Most applications will use higher-level
+ * osmo_twrtp_bind_local_ipv4() and osmo_twrtp_bind_local_ipv6() functions
+ * that create and bind the right type of sockets, then call the present
+ * function - however, some applications may call this function directly.
+ * In Themyscira Wireless CN environment, there is a separate daemon process
+ * that manages the pool of local UDP ports for RTP+RTCP pairs, and that
+ * daemon passes allocated sockets to its clients via UNIX domain socket
+ * file descriptor passing mechanism - hence twrtp layer must have a public
+ * API that takes in already-bound file descriptor pairs.
+ *
+ * This function always "consumes" the two file descriptors that are passed
+ * to it. If the operation succeeds, each of these fds becomes wrapped in
+ * an osmo_io_fd subordinate to struct osmo_twrtp, and both will eventually
+ * be closed upon osmo_twrtp_destroy(). OTOH, if the present function fails,
+ * it closes both fds before returning its error indication. The latter
+ * behavior may seem wrong, but it is more convenient for all current users,
+ * and consistent with the original twrtp-proto version. If we get a user
+ * application that prefers the other alternative (keeping the fds intact
+ * on EBUSY or if osmo_iofd_register() operations fail), we can create
+ * another variant of this API with that alternative behavior.
+ */
+int osmo_twrtp_supply_fds(struct osmo_twrtp *endp, int rtp_fd, int rtcp_fd)
+{
+ int rc;
+
+ if (endp->register_done) {
+ close(rtp_fd);
+ close(rtcp_fd);
+ return -EBUSY;
+ }
+
+ rc = osmo_iofd_register(endp->iofd_rtp, rtp_fd);
+ if (rc < 0) {
+ close(rtp_fd);
+ close(rtcp_fd);
+ return rc;
+ }
+
+ rc = osmo_iofd_register(endp->iofd_rtcp, rtcp_fd);
+ if (rc < 0) {
+ osmo_iofd_close(endp->iofd_rtp);
+ close(rtcp_fd);
+ return rc;
+ }
+
+ endp->register_done = true;
+ return 0;
+}
diff --git a/src/twrtp_bind.c b/src/twrtp_bind.c
new file mode 100644
index 0000000..66b7e15
--- /dev/null
+++ b/src/twrtp_bind.c
@@ -0,0 +1,120 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation: creating and binding
+ * local UDP sockets for RTP and RTCP.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <osmocom/netif/twrtp.h>
+
+int osmo_twrtp_bind_local_ipv4(struct osmo_twrtp *endp,
+ const struct in_addr *ip, uint16_t port)
+{
+ int rtp_fd, rtcp_fd;
+ struct sockaddr_in sin;
+ int rc;
+
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr, ip, sizeof(struct in_addr));
+
+ /* do RTP socket first */
+ rc = socket(AF_INET, SOCK_DGRAM, 0);
+ if (rc < 0)
+ return -errno;
+ rtp_fd = rc;
+ sin.sin_port = htons(port);
+ rc = bind(rtp_fd, (struct sockaddr *) &sin, sizeof(sin));
+ if (rc < 0) {
+ rc = -errno;
+ close(rtp_fd);
+ return rc;
+ }
+
+ /* now do RTCP */
+ rc = socket(AF_INET, SOCK_DGRAM, 0);
+ if (rc < 0) {
+ rc = -errno;
+ close(rtp_fd);
+ return rc;
+ }
+ rtcp_fd = rc;
+ sin.sin_port = htons(port + 1);
+ rc = bind(rtcp_fd, (struct sockaddr *) &sin, sizeof(sin));
+ if (rc < 0) {
+ rc = -errno;
+ close(rtp_fd);
+ close(rtcp_fd);
+ return rc;
+ }
+
+ return osmo_twrtp_supply_fds(endp, rtp_fd, rtcp_fd);
+}
+
+int osmo_twrtp_bind_local_ipv6(struct osmo_twrtp *endp,
+ const struct in6_addr *ip6, uint16_t port)
+{
+ int rtp_fd, rtcp_fd;
+ struct sockaddr_in6 sin6;
+ int rc;
+
+ sin6.sin6_family = AF_INET6;
+ memcpy(&sin6.sin6_addr, ip6, sizeof(struct in6_addr));
+
+ /* do RTP socket first */
+ rc = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (rc < 0)
+ return -errno;
+ rtp_fd = rc;
+ sin6.sin6_port = htons(port);
+ rc = bind(rtp_fd, (struct sockaddr *) &sin6, sizeof(sin6));
+ if (rc < 0) {
+ rc = -errno;
+ close(rtp_fd);
+ return rc;
+ }
+
+ /* now do RTCP */
+ rc = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (rc < 0) {
+ rc = -errno;
+ close(rtp_fd);
+ return rc;
+ }
+ rtcp_fd = rc;
+ sin6.sin6_port = htons(port + 1);
+ rc = bind(rtcp_fd, (struct sockaddr *) &sin6, sizeof(sin6));
+ if (rc < 0) {
+ rc = -errno;
+ close(rtp_fd);
+ close(rtcp_fd);
+ return rc;
+ }
+
+ return osmo_twrtp_supply_fds(endp, rtp_fd, rtcp_fd);
+}
+
+int osmo_twrtp_bind_local_sin(struct osmo_twrtp *endp,
+ const struct sockaddr_in *sin)
+{
+ return osmo_twrtp_bind_local_ipv4(endp, &sin->sin_addr,
+ ntohs(sin->sin_port));
+}
+
+int osmo_twrtp_bind_local_sin6(struct osmo_twrtp *endp,
+ const struct sockaddr_in6 *sin6)
+{
+ return osmo_twrtp_bind_local_ipv6(endp, &sin6->sin6_addr,
+ ntohs(sin6->sin6_port));
+}
diff --git a/src/twrtp_misc.c b/src/twrtp_misc.c
new file mode 100644
index 0000000..0526c4a
--- /dev/null
+++ b/src/twrtp_misc.c
@@ -0,0 +1,73 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation: miscellaneous
+ * functions that don't belong anywhere else.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/core/osmo_io.h>
+#include <osmocom/core/socket.h>
+
+#include <osmocom/netif/twrtp.h>
+#include <osmocom/netif/twrtp_private.h>
+
+const struct osmo_twrtp_stats *osmo_twrtp_get_stats(struct osmo_twrtp *endp)
+{
+ return &endp->stats;
+}
+
+bool osmo_twrtp_got_rtcp_rr(struct osmo_twrtp *endp)
+{
+ return endp->rtcp_rx.got_rr;
+}
+
+uint32_t osmo_twrtp_rr_lost_word(struct osmo_twrtp *endp)
+{
+ return endp->rtcp_rx.rr_lost_word;
+}
+
+int32_t osmo_twrtp_rr_lost_cumulative(struct osmo_twrtp *endp)
+{
+ int32_t lost_count;
+
+ lost_count = endp->rtcp_rx.rr_lost_word & 0xFFFFFF;
+ if (lost_count & 0x800000)
+ lost_count |= 0xFF000000;
+ return lost_count;
+}
+
+uint32_t osmo_twrtp_rr_jitter_last(struct osmo_twrtp *endp)
+{
+ return endp->rtcp_rx.rr_jitter;
+}
+
+uint32_t osmo_twrtp_rr_jitter_max(struct osmo_twrtp *endp)
+{
+ return endp->rtcp_rx.rr_jitter_max;
+}
+
+int osmo_twrtp_set_dscp(struct osmo_twrtp *endp, uint8_t dscp)
+{
+ int rc;
+
+ rc = osmo_sock_set_dscp(osmo_iofd_get_fd(endp->iofd_rtp), dscp);
+ if (rc < 0)
+ return rc;
+ return osmo_sock_set_dscp(osmo_iofd_get_fd(endp->iofd_rtcp), dscp);
+}
+
+int osmo_twrtp_set_socket_prio(struct osmo_twrtp *endp, int prio)
+{
+ int rc;
+
+ rc = osmo_sock_set_priority(osmo_iofd_get_fd(endp->iofd_rtp), prio);
+ if (rc < 0)
+ return rc;
+ return osmo_sock_set_priority(osmo_iofd_get_fd(endp->iofd_rtcp), prio);
+}
diff --git a/src/twrtp_remote.c b/src/twrtp_remote.c
new file mode 100644
index 0000000..75e85da
--- /dev/null
+++ b/src/twrtp_remote.c
@@ -0,0 +1,62 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation: different ways
+ * of setting the address of the remote RTP peer.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <osmocom/netif/twrtp.h>
+#include <osmocom/netif/twrtp_private.h>
+
+void osmo_twrtp_set_remote_ipv4(struct osmo_twrtp *endp,
+ const struct in_addr *ip, uint16_t port)
+{
+ endp->rtp_remote.u.sin.sin_family = AF_INET;
+ memcpy(&endp->rtp_remote.u.sin.sin_addr, ip, sizeof(struct in_addr));
+ endp->rtp_remote.u.sin.sin_port = htons(port);
+
+ endp->rtcp_remote.u.sin.sin_family = AF_INET;
+ memcpy(&endp->rtcp_remote.u.sin.sin_addr, ip, sizeof(struct in_addr));
+ endp->rtcp_remote.u.sin.sin_port = htons(port + 1);
+
+ endp->remote_set = true;
+}
+
+void osmo_twrtp_set_remote_ipv6(struct osmo_twrtp *endp,
+ const struct in6_addr *ip6, uint16_t port)
+{
+ endp->rtp_remote.u.sin6.sin6_family = AF_INET6;
+ memcpy(&endp->rtp_remote.u.sin6.sin6_addr, ip6,
+ sizeof(struct in6_addr));
+ endp->rtp_remote.u.sin6.sin6_port = htons(port);
+
+ endp->rtcp_remote.u.sin6.sin6_family = AF_INET6;
+ memcpy(&endp->rtcp_remote.u.sin6.sin6_addr, ip6,
+ sizeof(struct in6_addr));
+ endp->rtcp_remote.u.sin6.sin6_port = htons(port + 1);
+
+ endp->remote_set = true;
+}
+
+void osmo_twrtp_set_remote_sin(struct osmo_twrtp *endp,
+ const struct sockaddr_in *sin)
+{
+ osmo_twrtp_set_remote_ipv4(endp, &sin->sin_addr, ntohs(sin->sin_port));
+}
+
+void osmo_twrtp_set_remote_sin6(struct osmo_twrtp *endp,
+ const struct sockaddr_in6 *sin6)
+{
+ osmo_twrtp_set_remote_ipv6(endp, &sin6->sin6_addr,
+ ntohs(sin6->sin6_port));
+}
diff --git a/src/twrtp_rtcp_rx.c b/src/twrtp_rtcp_rx.c
new file mode 100644
index 0000000..d4b01ad
--- /dev/null
+++ b/src/twrtp_rtcp_rx.c
@@ -0,0 +1,98 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation: RTCP Rx path
+ * via osmo_io callback.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#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 <osmocom/netif/twrtp.h>
+#include <osmocom/netif/twrtp_private.h>
+#include <osmocom/netif/rtcp_defs.h>
+
+static void parse_rtcp(struct osmo_twrtp *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 *) msg->data;
+ 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 *) msg->data;
+ 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 *) msg->data;
+ 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);
+ if (rxs->rr_jitter > rxs->rr_jitter_max)
+ rxs->rr_jitter_max = rxs->rr_jitter;
+ }
+}
+
+static void rtcp_rx_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
+ const struct osmo_sockaddr *saddr)
+{
+ struct osmo_twrtp *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 _osmo_twrtp_iops_rtcp = {
+ .recvfrom_cb = rtcp_rx_cb,
+};
diff --git a/src/twrtp_rtcp_tx.c b/src/twrtp_rtcp_tx.c
new file mode 100644
index 0000000..360314a
--- /dev/null
+++ b/src/twrtp_rtcp_tx.c
@@ -0,0 +1,240 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation: RTCP Tx functionality.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#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/talloc.h>
+#include <osmocom/core/timer.h>
+
+#include <osmocom/netif/twrtp.h>
+#include <osmocom/netif/twrtp_private.h>
+#include <osmocom/netif/twjit.h>
+#include <osmocom/netif/rtcp_defs.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 osmo_twrtp *endp, struct rtcp_rr_block *rr)
+{
+ struct osmo_twjit *twjit = endp->twjit;
+ const struct osmo_twjit_rr_info *rri = osmo_twjit_get_rr_info(twjit);
+ const 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(rri->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 == rri->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 _osmo_twrtp_send_rtcp(struct osmo_twrtp *endp, bool send_sr,
+ const struct timespec *utc, uint32_t rtp_ts)
+{
+ bool send_rr = false;
+ 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 (endp->twjit && osmo_twjit_got_any_input(endp->twjit))
+ send_rr = true;
+ 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;
+}
+
+int osmo_twrtp_send_rtcp_rr(struct osmo_twrtp *endp)
+{
+ return _osmo_twrtp_send_rtcp(endp, false, NULL, 0);
+}
+
+void osmo_twrtp_set_auto_rtcp_interval(struct osmo_twrtp *endp,
+ uint16_t interval)
+{
+ endp->auto_rtcp_interval = interval;
+}
+
+int osmo_twrtp_set_sdes(struct osmo_twrtp *endp, const char *cname,
+ const char *name, const char *email, const char *phone,
+ const char *loc, const char *tool, const char *note)
+{
+ uint16_t len_str, len_padded, len_with_hdr, len;
+ struct rtcp_sr_rr_hdr *hdr;
+ uint8_t *dp;
+
+ if (!cname)
+ return -EINVAL;
+ len_str = strlen(cname) + 2;
+ if (name)
+ len_str += strlen(name) + 2;
+ if (email)
+ len_str += strlen(email) + 2;
+ if (phone)
+ len_str += strlen(phone) + 2;
+ if (loc)
+ len_str += strlen(loc) + 2;
+ if (tool)
+ len_str += strlen(tool) + 2;
+ if (note)
+ len_str += strlen(note) + 2;
+ len_padded = (len_str + 4) & ~3;
+ len_with_hdr = len_padded + sizeof(struct rtcp_sr_rr_hdr);
+
+ if (endp->sdes_buf)
+ talloc_free(endp->sdes_buf);
+ endp->sdes_buf = talloc_size(endp, len_with_hdr);
+ if (!endp->sdes_buf)
+ return -ENOMEM;
+
+ hdr = (struct rtcp_sr_rr_hdr *) endp->sdes_buf;
+ hdr->v_p_rc = 0x81;
+ hdr->pt = RTCP_PT_SDES;
+ hdr->len = htons(len_with_hdr / 4 - 1);
+ hdr->ssrc = htonl(endp->tx.ssrc);
+ dp = endp->sdes_buf + sizeof(struct rtcp_sr_rr_hdr);
+ *dp++ = SDES_ITEM_CNAME;
+ *dp++ = len = strlen(cname);
+ memcpy(dp, cname, len);
+ dp += len;
+ if (name) {
+ *dp++ = SDES_ITEM_NAME;
+ *dp++ = len = strlen(name);
+ memcpy(dp, name, len);
+ dp += len;
+ }
+ if (email) {
+ *dp++ = SDES_ITEM_EMAIL;
+ *dp++ = len = strlen(email);
+ memcpy(dp, email, len);
+ dp += len;
+ }
+ if (phone) {
+ *dp++ = SDES_ITEM_PHONE;
+ *dp++ = len = strlen(phone);
+ memcpy(dp, phone, len);
+ dp += len;
+ }
+ if (loc) {
+ *dp++ = SDES_ITEM_LOC;
+ *dp++ = len = strlen(loc);
+ memcpy(dp, loc, len);
+ dp += len;
+ }
+ if (tool) {
+ *dp++ = SDES_ITEM_TOOL;
+ *dp++ = len = strlen(tool);
+ memcpy(dp, tool, len);
+ dp += len;
+ }
+ if (note) {
+ *dp++ = SDES_ITEM_NOTE;
+ *dp++ = len = strlen(note);
+ memcpy(dp, note, len);
+ dp += len;
+ }
+ memset(dp, 0, len_padded - len_str);
+
+ endp->sdes_len = len_with_hdr;
+ return 0;
+}
diff --git a/src/twrtp_rtp_rx.c b/src/twrtp_rtp_rx.c
new file mode 100644
index 0000000..69db583
--- /dev/null
+++ b/src/twrtp_rtp_rx.c
@@ -0,0 +1,57 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation: RTP Rx path
+ * via osmo_io callback.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/osmo_io.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/netif/twrtp.h>
+#include <osmocom/netif/twrtp_private.h>
+#include <osmocom/netif/twjit.h>
+
+static void rtp_rx_cb(struct osmo_io_fd *iofd, int res, struct msgb *msg,
+ const struct osmo_sockaddr *saddr)
+{
+ struct osmo_twrtp *endp = osmo_iofd_get_data(iofd);
+
+ if (!msg)
+ return;
+ if (!endp->remote_set) {
+ msgb_free(msg);
+ return;
+ }
+ if (osmo_sockaddr_cmp(saddr, &endp->rtp_remote)) {
+ endp->stats.rx_rtp_badsrc++;
+ msgb_free(msg);
+ return;
+ }
+ endp->stats.rx_rtp_pkt++;
+ if (endp->twjit_rx_enable)
+ osmo_twjit_input(endp->twjit, msg);
+ else if (endp->raw_rx_cb)
+ endp->raw_rx_cb(endp, endp->raw_rx_cb_data, msg);
+ else
+ msgb_free(msg);
+}
+
+const struct osmo_io_ops _osmo_twrtp_iops_rtp = {
+ .recvfrom_cb = rtp_rx_cb,
+};
+
+void osmo_twrtp_set_raw_rx_cb(struct osmo_twrtp *endp, osmo_twrtp_raw_rx_cb cb,
+ void *user_data)
+{
+ endp->raw_rx_cb = cb;
+ endp->raw_rx_cb_data = user_data;
+}
diff --git a/src/twrtp_rtp_tx.c b/src/twrtp_rtp_tx.c
new file mode 100644
index 0000000..410781f
--- /dev/null
+++ b/src/twrtp_rtp_tx.c
@@ -0,0 +1,132 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation: RTP Tx functionality.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#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 <osmocom/netif/twrtp.h>
+#include <osmocom/netif/twrtp_private.h>
+#include <osmocom/netif/rtp.h>
+
+static uint32_t gen_timestamp(struct timespec *now, struct osmo_twrtp *endp)
+{
+ uint32_t ts;
+
+ ts = now->tv_sec * endp->ts_units_per_sec +
+ now->tv_nsec / endp->ns_to_ts_units;
+ ts += endp->tx.ts_addend;
+ return ts;
+}
+
+int osmo_twrtp_tx_quantum(struct osmo_twrtp *endp, const uint8_t *payload,
+ unsigned payload_len, uint8_t payload_type,
+ bool marker, bool auto_marker, bool send_rtcp)
+{
+ struct msgb *msg;
+ struct timespec now;
+ uint32_t restart_ts;
+ int32_t ts_delta;
+ struct rtp_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_hdr) + payload_len,
+ "ThemWi-RTP-Tx");
+ if (!msg) {
+ osmo_twrtp_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);
+ endp->tx.started = true;
+ endp->tx.restart = false;
+ if (auto_marker)
+ marker = true;
+ } else if (endp->tx.restart) {
+ restart_ts = gen_timestamp(&now, endp);
+ 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 % endp->ts_quantum == 0)
+ restart_ts++;
+ endp->tx.ts = restart_ts;
+ }
+ endp->tx.restart = false;
+ if (auto_marker)
+ marker = true;
+ }
+
+ rtph = (struct rtp_hdr *) msgb_put(msg, sizeof(struct rtp_hdr));
+ rtph->version = RTP_VERSION;
+ rtph->padding = 0;
+ rtph->extension = 0;
+ rtph->csrc_count = 0;
+ rtph->marker = marker;
+ rtph->payload_type = payload_type;
+ rtph->sequence = htons(endp->tx.seq);
+ rtph->timestamp = htonl(endp->tx.ts);
+ rtph->ssrc = htonl(endp->tx.ssrc);
+ pl_out = msgb_put(msg, payload_len);
+ memcpy(pl_out, payload, payload_len);
+ endp->tx.seq++;
+ endp->tx.ts += endp->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;
+
+ if (endp->auto_rtcp_interval) {
+ endp->auto_rtcp_count++;
+ if (endp->auto_rtcp_count >= endp->auto_rtcp_interval) {
+ endp->auto_rtcp_count = 0;
+ send_rtcp = true;
+ }
+ }
+ if (send_rtcp) {
+ _osmo_twrtp_send_rtcp(endp, true, &now,
+ endp->tx.ts - endp->ts_quantum);
+ }
+
+ return 0;
+}
+
+void osmo_twrtp_tx_skip(struct osmo_twrtp *endp)
+{
+ if (!endp->tx.started || endp->tx.restart)
+ return;
+ endp->tx.ts += endp->ts_quantum;
+}
+
+void osmo_twrtp_tx_restart(struct osmo_twrtp *endp)
+{
+ endp->tx.restart = true;
+}
+
+int osmo_twrtp_tx_forward(struct osmo_twrtp *endp, struct msgb *msg)
+{
+ return osmo_iofd_sendto_msgb(endp->iofd_rtp, msg, 0, &endp->rtp_remote);
+}
diff --git a/src/twrtp_twjit.c b/src/twrtp_twjit.c
new file mode 100644
index 0000000..3ae5b00
--- /dev/null
+++ b/src/twrtp_twjit.c
@@ -0,0 +1,58 @@
+/*
+ * Themyscira Wireless RTP endpoint implementation: interface to twjit
+ * layer below. Use of twjit is optional in the strict sense, but it
+ * is used most of the time.
+ *
+ * This code was contributed to Osmocom Cellular Network Infrastructure
+ * project by Mother Mychaela N. Falconia of Themyscira Wireless.
+ * Mother Mychaela's contributions are NOT subject to copyright:
+ * no rights reserved, all rights relinquished.
+ */
+
+#include <stdbool.h>
+#include <osmocom/core/utils.h>
+
+#include <osmocom/netif/twrtp.h>
+#include <osmocom/netif/twrtp_private.h>
+#include <osmocom/netif/twjit.h>
+
+void osmo_twrtp_twjit_rx_enable(struct osmo_twrtp *endp)
+{
+ OSMO_ASSERT(endp->twjit);
+ endp->twjit_rx_enable = true;
+}
+
+void osmo_twrtp_twjit_rx_disable(struct osmo_twrtp *endp)
+{
+ OSMO_ASSERT(endp->twjit);
+ endp->twjit_rx_enable = false;
+ osmo_twjit_reset(endp->twjit);
+}
+
+struct msgb *osmo_twrtp_twjit_rx_poll(struct osmo_twrtp *endp)
+{
+ return osmo_twjit_output(endp->twjit);
+}
+
+void osmo_twrtp_new_twjit_config(struct osmo_twrtp *endp,
+ const struct osmo_twjit_config *config)
+{
+ osmo_twjit_new_config(endp->twjit, config);
+}
+
+const struct osmo_twjit_stats *
+osmo_twrtp_get_twjit_stats(struct osmo_twrtp *endp)
+{
+ return osmo_twjit_get_stats(endp->twjit);
+}
+
+const struct osmo_twjit_rr_info *
+osmo_twrtp_get_twjit_rr_info(struct osmo_twrtp *endp)
+{
+ return osmo_twjit_get_rr_info(endp->twjit);
+}
+
+bool osmo_twrtp_twjit_got_input(struct osmo_twrtp *endp)
+{
+ return osmo_twjit_got_any_input(endp->twjit);
+}
--
To view, visit
https://gerrit.osmocom.org/c/libosmo-netif/+/39281?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: libosmo-netif
Gerrit-Branch: master
Gerrit-Change-Id: Ib63215aaf13ef8ab8f2e0c8d310164cd5c8824eb
Gerrit-Change-Number: 39281
Gerrit-PatchSet: 1
Gerrit-Owner: falconia <falcon(a)freecalypso.org>