falconia has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-bts/+/42165?usp=email )

Change subject: RTP: implement RTP socket abstraction layer
......................................................................

RTP: implement RTP socket abstraction layer

This abstraction layer is another step toward supporting a choice
between legacy Belledonne ortp and Osmocom-integrated twrtp.

Related: OS#6474
Depends: Ibda74c0dbfb163f5d0e3fb13f593a6e2c6817673 (libosmo-netif.git)
Change-Id: Ic945f6d753ec7f5c0ac5cecc9f71049464de7e8f
---
M TODO-RELEASE
M include/osmo-bts/Makefile.am
A include/osmo-bts/rtp_abstract.h
M src/common/Makefile.am
A src/common/rtp_abstract.c
5 files changed, 538 insertions(+), 0 deletions(-)

Approvals:
  pespin: Looks good to me, approved
  fixeria: Looks good to me, but someone else must approve
  Jenkins Builder: Verified
  laforge: Looks good to me, but someone else must approve




diff --git a/TODO-RELEASE b/TODO-RELEASE
index 0ed7189..57c89e7 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -7,3 +7,4 @@
 # If any interfaces have been added since the last public release: c:r:a + 1.
 # If any interfaces have been removed or changed since the last public 
release: c:r:0.
 #library       what                    description / commit summary line
+libosmo-netif  >1.7.0          soft_underruns added to struct osmo_twjit_stats
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am
index 1922f0d..c7323b6 100644
--- a/include/osmo-bts/Makefile.am
+++ b/include/osmo-bts/Makefile.am
@@ -13,6 +13,7 @@
        oml.h \
        paging.h \
        rsl.h \
+       rtp_abstract.h \
        rtp_input_preen.h \
        signal.h \
        vty.h \
