diff options
-rw-r--r-- | .checkpatch.conf | 1 | ||||
-rw-r--r-- | .gitignore | 5 | ||||
-rw-r--r-- | COPYING (renamed from gpl-3.0.txt) | 0 | ||||
-rw-r--r-- | Makefile.am | 16 | ||||
-rw-r--r-- | README.md | 35 | ||||
-rw-r--r-- | configure.ac | 27 | ||||
-rw-r--r-- | contrib/gapk.spec.in | 151 | ||||
-rwxr-xr-x | contrib/jenkins.sh | 1 | ||||
-rw-r--r-- | debian/changelog | 5 | ||||
-rw-r--r-- | debian/compat | 1 | ||||
-rw-r--r-- | debian/control | 37 | ||||
-rw-r--r-- | debian/copyright | 23 | ||||
-rw-r--r-- | debian/gapk.install | 1 | ||||
-rw-r--r-- | debian/libosmogapk-dev.install | 3 | ||||
-rw-r--r-- | debian/libosmogapk0.install | 1 | ||||
-rwxr-xr-x | debian/rules | 12 | ||||
-rw-r--r-- | debian/source/format | 1 | ||||
-rw-r--r-- | include/osmocom/gapk/get_cycles.h | 10 | ||||
-rw-r--r-- | libgsmhr/Makefile.am | 14 | ||||
-rwxr-xr-x | libgsmhr/fetch_sources.py | 46 | ||||
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/app_osmo_gapk.c | 69 | ||||
-rw-r--r-- | src/fmt_rtp_amr.c | 9 | ||||
-rw-r--r-- | src/fmt_rtp_efr.c | 20 | ||||
-rw-r--r-- | src/fmt_rtp_hr_etsi.c | 6 | ||||
-rw-r--r-- | src/fmt_rtp_hr_ietf.c | 6 | ||||
-rw-r--r-- | src/pq_alsa.c | 4 | ||||
-rw-r--r-- | src/pq_file.c | 4 | ||||
-rw-r--r-- | src/pq_rtp.c | 26 | ||||
-rw-r--r-- | tests/Makefile.am | 2 |
30 files changed, 470 insertions, 78 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf new file mode 100644 index 0000000..58a0b87 --- /dev/null +++ b/.checkpatch.conf @@ -0,0 +1 @@ +--ignore NEW_TYPEDEFS @@ -3,8 +3,8 @@ autoscan-2.*.log configure.scan # autoreconf by-products +.version Makefile.in - aclocal.m4 autom4te.cache/ config.guess @@ -49,8 +49,9 @@ tests/*/*_test src/osmo-gapk # temporary/backup files -*.*~ +*~ .*.swp /compile .dirstamp +contrib/gapk.spec diff --git a/Makefile.am b/Makefile.am index 0093f0e..f2a2c31 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,8 +4,6 @@ ACLOCAL_AMFLAGS = -I m4 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libosmogapk.pc -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include - SUBDIRS = include if ENABLE_GSMHR @@ -13,3 +11,17 @@ SUBDIRS += libgsmhr endif SUBDIRS += src tests + +BUILT_SOURCES = \ + $(top_srcdir)/.version \ + $(NULL) +EXTRA_DIST = \ + git-version-gen \ + .version \ + $(NULL) + +# versioning magic +$(top_srcdir)/.version: + echo $(VERSION) > $@-t && mv $@-t $@ +dist-hook: + echo $(VERSION) > $(distdir)/.tarball-version diff --git a/README.md b/README.md new file mode 100644 index 0000000..5cf880e --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +gapk - GSM Audio Pocket Knife +============================= + +The GSM Audio Pocket Knife is a tool that can help you to convert +codec frames of all codecs in GSM networks between a variety of +different formats / representations. + +It is part of the [Osmocom](https://osmocom.org/) Open Source Mobile +Communications project. + +GIT Repository +-------------- + +You can clone from the official gapk.git repository using + + git clone https://gitea.osmocom.org/osmocom/gapk.git + +There is a web interface at <https://gitea.osmocom.org/osmocom/gapk>. + +Documentation +------------- + +Unfortunately none. + +Mailing List +------------ + +Discussions related to gapk are happening on the +openbsc@lists.osmocom.org mailing list, please see +https://lists.osmocom.org/mailman/listinfo/openbsc for subscription +options and the list archive. + +Please observe the [Osmocom Mailing List +Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules) +when posting. diff --git a/configure.ac b/configure.ac index 6551ae6..9a318bb 100644 --- a/configure.ac +++ b/configure.ac @@ -6,6 +6,8 @@ AC_INIT([gapk], AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects]) LT_INIT([disable-static]) +CFLAGS="$CFLAGS -std=gnu11" + # kernel style compile messages m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) @@ -13,16 +15,12 @@ AC_CONFIG_SRCDIR([src/app_osmo_gapk.c]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_TESTDIR(tests) -AC_CONFIG_FILES([ - Makefile - src/Makefile - libgsmhr/Makefile - include/Makefile - include/gsmhr/Makefile - libosmogapk.pc - tests/atlocal - tests/Makefile -]) + +dnl patching ${archive_cmds} to affect generation of file "libtool" to fix linking with clang +AS_CASE(["$LD"],[*clang*], + [AS_CASE(["${host_os}"], + [*linux*],[archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'])]) + # Options AC_ARG_ENABLE(gsmhr, @@ -115,4 +113,13 @@ AC_TYPE_UINT8_T AC_FUNC_MALLOC AC_CHECK_FUNCS([memset]) +AC_CONFIG_FILES([contrib/gapk.spec + Makefile + src/Makefile + libgsmhr/Makefile + include/Makefile + include/gsmhr/Makefile + libosmogapk.pc + tests/atlocal + tests/Makefile]) AC_OUTPUT diff --git a/contrib/gapk.spec.in b/contrib/gapk.spec.in new file mode 100644 index 0000000..e0466f4 --- /dev/null +++ b/contrib/gapk.spec.in @@ -0,0 +1,151 @@ +# +# spec file for package gapk +# +# Copyright (c) 2017, Martin Hauke <mardnh@gmx.de> +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +%define with_amr 1 +%define with_gsmhr 1 +%define sover 0 + +Name: gapk +Version: @VERSION@ +Release: 0 +Summary: GSM Audio Pocket Knife +License: GPL-3.0-only +Group: Productivity/Multimedia/Sound/Editors and Convertors +URL: http://www.osmocom.org +Source: gapk-%{version}.tar.xz +# License: for libgsmhr see 3gpp website +Source1: 0606_421.zip +Patch1: gapk-disable-codec-dl-during-build.diff +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: libgsm-devel +BuildRequires: libtool +BuildRequires: pkgconfig +BuildRequires: python +BuildRequires: pkgconfig(alsa) +BuildRequires: pkgconfig(libosmocodec) +BuildRequires: pkgconfig(libosmocore) +# Benchmarking is currently only supported on intel platforms... +ExclusiveArch: %{ix86} x86_64 +%if 0%{with_amr} +BuildRequires: libopencore-amr-devel +%endif + +%description +gapk is intented to be the GSM Audio Pocket Knife. +It encodes/decodes several GSM-related audio-codes (HR,FR,EFR) + +%if 0%{with_gsmhr} +%package -n libgsmhr0 +Summary: Shared Library part of libgsmhr +License: NonFree +Group: Development/Libraries/C and C++ + +%description -n libgsmhr0 +libgsmhr contains a standard implementation of the European GSM 06.20 +provisional standard for GSM Half Rate speech speech transcoding. + +%package -n libgsmhr-devel +Summary: Development files for the gsmhr library +License: NonFree +Group: Development/Libraries/C and C++ +Requires: libgsmhr0 = %{version} + +%description -n libgsmhr-devel +libgsmhr contains a standard implementation of the European GSM 06.20 +provisional standard for GSM Half Rate speech speech transcoding. + +This subpackage contains libraries and header files for developing +applications that want to make use of libgsmhr. +%endif + +%package -n libosmogapk%{sover} +Summary: Shared library part of GSM Audio Pocket Knife (GAPK) +License: GPL-3.0-only +Group: Development/Libraries/C and C++ + +%description -n libosmogapk%{sover} +Shared library part of GSM Audio Pocket Knife (GAPK). + +%package -n libosmogapk-devel +Summary: Development files for the GAPK library +License: GPL-3.0-only +Group: Development/Libraries/C and C++ +Requires: libosmogapk%{sover} = %{version} + +%description -n libosmogapk-devel +Shared library part of GSM Audio Pocket Knife (GAPK). + +This subpackage contains the development files for the Osmocom GAPK +library. + +%prep +%setup -q +%if 0%{with_gsmhr} +%patch1 -p1 +cp %{SOURCE1} libgsmhr/ +%endif + +%build +echo "%{version}" >.tarball-version +autoreconf -fi +%configure \ +%if 0%{with_gsmhr} + --enable-gsmhr \ +%endif + --disable-static +make V=1 %{?_smp_mflags} + +%install +%make_install +find %{buildroot} -type f -name "*.la" -delete -print + +%check +%if 0%{with_gsmhr} +## GSM HR tests (6,9,13,14) are known to be broken - https://osmocom.org/issues/2514 +make %{?_smp_mflags} check || : +%else +make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +) +%endif + +%if 0%{with_gsmhr} +%post -n libgsmhr0 -p /sbin/ldconfig +%postun -n libgsmhr0 -p /sbin/ldconfig +%endif + +%post -n libosmogapk%{sover} -p /sbin/ldconfig +%postun -n libosmogapk%{sover} -p /sbin/ldconfig + +%files +%doc COPYING +%{_bindir}/osmo-gapk + +%if 0%{with_gsmhr} +%files -n libgsmhr0 +%{_libdir}/libgsmhr.so.0* + +%files -n libgsmhr-devel +%{_libdir}/libgsmhr.so +%endif + +%files -n libosmogapk%{sover} +%{_libdir}/libosmogapk.so.%{sover}* + +%files -n libosmogapk-devel +%dir %{_includedir}/osmocom/ +%{_includedir}/osmocom/%{name}/ +%{_libdir}/libosmogapk.so +%{_libdir}/pkgconfig/libosmogapk.pc + +%changelog diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index cf53c3a..2e9035d 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -38,5 +38,6 @@ autoreconf --install --force $MAKE $PARALLEL_MAKE LD_LIBRARY_PATH="$inst/lib" $MAKE check || cat-testlogs.sh LD_LIBRARY_PATH="$inst/lib" DISTCHECK_CONFIGURE_FLAGS="" $MAKE distcheck || cat-testlogs.sh +$MAKE maintainer-clean osmo-clean-workspace.sh diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..4cbf688 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +gapk (1.1) unstable; urgency=medium + + * Initial debian packaging + + -- Oliver Smith <osmith@sysmocom.de> Mon, 18 Mar 2024 13:15:22 +0100 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..f599e28 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +10 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..556bbf8 --- /dev/null +++ b/debian/control @@ -0,0 +1,37 @@ +Source: gapk +Section: net +Priority: optional +Maintainer: Osmocom team <openbsc@lists.osmocom.org> +Build-Depends: debhelper (>= 10), + dh-autoreconf, + autotools-dev, + autoconf, + automake, + libtool, + pkg-config, + libasound2-dev, + libgsm1-dev, + libosmocore-dev (>= 0.3.2) +Standards-Version: 4.1.4 +Vcs-Browser: https://gitea.osmocom.org/osmocom/gapk +Vcs-Git: https://gerrit.osmocom.org/gapk +Homepage: https://osmocom.org/projects/gapk/wiki/Gapk + +Package: gapk +Architecture: any +Multi-Arch: foreign +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: GSM Audio Pocket Knife converts between GSM related codecs + +Package: libosmogapk0 +Architecture: any +Multi-Arch: same +Pre-Depends: ${misc:Pre-Depends} +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: GSM Audio Pocket Knife converts between GSM related codecs + +Package: libosmogapk-dev +Section: libdevel +Architecture: any +Depends: libosmogapk0 (= ${binary:Version}), ${misc:Depends} +Description: GSM Audio Pocket Knife converts between GSM related codecs diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..8d7bd0c --- /dev/null +++ b/debian/copyright @@ -0,0 +1,23 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: gapk +Source: https://gitea.osmocom.org/osmocom/gapk + +Files: * +License: GPL-3.0+ + +License: GPL-3.0+ + 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 3 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, see <http://www.gnu.org/licenses/>. + . + On Debian systems, the complete text of the GNU General Public License + Version 3 can be found in `/usr/share/common-licenses/GPL-3'. diff --git a/debian/gapk.install b/debian/gapk.install new file mode 100644 index 0000000..1df36c6 --- /dev/null +++ b/debian/gapk.install @@ -0,0 +1 @@ +usr/bin/* diff --git a/debian/libosmogapk-dev.install b/debian/libosmogapk-dev.install new file mode 100644 index 0000000..ab755d6 --- /dev/null +++ b/debian/libosmogapk-dev.install @@ -0,0 +1,3 @@ +usr/include/* +usr/lib/*/pkgconfig/libosmogapk.pc +usr/lib/*/*.so diff --git a/debian/libosmogapk0.install b/debian/libosmogapk0.install new file mode 100644 index 0000000..3de3b10 --- /dev/null +++ b/debian/libosmogapk0.install @@ -0,0 +1 @@ +usr/lib/*/*.so.* diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..c854d74 --- /dev/null +++ b/debian/rules @@ -0,0 +1,12 @@ +#!/usr/bin/make -f + +%: + dh $@ --with autoreconf + +override_dh_auto_configure: + touch libgsmhr/.downloaded # Don't fetch 3GPP sources + dh_auto_configure + +# Print test results in case of a failure +override_dh_auto_test: + dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false) diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/include/osmocom/gapk/get_cycles.h b/include/osmocom/gapk/get_cycles.h index 40ac570..25376a1 100644 --- a/include/osmocom/gapk/get_cycles.h +++ b/include/osmocom/gapk/get_cycles.h @@ -103,6 +103,16 @@ static inline cycles_t get_cycles() #endif return ret & ~TICK_PRIV_BIT; } +#elif defined(__aarch64__) + +typedef unsigned long cycles_t; +static inline cycles_t get_cycles(void) +{ + cycles_t cval; + asm volatile("isb" : : : "memory"); + asm volatile("mrs %0, cntvct_el0" : "=r" (cval)); + return cval; +} #elif defined(__PPC__) #define CPU_FTR_601 0x00000100 typedef unsigned long cycles_t; diff --git a/libgsmhr/Makefile.am b/libgsmhr/Makefile.am index f36d759..ffbde21 100644 --- a/libgsmhr/Makefile.am +++ b/libgsmhr/Makefile.am @@ -1,3 +1,8 @@ +# 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 + AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS = -fPIC -Wall ${SYMBOL_VISIBILITY} @@ -6,8 +11,6 @@ EXTRA_DIST = \ patches \ $(NULL) -LIBVERSION=0:0:0 - REFSRC_PATH=refsrc REFSRC_SRC=refsrc/dtx.c refsrc/globdefs.c refsrc/host.c refsrc/sp_enc.c refsrc/sp_rom.c refsrc/vad.c refsrc/err_conc.c refsrc/homing.c refsrc/mathdp31.c refsrc/sp_dec.c refsrc/sp_frm.c refsrc/sp_sfrm.c @@ -18,10 +21,11 @@ ${REFSRC_PATH}/.downloaded: done touch $@ -$(REFSRC_SRC) libgsmhr.c: ${REFSRC_PATH}/.downloaded +$(REFSRC_SRC): ${REFSRC_PATH}/.downloaded lib_LTLIBRARIES = libgsmhr.la libgsmhr_la_SOURCES = $(REFSRC_SRC) libgsmhr.c +libgsmhr_la_LDFLAGS = -version-info $(LIBVERSION) libgsmhr_la_LIBADD = -ldl clean-local: @@ -29,3 +33,7 @@ clean-local: distclean-local: -rm -rf ${REFSRC_PATH}/ + +# exclude files downloaded by fetch_sources.py +dist-hook: + -rm -rf $(distdir)/$(REFSRC_PATH) diff --git a/libgsmhr/fetch_sources.py b/libgsmhr/fetch_sources.py index 6fb1b8e..178125c 100755 --- a/libgsmhr/fetch_sources.py +++ b/libgsmhr/fetch_sources.py @@ -1,35 +1,30 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -import urllib2 +import logging as log +import urllib.request +import io import os import sys import zipfile -try: - import cStringIO as StringIO -except: - import StringIO +URL = "http://www.3gpp.org/ftp/Specs/archive/06_series/06.06/0606-421.zip" -SRC = "http://www.3gpp.org/ftp/Specs/archive/06_series/06.06/0606-421.zip" -HDR = { - "User-Agent": "Mozilla/5.0 (X11; ArchLinux; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", -} +def get_zipfile(data: bytes) -> zipfile.ZipFile: + return zipfile.ZipFile(io.BytesIO(data), 'r') -def get_zipfile(data): - return zipfile.ZipFile(StringIO.StringIO(data)) - -def get_subfile_data(data, filename): +def get_subfile_data(data: bytes, filename: str): + log.debug('Unpacking \'%s\'', filename) z = get_zipfile(data) return z.read(filename) def process_file(z, e): - fh = open(os.path.basename(e.filename.lower()), 'w') - d = z.read(e).replace('\r','') + log.debug('Processing file \'%s\'', e.filename.lower()) + fh = open(os.path.basename(e.filename.lower()), 'wb') + d = z.read(e).replace(b'\r', b'') fh.write(d) fh.close() @@ -38,7 +33,7 @@ def main(*args): # Args if len(args) != 2: - print "Usage: %s target_dir" % args[0] + print("Usage: %s target_dir" % args[0]) return tgt = args[1] @@ -49,9 +44,16 @@ def main(*args): os.chdir(tgt) # Get the original data - req = urllib2.Request(SRC, headers = HDR) - u = urllib2.urlopen(req) - d = u.read() + log.info('Requesting file: %s', URL) + with urllib.request.urlopen(URL) as response: + log.debug('Response code: %d', response.code) + assert response.code == 200 + + for h in ('Last-Modified', 'Content-Type', 'Content-Length'): + log.debug('%s: %s', h, response.getheader(h)) + + log.info('Downloading %d bytes...', response.length) + d = response.read() # Get DISK.zip d = get_subfile_data(d, 'DISK.zip') @@ -67,5 +69,7 @@ def main(*args): process_file(z, e) +log.basicConfig(format='[%(levelname)s] %(filename)s:%(lineno)d %(message)s', level=log.DEBUG) + if __name__ == '__main__': main(*sys.argv) diff --git a/src/Makefile.am b/src/Makefile.am index 8fdeff7..550e3b8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,19 +20,22 @@ AM_CFLAGS = \ lib_LTLIBRARIES = libosmogapk.la EXTRA_DIST = libosmogapk.map -libosmogapk_la_LDFLAGS = \ +libosmogapk_la_LIBADD = \ $(LIBOSMOCORE_LIBS) \ $(LIBOSMOCODEC_LIBS) \ ${OPENCORE_AMRNB_LIBS} \ ${LIBGSM_LIBS} \ $(LIBALSA_LIBS) \ + $(NULL) + +libosmogapk_la_LDFLAGS = \ $(LTLDFLAGS_OSMOGAPK) \ -version-info $(LIBVERSION) \ -no-undefined \ $(NULL) if ENABLE_GSMHR -libosmogapk_la_LIBADD = $(top_builddir)/libgsmhr/libgsmhr.la +libosmogapk_la_LIBADD += $(top_builddir)/libgsmhr/libgsmhr.la endif # Processing queue implementation @@ -94,10 +97,7 @@ osmo_gapk_SOURCES = \ app_osmo_gapk.c \ $(NULL) -osmo_gapk_LDFLAGS = \ - $(LIBOSMOCORE_LIBS) \ - $(NULL) - osmo_gapk_LDADD = \ libosmogapk.la \ + $(LIBOSMOCORE_LIBS) \ $(NULL) diff --git a/src/app_osmo_gapk.c b/src/app_osmo_gapk.c index 91647ee..1e4e9a0 100644 --- a/src/app_osmo_gapk.c +++ b/src/app_osmo_gapk.c @@ -36,6 +36,7 @@ #include <osmocom/core/logging.h> #include <osmocom/core/socket.h> #include <osmocom/core/utils.h> +#include <osmocom/core/select.h> #include <osmocom/gapk/common.h> #include <osmocom/gapk/codecs.h> @@ -67,6 +68,7 @@ struct gapk_options /* RTP payload type */ uint8_t rtp_pt_in, rtp_pt_out; + int throttle; int benchmark; int verbose; }; @@ -75,6 +77,8 @@ struct gapk_state { struct gapk_options opts; struct osmo_gapk_pq *pq; + struct osmo_fd timerfd; /* for optional throttling */ + unsigned int num_frames; int exit; struct { @@ -139,6 +143,7 @@ print_help(char *progname) fprintf(stdout, " -p --rtp-pt-in=TYPE\t\tRTP payload type for incoming frames\n"); fprintf(stdout, " -P --rtp-pt-out=TYPE\t\tRTP payload type for outgoing frames\n"); fprintf(stdout, " -b, --enable-benchmark\tEnable codec benchmarking\n"); + fprintf(stdout, " -t, --throttle\tEnable throttling (one codec frame every 20ms)\n"); fprintf(stdout, " -v, --verbose\t\t\tEnable debug messages\n"); fprintf(stdout, "\n"); @@ -211,10 +216,11 @@ parse_options(struct gapk_state *state, int argc, char *argv[]) {"rtp-pt-in", 1, 0, 'p'}, {"rtp-pt-out", 1, 0, 'P'}, {"enable-benchmark", 0, 0, 'b'}, + {"throttle", 0, 0, 't'}, {"verbose", 0, 0, 'v'}, {"help", 0, 0, 'h'}, }; - const char *short_options = "i:o:I:O:f:g:p:P:bvh" + const char *short_options = "i:o:I:O:f:g:p:P:btvh" #ifdef HAVE_ALSA "a:A:" #endif @@ -312,6 +318,10 @@ parse_options(struct gapk_state *state, int argc, char *argv[]) opt->benchmark = 1; break; + case 't': + opt->throttle = 1; + break; + case 'v': log_parse_category_mask(osmo_stderr_target, "DAPP"); opt->verbose = 1; @@ -668,22 +678,65 @@ make_processing_chain(struct gapk_state *gs) } static int +timerfd_cb(struct osmo_fd *ofd, unsigned int what) +{ + struct gapk_state *gs = ofd->data; + uint64_t expire_count; + int rc; + + rc = read(ofd->fd, (void *)&expire_count, sizeof(expire_count)); + if (rc < 0 && errno == EAGAIN) + return 0; + OSMO_ASSERT(rc == sizeof(expire_count)); + + while (expire_count--) { + gs->num_frames++; + rc = osmo_gapk_pq_execute(gs->pq); + if (rc < 0) + gs->exit = true; + } + return 0; +} + +static int run(struct gapk_state *gs) { struct osmo_gapk_pq_item *item; - int rv, frames; + int rv; rv = osmo_gapk_pq_prepare(gs->pq); if (rv) return rv; - for (frames = 0; !gs->exit; frames++) { - rv = osmo_gapk_pq_execute(gs->pq); - if (rv) - break; + if (!gs->opts.throttle) { + for (gs->num_frames = 0; !gs->exit; gs->num_frames++) { + rv = osmo_gapk_pq_execute(gs->pq); + if (rv) + break; + } + } else { + /* setup timerfd based processing */ + const struct timespec interval = { + .tv_sec = 0, + .tv_nsec = 20*1000*1000, + }; + gs->timerfd.fd = -1; + rv = osmo_timerfd_setup(&gs->timerfd, timerfd_cb, gs); + OSMO_ASSERT(rv == 0); + rv = osmo_timerfd_schedule(&gs->timerfd, NULL, &interval); + OSMO_ASSERT(rv == 0); + + /* actual processing loop */ + while (!gs->exit) + osmo_select_main(0); + + /* cleanup */ + osmo_timerfd_disable(&gs->timerfd); + close(gs->timerfd.fd); + osmo_fd_unregister(&gs->timerfd); } - LOGP(DAPP, LOGL_NOTICE, "Processed %d frames\n", frames); + LOGP(DAPP, LOGL_NOTICE, "Processed %d frames\n", gs->num_frames); /* Wait for sink to process buffers */ item = llist_last_entry(&gs->pq->items, struct osmo_gapk_pq_item, list); @@ -693,7 +746,7 @@ run(struct gapk_state *gs) continue; } - return frames > 0 ? 0 : rv; + return gs->num_frames > 0 ? 0 : rv; } diff --git a/src/fmt_rtp_amr.c b/src/fmt_rtp_amr.c index a6a3c9f..4982c83 100644 --- a/src/fmt_rtp_amr.c +++ b/src/fmt_rtp_amr.c @@ -27,6 +27,9 @@ #include <osmocom/gapk/formats.h> #include <osmocom/gapk/utils.h> +/* AMR SID frame is according to TS 126 101 4.2.3 */ +static const uint8_t SILENCE[] = {0x80, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00}; + /* conversion function: RTP payload -> canonical format */ static int rtp_amr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len) @@ -42,6 +45,12 @@ rtp_amr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len) static int rtp_amr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len) { + /* Detect severely damaged frames according to RFC4867 4.3.2 */ + if ((src[1] & 0x04) == 0) { + src = SILENCE; + src_len = sizeof(SILENCE); + } + /* skip Payload Header according to RFC4867 4.4.1 */ memcpy(dst, src+1, src_len-1); diff --git a/src/fmt_rtp_efr.c b/src/fmt_rtp_efr.c index accfd4f..214010e 100644 --- a/src/fmt_rtp_efr.c +++ b/src/fmt_rtp_efr.c @@ -30,6 +30,17 @@ #define EFR_LEN 31 #define EFR_MAGIC 0xc +/* EFR encoding starts with 0xc, if all other bits are 0 the packet is probably damaged */ +static const uint8_t DAMAGED_PACKET[EFR_LEN] = { + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +/* EFR SID frame is according to TS 101 318 5.3.2 */ +static const uint8_t SILENCE[EFR_LEN] = { + 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + /* conversion function: RTP payload -> canonical format */ static int rtp_efr_from_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len) @@ -52,7 +63,14 @@ rtp_efr_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len) { int i; - assert(src_len == EFR_LEN); + /* broken RTP frames may be short; substitute empty frame */ + if (src_len != EFR_LEN) { + memset(dst, 0, EFR_CANON_LEN); + return EFR_CANON_LEN; + } + + if (!memcmp(DAMAGED_PACKET, src, EFR_LEN)) + src = SILENCE; for (i=0; i<(EFR_LEN-1); i++) dst[i] = (src[i] << 4) | (src[i+1] >> 4); diff --git a/src/fmt_rtp_hr_etsi.c b/src/fmt_rtp_hr_etsi.c index 9ed9b22..0b7e392 100644 --- a/src/fmt_rtp_hr_etsi.c +++ b/src/fmt_rtp_hr_etsi.c @@ -42,7 +42,11 @@ static int rtp_hr_etsi_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len) { /* according to TS 101 318 */ - assert(src_len == HR_CANON_LEN); + /* broken RTP frames may be short; substitute empty frame */ + if (src_len != HR_CANON_LEN) { + memset(dst, 0, HR_CANON_LEN); + return HR_CANON_LEN; + } memcpy(dst, src, src_len); return HR_CANON_LEN; diff --git a/src/fmt_rtp_hr_ietf.c b/src/fmt_rtp_hr_ietf.c index 4ee548f..a840d4b 100644 --- a/src/fmt_rtp_hr_ietf.c +++ b/src/fmt_rtp_hr_ietf.c @@ -60,7 +60,11 @@ static int rtp_hr_ietf_to_canon(uint8_t *dst, const uint8_t *src, unsigned int src_len) { /* according to RFC5993 */ - assert(src_len == HR_LEN); + /* broken RTP frames may be short; substitute empty frame */ + if (src_len != HR_LEN) { + memset(dst, 0, HR_LEN); + return HR_CANON_LEN; + } /* Remove ToC byte */ memcpy(dst, src+1, HR_CANON_LEN); diff --git a/src/pq_alsa.c b/src/pq_alsa.c index 3550221..50479e6 100644 --- a/src/pq_alsa.c +++ b/src/pq_alsa.c @@ -176,7 +176,7 @@ out_print: * \param pq Processing Queue to add the ALSA input to * \param[in] hwdev ALSA hardware device to use * \param[in] blk_len block length to be read from device - * \returns 0 on sucess; negative on error */ + * \returns 0 on success; negative on error */ int osmo_gapk_pq_queue_alsa_input(struct osmo_gapk_pq *pq, const char *hwdev, unsigned int blk_len) { @@ -190,7 +190,7 @@ osmo_gapk_pq_queue_alsa_input(struct osmo_gapk_pq *pq, const char *hwdev, unsign * \param pq Processing Queue to add the ALSA output to * \param[in] hwdev ALSA hardware device to use * \param[in] blk_len block length to be written to device - * \returns 0 on sucess; negative on error */ + * \returns 0 on success; negative on error */ int osmo_gapk_pq_queue_alsa_output(struct osmo_gapk_pq *pq, const char *hwdev, unsigned int blk_len) { diff --git a/src/pq_file.c b/src/pq_file.c index 22dc9cd..d496eec 100644 --- a/src/pq_file.c +++ b/src/pq_file.c @@ -103,7 +103,7 @@ pq_queue_file_op(struct osmo_gapk_pq *pq, FILE *fh, unsigned int blk_len, int in * \param pq Processing Queue to add the input file to * \param[in] src caller-fopen()ed input file * \param[in] blk_len block length to be read from file - * \returns 0 on sucess; negative on error */ + * \returns 0 on success; negative on error */ int osmo_gapk_pq_queue_file_input(struct osmo_gapk_pq *pq, FILE *src, unsigned int blk_len) { @@ -117,7 +117,7 @@ osmo_gapk_pq_queue_file_input(struct osmo_gapk_pq *pq, FILE *src, unsigned int b * \param pq Processing Queue to add the output file to * \param[in] dst caller-fopen()ed output file * \param[in] blk_len block length to be written to file - * \returns 0 on sucess; negative on error */ + * \returns 0 on success; negative on error */ int osmo_gapk_pq_queue_file_output(struct osmo_gapk_pq *pq, FILE *dst, unsigned int blk_len) { diff --git a/src/pq_rtp.c b/src/pq_rtp.c index 81eeb19..a5543a6 100644 --- a/src/pq_rtp.c +++ b/src/pq_rtp.c @@ -30,33 +30,21 @@ #include <osmocom/gapk/codecs.h> #include <osmocom/gapk/formats.h> #include <osmocom/gapk/procqueue.h> - -#ifndef __BYTE_ORDER -# ifdef __APPLE__ -# define __BYTE_ORDER __DARWIN_BYTE_ORDER -# define __LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN -# define __BIG_ENDIAN __DARWIN_BIG_ENDIAN -# else -# error "__BYTE_ORDER should be defined by someone" -# endif -#endif +#include <osmocom/core/endian.h> /* according to RFC 3550 */ struct rtp_hdr { -#if __BYTE_ORDER == __LITTLE_ENDIAN +#if OSMO_IS_LITTLE_ENDIAN uint8_t csrc_count:4, extension:1, padding:1, version:2; uint8_t payload_type:7, marker:1; -#elif __BYTE_ORDER == __BIG_ENDIAN - uint8_t version:2, - padding:1, - extension:1, - csrc_count:4; - uint8_t marker:1, - payload_type:7; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t version:2, padding:1, extension:1, csrc_count:4; + uint8_t marker:1, payload_type:7; #endif uint16_t sequence; uint32_t timestamp; @@ -116,7 +104,7 @@ pq_cb_rtp_input(void *_state, uint8_t *out, const uint8_t *in, unsigned int in_l payload = buf + sizeof(struct rtp_hdr) + (rtph->csrc_count << 2); payload_len = rv - sizeof(struct rtp_hdr) - (rtph->csrc_count << 2); if (payload_len < 0) { - rtp_err("non-existant RTP payload length %d\n", payload_len); + rtp_err("non-existent RTP payload length %d\n", payload_len); return -1; } diff --git a/tests/Makefile.am b/tests/Makefile.am index dee4060..e0a3c96 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,6 +10,8 @@ AM_CFLAGS = \ $(LIBOSMOCODEC_CFLAGS) \ $(NULL) +AM_LDFLAGS = -no-install + check_PROGRAMS = \ procqueue/pq_test \ io/pq_file_test \ |