summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac4
-rw-r--r--include/osmocom/Makefile.am2
-rw-r--r--include/osmocom/trau/Makefile.am3
-rw-r--r--include/osmocom/trau/osmo_ortp.h56
-rw-r--r--libosmotrau.pc.in10
-rw-r--r--src/Makefile.am2
-rw-r--r--src/trau/Makefile.am15
-rw-r--r--src/trau/osmo_ortp.c383
8 files changed, 473 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index f14f047..ec5086d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -37,15 +37,19 @@ AM_CONFIG_HEADER(config.h)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.3.0)
+PKG_CHECK_MODULES(ORTP, ortp)
AC_CHECK_HEADERS(dahdi/user.h,,AC_MSG_WARN(DAHDI input driver will not be built))
AC_OUTPUT(
libosmoabis.pc
+ libosmotrau.pc
include/Makefile
include/osmocom/Makefile
include/osmocom/abis/Makefile
+ include/osmocom/trau/Makefile
src/Makefile
src/input/Makefile
+ src/trau/Makefile
tests/Makefile
Makefile)
diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am
index f9d5e7c..a8574ba 100644
--- a/include/osmocom/Makefile.am
+++ b/include/osmocom/Makefile.am
@@ -1 +1 @@
-SUBDIRS=abis
+SUBDIRS=abis trau
diff --git a/include/osmocom/trau/Makefile.am b/include/osmocom/trau/Makefile.am
new file mode 100644
index 0000000..d796c7c
--- /dev/null
+++ b/include/osmocom/trau/Makefile.am
@@ -0,0 +1,3 @@
+osmotrau_HEADERS = osmo_ortp.h
+
+osmotraudir = $(includedir)/osmocom/trau
diff --git a/include/osmocom/trau/osmo_ortp.h b/include/osmocom/trau/osmo_ortp.h
new file mode 100644
index 0000000..278423b
--- /dev/null
+++ b/include/osmocom/trau/osmo_ortp.h
@@ -0,0 +1,56 @@
+#ifndef _OSMO_ORTP_H
+#define _OSMO_ORTP_H
+
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/select.h>
+
+//#include <ortp/ortp.h>
+struct _RtpSession;
+
+
+#define RTP_PT_GSM_FULL 3
+#define RTP_PT_GSM_HALF 96
+#define RTP_PT_GSM_EFR 97
+#define RTP_PT_AMR 98
+
+struct osmo_rtp_socket {
+ /*! \biref list header for global list of sockets */
+ struct llist_head list;
+
+ /*! \brief libortp RTP session pointer */
+ struct _RtpSession *sess;
+ /*! \brief Osmo file descriptor for RTP socket FD */
+ struct osmo_fd rtp_bfd;
+ /*! \brief Osmo file descriptor for RTCP socket FD */
+ struct osmo_fd rtcp_bfd;
+
+ /*! \brief callback for incoming data */
+ void (*rx_cb)(struct osmo_rtp_socket *rs, const uint8_t *payload,
+ unsigned int payload_len);
+
+ /* Rx related */
+ uint32_t rx_user_ts;
+
+ /* Tx related */
+ uint32_t tx_timestamp;
+
+ void *priv;
+};
+
+void osmo_rtp_init(void *ctx);
+struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx);
+int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port);
+int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t port);
+int osmo_rtp_socket_set_pt(struct osmo_rtp_socket *rs, int payload_type);
+int osmo_rtp_socket_free(struct osmo_rtp_socket *rs);
+int osmo_rtp_send_frame(struct osmo_rtp_socket *rs, const uint8_t *payload,
+ unsigned int payload_len, unsigned int duration);
+
+int osmo_rtp_get_bound_ip_port(struct osmo_rtp_socket *rs,
+ uint32_t *ip, int *port);
+int osmo_rtp_get_bound_addr(struct osmo_rtp_socket *rs,
+ const char **addr, int *port);
+
+#endif /* _OSMO_ORTP_H */
diff --git a/libosmotrau.pc.in b/libosmotrau.pc.in
new file mode 100644
index 0000000..d15c5fa
--- /dev/null
+++ b/libosmotrau.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Osmocom TRAU (E1/RTP) Library
+Description: C Utility Library
+Version: @VERSION@
+Libs: -L${libdir} -losmotrau
+Cflags: -I${includedir}/
diff --git a/src/Makefile.am b/src/Makefile.am
index eb4467c..aee2af3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS=input
+SUBDIRS=input trau
# This is _NOT_ the library release version, it's an API version.
# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
diff --git a/src/trau/Makefile.am b/src/trau/Makefile.am
new file mode 100644
index 0000000..47b5875
--- /dev/null
+++ b/src/trau/Makefile.am
@@ -0,0 +1,15 @@
+# This is _NOT_ the library release version, it's an API version.
+# Please read Chapter 6 "Library interface versions" of the libtool
+# documentation before making any modification
+LIBVERSION=0:0:0
+
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS= -fPIC -Wall \
+ $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
+ $(ORTP_CFLAGS) $(COVERAGE_CFLAGS)
+AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
+ $(ORTP_LIBS) $(COVERAGE_LDFLAGS)
+
+lib_LTLIBRARIES = libosmotrau.la
+
+libosmotrau_la_SOURCES = osmo_ortp.c
diff --git a/src/trau/osmo_ortp.c b/src/trau/osmo_ortp.c
new file mode 100644
index 0000000..461322e
--- /dev/null
+++ b/src/trau/osmo_ortp.c
@@ -0,0 +1,383 @@
+/* (C) 2011 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2011 by On-Waves e.h.f
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/*! \file osmo_ortp.c
+ * \brief Integration of libortp into osmocom framework (select, logging)
+ */
+
+#include <stdint.h>
+#include <netdb.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/select.h>
+#include <osmocom/trau/osmo_ortp.h>
+
+#include <ortp/ortp.h>
+
+
+static PayloadType *payload_type_efr;
+static PayloadType *payload_type_hr;
+static RtpProfile *osmo_pt_profile;
+
+static void *tall_rtp_ctx;
+
+/* malloc integration */
+
+static void *osmo_ortp_malloc(size_t sz)
+{
+ return talloc_size(tall_rtp_ctx, sz);
+}
+
+static void *osmo_ortp_realloc(void *ptr, size_t sz)
+{
+ return talloc_realloc_size(tall_rtp_ctx, ptr, sz);
+}
+
+static void osmo_ortp_free(void *ptr)
+{
+ talloc_free(ptr);
+}
+
+static OrtpMemoryFunctions osmo_ortp_memfn = {
+ .malloc_fun = osmo_ortp_malloc,
+ .realloc_fun = osmo_ortp_realloc,
+ .free_fun = osmo_ortp_free
+};
+
+/* logging */
+
+struct level_map {
+ OrtpLogLevel ortp;
+ int osmo_level;
+};
+static const struct level_map level_map[] = {
+ { ORTP_DEBUG, LOGL_DEBUG },
+ { ORTP_MESSAGE, LOGL_INFO },
+ { ORTP_WARNING, LOGL_NOTICE },
+ { ORTP_ERROR, LOGL_ERROR },
+ { ORTP_FATAL, LOGL_FATAL },
+};
+static int ortp_to_osmo_lvl(OrtpLogLevel lev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(level_map); i++) {
+ if (level_map[i].ortp == lev)
+ return level_map[i].osmo_level;
+ }
+ /* default */
+ return LOGL_ERROR;
+}
+
+static void my_ortp_logfn(OrtpLogLevel lev, const char *fmt,
+ va_list args)
+{
+ osmo_vlogp(DLMIB, ortp_to_osmo_lvl(lev), __FILE__, 0,
+ 0, fmt, args);
+}
+
+/* ORTP signal callbacks */
+
+static void ortp_sig_cb_ssrc(RtpSession *rs, void *data)
+{
+ fprintf(stderr, "ssrc_changed\n");
+}
+
+static void ortp_sig_cb_pt(RtpSession *rs, void *data)
+{
+ fprintf(stderr, "payload_type_changed\n");
+}
+
+static void ortp_sig_cb_net(RtpSession *rs, void *data)
+{
+ fprintf(stderr, "network_error\n");
+}
+
+static void ortp_sig_cb_ts(RtpSession *rs, void *data)
+{
+ fprintf(stderr, "timestamp_jump\n");
+}
+
+
+/* Osmo FD callbacks */
+
+static int osmo_rtp_fd_cb(struct osmo_fd *fd, unsigned int what)
+{
+ struct osmo_rtp_socket *rs = fd->data;
+ mblk_t *mblk;
+
+ if (what & BSC_FD_READ) {
+ mblk = rtp_session_recvm_with_ts(rs->sess, rs->rx_user_ts);
+ if (mblk) {
+ rtp_get_payload(mblk, &mblk->b_rptr);
+ /* hand into receiver */
+ if (rs->rx_cb)
+ rs->rx_cb(rs, mblk->b_rptr,
+ mblk->b_wptr - mblk->b_rptr);
+ freemsg(mblk);
+ }
+ rs->rx_user_ts += 160;
+ }
+ /* writing is not queued at the moment, so BSC_FD_WRITE
+ * shouldn't occur */
+ return 0;
+}
+
+static int osmo_rtcp_fd_cb(struct osmo_fd *fd, unsigned int what)
+{
+ struct osmo_rtp_socket *rs = fd->data;
+
+ /* We probably don't need this at all, as
+ * rtp_session_recvm_with_ts() will alway also poll the RTCP
+ * file descriptor for new data */
+ return rtp_session_rtcp_recv(rs->sess);
+}
+
+static int osmo_rtp_socket_fdreg(struct osmo_rtp_socket *rs)
+{
+ rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
+ rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
+ rs->rtp_bfd.when = rs->rtcp_bfd.when = BSC_FD_READ;
+ rs->rtp_bfd.data = rs->rtcp_bfd.data = rs;
+ rs->rtp_bfd.cb = osmo_rtp_fd_cb;
+ rs->rtcp_bfd.cb = osmo_rtcp_fd_cb;
+
+ osmo_fd_register(&rs->rtp_bfd);
+ osmo_fd_register(&rs->rtcp_bfd);
+
+ return 0;
+}
+
+static void create_payload_types()
+{
+ PayloadType *pt;
+
+ /* EFR */
+ pt = payload_type_new();
+ pt->type = PAYLOAD_AUDIO_PACKETIZED;
+ pt->clock_rate = 8000;
+ pt->mime_type = "EFR";
+ pt->normal_bitrate = 12200;
+ pt->channels = 1;
+ payload_type_efr = pt;
+
+ /* HR */
+ pt = payload_type_new();
+ pt->type = PAYLOAD_AUDIO_PACKETIZED;
+ pt->clock_rate = 8000;
+ pt->mime_type = "HR";
+ pt->normal_bitrate = 6750; /* FIXME */
+ pt->channels = 1;
+ payload_type_hr = pt;
+
+ /* create a new RTP profile as clone of AV profile */
+ osmo_pt_profile = rtp_profile_clone(&av_profile);
+
+ /* add the GSM specific payload types. They are all dynamically
+ * assigned, but in the Osmocom GSM system we have allocated
+ * them as follows: */
+ rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_EFR, payload_type_efr);
+ rtp_profile_set_payload(osmo_pt_profile, RTP_PT_GSM_HALF, payload_type_hr);
+ rtp_profile_set_payload(osmo_pt_profile, RTP_PT_AMR, &payload_type_amr);
+}
+
+/* public functions */
+
+/*! \brief initialize Osmocom RTP code
+ * \param[in] ctx talloc context
+ */
+void osmo_rtp_init(void *ctx)
+{
+ tall_rtp_ctx = ctx;
+ ortp_set_memory_functions(&osmo_ortp_memfn);
+ ortp_init();
+ ortp_set_log_level_mask(0xffff);
+ ortp_set_log_handler(my_ortp_logfn);
+ create_payload_types();
+}
+
+/*! \brief create a new RTP socket */
+struct osmo_rtp_socket *osmo_rtp_socket_create(void *talloc_ctx)
+{
+ struct osmo_rtp_socket *rs;
+
+ if (!talloc_ctx)
+ talloc_ctx = tall_rtp_ctx;
+
+ rs = talloc_zero(talloc_ctx, struct osmo_rtp_socket);
+ if (!rs)
+ return NULL;
+
+ rs->sess = rtp_session_new(RTP_SESSION_SENDRECV);
+ if (!rs->sess) {
+ talloc_free(rs);
+ return NULL;
+ }
+ rtp_session_set_data(rs->sess, rs);
+ rtp_session_set_profile(rs->sess, osmo_pt_profile);
+
+ rtp_session_signal_connect(rs->sess, "ssrc_changed",
+ (RtpCallback) ortp_sig_cb_ssrc,
+ (unsigned long) rs);
+ rtp_session_signal_connect(rs->sess, "payload_type_changed",
+ (RtpCallback) ortp_sig_cb_pt,
+ (unsigned long) rs);
+ rtp_session_signal_connect(rs->sess, "network_error",
+ (RtpCallback) ortp_sig_cb_net,
+ (unsigned long) rs);
+ rtp_session_signal_connect(rs->sess, "timestamp_jump",
+ (RtpCallback) ortp_sig_cb_ts,
+ (unsigned long) rs);
+
+ return rs;
+}
+
+/*! \brief bind a RTP socket to a local port */
+int osmo_rtp_socket_bind(struct osmo_rtp_socket *rs, const char *ip, int port)
+{
+ int rc;
+
+ rc = rtp_session_set_local_addr(rs->sess, ip, port);
+ if (rc < 0)
+ return rc;
+
+ rs->rtp_bfd.fd = rtp_session_get_rtp_socket(rs->sess);
+ rs->rtcp_bfd.fd = rtp_session_get_rtcp_socket(rs->sess);
+
+ return 0;
+}
+
+/*! \brief connect a RTP socket to a remote port */
+int osmo_rtp_socket_connect(struct osmo_rtp_socket *rs, const char *ip, uint16_t port)
+{
+ int rc;
+
+ rc = rtp_session_set_remote_addr(rs->sess, ip, port);
+ if (rc < 0)
+ return rc;
+
+ return osmo_rtp_socket_fdreg(rs);
+}
+
+/*! \brief Send one RTP frame via a RTP socket */
+int osmo_rtp_send_frame(struct osmo_rtp_socket *rs, const uint8_t *payload,
+ unsigned int payload_len, unsigned int duration)
+{
+ mblk_t *mblk;
+ int rc;
+
+ mblk = rtp_session_create_packet(rs->sess, RTP_FIXED_HEADER_SIZE,
+ payload, payload_len);
+ if (!mblk)
+ return -ENOMEM;
+
+ rc = rtp_session_sendm_with_ts(rs->sess, mblk,
+ rs->tx_timestamp);
+ rs->tx_timestamp += duration;
+ if (rc < 0) {
+ /* no need to free() the mblk, as rtp_session_rtp_send()
+ * unconditionally free()s the mblk even in case of
+ * error */
+ return rc;
+ }
+
+ return rc;
+}
+
+/*! \brief Set the payload type of a RTP socket */
+int osmo_rtp_socket_set_pt(struct osmo_rtp_socket *rs, int payload_type)
+{
+ int rc;
+
+ rc = rtp_session_set_payload_type(rs->sess, payload_type);
+ //rtp_session_set_rtcp_report_interval(rs->sess, 5*1000);
+
+ return rc;
+}
+
+/*! \brief completely close the RTP socket and release all resources */
+int osmo_rtp_socket_free(struct osmo_rtp_socket *rs)
+{
+ if (rs->rtp_bfd.list.next && rs->rtp_bfd.list.next != LLIST_POISON1)
+ osmo_fd_unregister(&rs->rtp_bfd);
+
+ if (rs->rtcp_bfd.list.next && rs->rtcp_bfd.list.next != LLIST_POISON1)
+ osmo_fd_unregister(&rs->rtcp_bfd);
+
+ if (rs->sess) {
+ rtp_session_release_sockets(rs->sess);
+ rtp_session_destroy(rs->sess);
+ rs->sess = NULL;
+ }
+
+ talloc_free(rs);
+
+ return 0;
+}
+
+
+int osmo_rtp_get_bound_ip_port(struct osmo_rtp_socket *rs,
+ uint32_t *ip, int *port)
+{
+ int rc;
+ struct sockaddr_storage ss;
+ struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
+ socklen_t alen = sizeof(ss);
+
+ rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
+ if (rc < 0)
+ return rc;
+
+ if (ss.ss_family != AF_INET)
+ return -EIO;
+
+ *ip = ntohl(sin->sin_addr.s_addr);
+ *port = rtp_session_get_local_port(rs->sess);
+
+ return 0;
+}
+
+int osmo_rtp_get_bound_addr(struct osmo_rtp_socket *rs,
+ const char **addr, int *port)
+{
+ int rc;
+ struct sockaddr_storage ss;
+ socklen_t alen = sizeof(ss);
+ static char hostbuf[256];
+
+ memset(hostbuf, 0, sizeof(hostbuf));
+
+ rc = getsockname(rs->rtp_bfd.fd, (struct sockaddr *)&ss, &alen);
+ if (rc < 0)
+ return rc;
+
+ rc = getnameinfo((struct sockaddr *)&ss, alen,
+ hostbuf, sizeof(hostbuf), NULL, 0,
+ NI_NUMERICHOST);
+ if (rc < 0)
+ return rc;
+
+ *port = rtp_session_get_local_port(rs->sess);
+ *addr = hostbuf;
+
+ return 0;
+}