diff --git a/include/osmo-bts/rtp_abstract.h b/include/osmo-bts/rtp_abstract.h
new file mode 100644
index 0000000..995edcf
--- /dev/null
+++ b/include/osmo-bts/rtp_abstract.h
@@ -0,0 +1,95 @@
+/*
+ * This header file defines the RTP abstraction layer inside osmo-bts,
+ * allowing a choice between two different RTP endpoint libraries:
+ * Belledonne ortp or Themyscira twrtp.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <netinet/in.h>
+
+/* The following preprocessor definitions are legacy from
+ * <osmocom/trau/osmo_ortp.h>.  They have to be kept unchanged
+ * in order to allow the rest of OsmoBTS code to use the present
+ * abstraction header in the place of osmo_ortp.h - the latter
+ * may not exist if libosmo-abis is built with --disable-ortp -
+ * and to prevent conflicts when rtp_abstract.c has to include
+ * both osmo_ortp.h and the present header in the default
+ * ortp-enabled build config.
+ */
+
+/*! \brief default duration of a 20ms GSM codec frame */
+#define GSM_RTP_DURATION 160
+
+#define GSM_VOICE_SAMPLE_RATE_HZ 8000
+#define GSM_VOICE_SAMPLES_PER_MS (GSM_VOICE_SAMPLE_RATE_HZ / 1000)
+#define GSM_VOICE_MULTIFRAME 26
+#define GSM_RTP_FRAME_DURATION_MS 20
+#define GSM_SAMPLES_PER_RTP_FRAME (GSM_RTP_FRAME_DURATION_MS * 
GSM_VOICE_SAMPLES_PER_MS)
+#define GSM_TDMA_FRAME_MS (120 / GSM_VOICE_MULTIFRAME)
+#define GSM_MS_TO_SAMPLES(ms) ((ms) * GSM_VOICE_SAMPLES_PER_MS)
+#define GSM_FN_TO_MS(fn) ((fn) * GSM_TDMA_FRAME_MS)
+
+struct osmo_rtp_socket;
+struct osmo_twrtp;
+struct osmo_twjit_config;
+
+/*! \brief Abstracted RTP socket structure */
+struct rtp_abst_socket {
+       /* user fields */
+       void (*rx_cb)(struct rtp_abst_socket *rs, const uint8_t *payload,
+                     unsigned int payload_len, uint16_t seq_number,
+                     uint32_t timestamp, bool marker);
+       void *priv;
+
+       /* internal implementation */
+       struct osmo_rtp_socket *ortp;
+       struct osmo_twrtp *twrtp;
+       struct sockaddr_in local_addr;
+       uint32_t twrtp_rx_ticks;
+       uint32_t twrtp_rx_pl_bytes;
+       uint32_t twrtp_rx_bad_hdr;
+       uint32_t twrtp_rx_wrong_pt;
+       uint32_t twrtp_pl_extr_errors;
+       uint8_t payload_type;
+};
+
+struct rtp_abst_socket *
+rtp_abst_socket_create(void *talloc_ctx, bool use_twrtp,
+                       struct osmo_twjit_config *twjit_cfg);
+void rtp_abst_socket_free(struct rtp_abst_socket *rs);
+
+int rtp_abst_socket_bind(struct rtp_abst_socket *rs, const char *ipstr,
+                        int port);
+int rtp_abst_socket_connect(struct rtp_abst_socket *rs,
+                           const struct in_addr *ip, uint16_t port);
+
+int rtp_abst_socket_set_pt(struct rtp_abst_socket *rs, int payload_type);
+int rtp_abst_socket_set_dscp(struct rtp_abst_socket *rs, int dscp);
+int rtp_abst_socket_set_priority(struct rtp_abst_socket *rs, uint8_t prio);
+
+void rtp_abst_socket_poll(struct rtp_abst_socket *rs);
+
+int rtp_abst_send_frame(struct rtp_abst_socket *rs, const uint8_t *payload,
+                       unsigned int payload_len, bool marker);
+int rtp_abst_skipped_frame(struct rtp_abst_socket *rs);
+
+int rtp_abst_get_bound_ip_port(struct rtp_abst_socket *rs,
+                              uint32_t *ip, int *port);
+
+int rtp_abst_socket_set_param(struct rtp_abst_socket *rs,
+                             bool jitter_adaptive, int jitter_ms);
+
+void rtp_abst_socket_log_stats(struct rtp_abst_socket *rs, const char *cause);
+
+void rtp_abst_socket_stats(struct rtp_abst_socket *rs,
+                               uint32_t *sent_packets, uint32_t *sent_octets,
+                               uint32_t *recv_packets, uint32_t *recv_octets,
+                               uint32_t *recv_lost, uint32_t *last_jitter);
+
+void rtp_abst_set_source_desc(struct rtp_abst_socket *rs, const char *cname,
+                               const char *name, const char *email,
+                               const char *phone, const char *loc,
+                               const char *tool, const char *note);
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 1a62e8e..df3a8dd 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -36,6 +36,7 @@
        bts_sm.c \
        bts_trx.c \
        rsl.c \
+       rtp_abstract.c \
        rtp_input_preen.c \
        vty.c \
        paging.c \
