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); +}