diff --git a/src/common/rtp_abstract.c b/src/common/rtp_abstract.c
new file mode 100644
index 0000000..4854b25
--- /dev/null
+++ b/src/common/rtp_abstract.c
@@ -0,0 +1,440 @@
+/*
+ * Implementation of OsmoBTS-internal RTP abstraction layer, allowing
+ * both compile-time and runtime selection between ortp and twrtp.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define HAVE_ORTP
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/netif/rtp.h>
+#include <osmocom/netif/twrtp.h>
+#include <osmocom/netif/twjit.h>
+#ifdef HAVE_ORTP
+#include <osmocom/trau/osmo_ortp.h>
+#endif
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/rtp_abstract.h>
+
+#ifdef HAVE_ORTP
+/*! \brief call-back function for incoming RTP from libortp */
+static void ortp_rx_cb(struct osmo_rtp_socket *ors, const uint8_t *rtp_pl,
+                       unsigned int rtp_pl_len, uint16_t seq_number,
+                       uint32_t timestamp, bool marker)
+{
+       struct rtp_abst_socket *rs = ors->priv;
+
+       if (rs->rx_cb) {
+               rs->rx_cb(rs, rtp_pl, rtp_pl_len, seq_number, timestamp,
+                         marker);
+       }
+}
+#endif
+
+struct rtp_abst_socket *
+rtp_abst_socket_create(void *talloc_ctx, bool use_twrtp,
+                       struct osmo_twjit_config *twjit_cfg)
+{
+       struct rtp_abst_socket *rs;
+
+       rs = talloc_zero(talloc_ctx, struct rtp_abst_socket);
+       if (rs == NULL)
+               return NULL;
+
+#ifdef HAVE_ORTP
+       if (!use_twrtp) {
+               rs->ortp = osmo_rtp_socket_create(rs, OSMO_RTP_F_POLL);
+               if (rs->ortp == NULL) {
+                       talloc_free(rs);
+                       return NULL;
+               }
+               rs->ortp->priv = rs;
+               rs->ortp->rx_cb = ortp_rx_cb;
+               return rs;
+       }
+#endif
+
+       rs->twrtp = osmo_twrtp_create(rs, 8, 20, true, twjit_cfg);
+       if (rs->twrtp == NULL) {
+               talloc_free(rs);
+               return NULL;
+       }
+       return rs;
+}
+
+void rtp_abst_socket_free(struct rtp_abst_socket *rs)
+{
+#ifdef HAVE_ORTP
+       if (rs->ortp)
+               osmo_rtp_socket_free(rs->ortp);
+#endif
+       if (rs->twrtp)
+               osmo_twrtp_destroy(rs->twrtp);
+       talloc_free(rs);
+}
+
+int rtp_abst_socket_bind(struct rtp_abst_socket *rs, const char *ipstr,
+                        int port)
+{
+       int rc;
+
+#ifdef HAVE_ORTP
+       if (rs->ortp)
+               return osmo_rtp_socket_bind(rs->ortp, ipstr, port);
+#endif
+
+       rs->local_addr.sin_family = AF_INET;
+       rc = inet_aton(ipstr, &rs->local_addr.sin_addr);
+       if (!rc)
+               return -EINVAL;
+       rs->local_addr.sin_port = htons(port);
+       rc = osmo_twrtp_bind_local(rs->twrtp,
+                       (const struct osmo_sockaddr *) &rs->local_addr, true);
+       if (rc < 0)
+               return rc;
+       return 0;
+}
+
+int rtp_abst_socket_connect(struct rtp_abst_socket *rs,
+                           const struct in_addr *ip, uint16_t port)
+{
+       struct sockaddr_in remote;
+
+#ifdef HAVE_ORTP
+       if (rs->ortp)
+               return osmo_rtp_socket_connect(rs->ortp, inet_ntoa(*ip), port);
+#endif
+
+       memset(&remote, 0, sizeof(remote));
+       remote.sin_family = AF_INET;
+       memcpy(&remote.sin_addr, ip, sizeof(struct in_addr));
+       remote.sin_port = htons(port);
+       return osmo_twrtp_set_remote(rs->twrtp,
+                               (const struct osmo_sockaddr *) &remote);
+}
+
+int rtp_abst_socket_set_pt(struct rtp_abst_socket *rs, int payload_type)
+{
+       rs->payload_type = payload_type;
+#ifdef HAVE_ORTP
+       if (rs->ortp)
+               return osmo_rtp_socket_set_pt(rs->ortp, payload_type);
+#endif
+       return 0;
+}
+
+int rtp_abst_socket_set_dscp(struct rtp_abst_socket *rs, int dscp)
+{
+#ifdef HAVE_ORTP
+       if (rs->ortp)
+               return osmo_rtp_socket_set_dscp(rs->ortp, dscp);
+#endif
+       return osmo_twrtp_set_dscp(rs->twrtp, dscp);
+}
+
+int rtp_abst_socket_set_priority(struct rtp_abst_socket *rs, uint8_t prio)
+{
+#ifdef HAVE_ORTP
+       if (rs->ortp)
+               return osmo_rtp_socket_set_priority(rs->ortp, prio);
+#endif
+       return osmo_twrtp_set_socket_prio(rs->twrtp, prio);
+}
+
+void rtp_abst_socket_poll(struct rtp_abst_socket *rs)
+{
+       struct msgb *msg;
+       struct rtp_hdr *rtph;
+       const uint8_t *rtp_pl;
+       uint32_t rtp_pl_len;
+
+#ifdef HAVE_ORTP
+       if (rs->ortp) {
+               osmo_rtp_socket_poll(rs->ortp);
+               rs->ortp->rx_user_ts += GSM_RTP_DURATION;
+               return;
+       }
+#endif
+
+       /* This step does not need to be done on every poll, it is only
+        * needed once.  However, once we enable twjit Rx, we have to
+        * commit to regular polling - hence it would be bad to call
+        * twjit Rx enable on socket creation (or bind or connect step),
+        * then have some delay pass before we start polling.  OTOH,
+        * calling twjit Rx enable on every poll is harmless, despite
+        * being unnecessary - and seems like the safest solution
+        * at the moment. */
+       osmo_twrtp_twjit_rx_ctrl(rs->twrtp, true);
+
+       rs->twrtp_rx_ticks++;
+       msg = osmo_twrtp_twjit_rx_poll(rs->twrtp);
+       if (!msg)
+               return;
+
+       rtph = osmo_rtp_get_hdr(msg);
+       if (!rtph) {
+               rs->twrtp_rx_bad_hdr++;
+               msgb_free(msg);
+               return;
+       }
+
+       if (rtph->payload_type != rs->payload_type) {
+               rs->twrtp_rx_wrong_pt++;
+               msgb_free(msg);
+               return;
+       }
+
+       rtp_pl = osmo_rtp_get_payload(rtph, msg, &rtp_pl_len);
+       if (!rtp_pl) {
+               rs->twrtp_pl_extr_errors++;
+               msgb_free(msg);
+               return;
+       }
+       rs->twrtp_rx_pl_bytes += rtp_pl_len;
+
+       if (rs->rx_cb) {
+               rs->rx_cb(rs, rtp_pl, rtp_pl_len, rtph->sequence,
+                         rtph->timestamp, rtph->marker);
+       }
+       msgb_free(msg);
+}
+
+int rtp_abst_send_frame(struct rtp_abst_socket *rs, const uint8_t *payload,
+                       unsigned int payload_len, bool marker)
+{
+#ifdef HAVE_ORTP
+       if (rs->ortp) {
+               return osmo_rtp_send_frame_ext(rs->ortp, payload, payload_len,
+                                               GSM_RTP_DURATION, marker);
+       }
+#endif
+       return osmo_twrtp_tx_quantum(rs->twrtp, payload, payload_len,
+                                    rs->payload_type, marker, false, false);
+}
+
+int rtp_abst_skipped_frame(struct rtp_abst_socket *rs)
+{
+#ifdef HAVE_ORTP
+       if (rs->ortp)
+               return osmo_rtp_skipped_frame(rs->ortp, GSM_RTP_DURATION);
+#endif
+       osmo_twrtp_tx_skip(rs->twrtp);
+       return 0;
+}
+
+int rtp_abst_get_bound_ip_port(struct rtp_abst_socket *rs,
+                              uint32_t *ip, int *port)
+{
+#ifdef HAVE_ORTP
+       if (rs->ortp)
+               return osmo_rtp_get_bound_ip_port(rs->ortp, ip, port);
+#endif
+       *ip = ntohl(rs->local_addr.sin_addr.s_addr);
+       *port = ntohs(rs->local_addr.sin_port);
+       return 0;
+}
+
+int rtp_abst_socket_set_param(struct rtp_abst_socket *rs,
+                             bool jitter_adaptive, int jitter_ms)
+{
+#ifdef HAVE_ORTP
+       if (rs->ortp) {
+               return osmo_rtp_socket_set_param(rs->ortp,
+                               jitter_adaptive ? OSMO_RTP_P_JIT_ADAP
+                                               : OSMO_RTP_P_JITBUF,
+                               jitter_ms);
+       }
+#endif
+       return 0;       /* not applicable to twrtp */
+}
+
+void rtp_abst_socket_log_stats(struct rtp_abst_socket *rs, const char *cause)
+{
+       struct osmo_twjit *twjit;
+       const struct osmo_twrtp_stats *twrtp_stats;
+       const struct osmo_twjit_stats *twjit_stats;
+
+#ifdef HAVE_ORTP
+       if (rs->ortp) {
+               char prefix[80];
+
+               snprintf(prefix, sizeof(prefix), "Closing RTP socket on %s ",
+                        cause);
+               osmo_rtp_socket_log_stats(rs->ortp, DRTP, LOGL_INFO, prefix);
+               return;
+       }
+#endif
+
+       twjit = osmo_twrtp_get_twjit(rs->twrtp);
+       twrtp_stats = osmo_twrtp_get_stats(rs->twrtp);
+       twjit_stats = osmo_twjit_get_stats(twjit);
+
+       LOGP(DRTP, LOGL_INFO, "RTP session complete with %s\n", cause);
+       /* normal Rx stats */
+       LOGP(DRTP, LOGL_INFO, "Rx active for %u ticks\n", rs->twrtp_rx_ticks);
+       LOGP(DRTP, LOGL_INFO, "twjit rx_packets=%u delivered_pkt=%u\n",
+            twjit_stats->rx_packets, twjit_stats->delivered_pkt);
+       if (twjit_stats->handovers_in || twjit_stats->handovers_out) {
+               LOGP(DRTP, LOGL_INFO,
+                    "twjit handovers_in=%u handovers_out=%u\n",
+                    twjit_stats->handovers_in, twjit_stats->handovers_out);
+       }
+       if (twjit_stats->too_old) {
+               LOGP(DRTP, LOGL_INFO, "twjit too_old=%u\n",
+                    twjit_stats->too_old);
+       }
+       if (twjit_stats->underruns) {
+               LOGP(DRTP, LOGL_INFO, "twjit underruns=%u\n",
+                    twjit_stats->underruns);
+       }
+       if (twjit_stats->ho_underruns) {
+               LOGP(DRTP, LOGL_INFO, "twjit ho_underruns=%u\n",
+                    twjit_stats->ho_underruns);
+       }
+       if (twjit_stats->soft_underruns) {
+               LOGP(DRTP, LOGL_INFO, "twjit soft_underruns=%u\n",
+                    twjit_stats->soft_underruns);
+       }
+       if (twjit_stats->output_gaps) {
+               LOGP(DRTP, LOGL_INFO, "twjit output_gaps=%u\n",
+                    twjit_stats->output_gaps);
+       }
+       if (twjit_stats->thinning_drops) {
+               LOGP(DRTP, LOGL_INFO, "twjit thinning_drops=%u\n",
+                    twjit_stats->thinning_drops);
+       }
+       if (twjit_stats->duplicate_ts) {
+               LOGP(DRTP, LOGL_INFO, "twjit duplicate_ts=%u\n",
+                    twjit_stats->duplicate_ts);
+       }
+       if (twjit_stats->ssrc_changes) {
+               LOGP(DRTP, LOGL_INFO, "twjit ssrc_changes=%u\n",
+                    twjit_stats->ssrc_changes);
+       }
+       if (twjit_stats->seq_skips) {
+               LOGP(DRTP, LOGL_INFO, "twjit seq_skips=%u\n",
+                    twjit_stats->seq_skips);
+       }
+       if (twjit_stats->seq_backwards) {
+               LOGP(DRTP, LOGL_INFO, "twjit seq_backwards=%u\n",
+                    twjit_stats->seq_backwards);
+       }
+       if (twjit_stats->seq_repeats) {
+               LOGP(DRTP, LOGL_INFO, "twjit seq_repeats=%u\n",
+                    twjit_stats->seq_repeats);
+       }
+       if (twjit_stats->intentional_gaps) {
+               LOGP(DRTP, LOGL_INFO, "twjit intentional_gaps=%u\n",
+                    twjit_stats->intentional_gaps);
+       }
+       if (twjit_stats->ts_resets) {
+               LOGP(DRTP, LOGL_INFO, "twjit ts_resets=%u\n",
+                    twjit_stats->ts_resets);
+       }
+       LOGP(DRTP, LOGL_INFO, "Rx max jitter %u.%03u ms\n",
+            twjit_stats->jitter_max >> 3, (twjit_stats->jitter_max & 7) * 125);
+       /* Rx error stats */
+       if (twrtp_stats->rx_rtp_badsrc) {
+               LOGP(DRTP, LOGL_ERROR, "Rx %u RTP packets from wrong src\n",
+                    twrtp_stats->rx_rtp_badsrc);
+       }
+       if (twrtp_stats->rx_rtcp_badsrc) {
+               LOGP(DRTP, LOGL_ERROR, "Rx %u RTCP packets from wrong src\n",
+                    twrtp_stats->rx_rtcp_badsrc);
+       }
+       if (twjit_stats->bad_packets) {
+               LOGP(DRTP, LOGL_ERROR, "Rx %u bad RTP packets (twjit)\n",
+                    twjit_stats->bad_packets);
+       }
+       if (rs->twrtp_rx_bad_hdr) {
+               LOGP(DRTP, LOGL_ERROR, "Rx %u bad RTP packets (after twjit)\n",
+                    rs->twrtp_rx_bad_hdr);
+       }
+       if (rs->twrtp_rx_wrong_pt) {
+               LOGP(DRTP, LOGL_ERROR, "Rx wrong pt number (%u times)\n",
+                    rs->twrtp_rx_wrong_pt);
+       }
+       if (rs->twrtp_pl_extr_errors) {
+               LOGP(DRTP, LOGL_ERROR,
+                    "Rx failed to extract payload (%u times)\n",
+                    rs->twrtp_pl_extr_errors);
+       }
+       if (twrtp_stats->rx_rtcp_invalid) {
+               LOGP(DRTP, LOGL_ERROR, "Rx %u bad RTCP packets\n",
+                    twrtp_stats->rx_rtcp_invalid);
+       }
+       if (twrtp_stats->rx_rtcp_wrong_ssrc) {
+               LOGP(DRTP, LOGL_ERROR, "Rx RTCP RR for wrong SSRC (%u times)\n",
+                    twrtp_stats->rx_rtcp_wrong_ssrc);
+       }
+       /* Tx stats */
+       LOGP(DRTP, LOGL_INFO, "Tx %u RTP packets\n", twrtp_stats->tx_rtp_pkt);
+}
+
+static uint32_t compute_lost_count(struct osmo_twjit *twjit)
+{
+       const struct osmo_twjit_rr_info *rri;
+       int32_t cumulative_lost;
+
+       rri = osmo_twjit_get_rr_info(twjit);
+       cumulative_lost = (int32_t)(rri->expected_pkt - rri->rx_packets);
+       if (cumulative_lost < 0)
+               cumulative_lost = 0;
+       return cumulative_lost;
+}
+
+void rtp_abst_socket_stats(struct rtp_abst_socket *rs,
+                               uint32_t *sent_packets, uint32_t *sent_octets,
+                               uint32_t *recv_packets, uint32_t *recv_octets,
+                               uint32_t *recv_lost, uint32_t *last_jitter)
+{
+       struct osmo_twjit *twjit;
+       const struct osmo_twrtp_stats *twrtp_stats;
+       const struct osmo_twjit_stats *twjit_stats;
+
+#ifdef HAVE_ORTP
+       if (rs->ortp) {
+               osmo_rtp_socket_stats(rs->ortp, sent_packets, sent_octets,
+                                       recv_packets, recv_octets,
+                                       recv_lost, last_jitter);
+               return;
+       }
+#endif
+
+       twjit = osmo_twrtp_get_twjit(rs->twrtp);
+       twrtp_stats = osmo_twrtp_get_stats(rs->twrtp);
+       twjit_stats = osmo_twjit_get_stats(twjit);
+
+       *sent_packets = twrtp_stats->tx_rtp_pkt;
+       *sent_octets = twrtp_stats->tx_rtp_bytes;
+       *recv_packets = twjit_stats->rx_packets;
+       *recv_octets = rs->twrtp_rx_pl_bytes;
+       *recv_lost = compute_lost_count(twjit);
+       *last_jitter = twjit_stats->jitter_max;
+}
+
+void rtp_abst_set_source_desc(struct rtp_abst_socket *rs, const char *cname,
+                               const char *name, const char *email,
+                               const char *phone, const char *loc,
+                               const char *tool, const char *note)
+{
+#ifdef HAVE_ORTP
+       if (rs->ortp) {
+               osmo_rtp_set_source_desc(rs->ortp, cname, name, email, phone,
+                                        loc, tool, note);
+               return;
+       }
+#endif
+       osmo_twrtp_set_sdes(rs->twrtp, cname, name, email, phone,
+                           loc, tool, note);
+}

--
To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/42165?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Change-Id: Ic945f6d753ec7f5c0ac5cecc9f71049464de7e8f
Gerrit-Change-Number: 42165
Gerrit-PatchSet: 4
Gerrit-Owner: falconia <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: falconia <[email protected]>
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>

Reply via email to