laforge submitted this change.
tests: add unit tests for trau2rtp conversion, FR & EFR
The present set of tests exercises osmo_trau_frame_decode_16k()
and osmo_trau2rtp() functions for frame types of FR speech and
EFR speech. Both standard (RFC 3551) and TW-TS-001 output modes
are tested.
Change-Id: Ie319900125baa8f20595cac83343771d780a5b4e
---
M .gitignore
M tests/Makefile.am
M tests/testsuite.at
A tests/trau_conv/trau16_efr.in
A tests/trau_conv/trau16_efr_std.ok
A tests/trau_conv/trau16_efr_twts001.ok
A tests/trau_conv/trau16_fr.in
A tests/trau_conv/trau16_fr_std.ok
A tests/trau_conv/trau16_fr_twts001.ok
A tests/trau_conv/trau16_to_rtp.c
10 files changed, 1,128 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
index f932b39..2bed942 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,6 +41,7 @@
tests/subchan_demux/subchan_demux_test
tests/ipa_recv/ipa_recv_test
tests/trau_pcu_ericsson/trau_pcu_ericsson_test
+tests/trau_conv/trau16_to_rtp
tests/trau_sync/trau_sync_test
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a01f381..e50a3b7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -7,6 +7,7 @@
ipa_proxy_test \
subchan_demux/subchan_demux_test \
ipa_recv/ipa_recv_test \
+ trau_conv/trau16_to_rtp \
trau_sync/trau_sync_test \
trau_pcu_ericsson/trau_pcu_ericsson_test
@@ -41,6 +42,10 @@
rtp_test_rtp_test_LDADD = $(top_builddir)/src/libosmotrau.la \
$(LIBOSMOCORE_LIBS)
+trau_conv_trau16_to_rtp_SOURCES = trau_conv/trau16_to_rtp.c
+trau_conv_trau16_to_rtp_LDADD = $(top_builddir)/src/libosmotrau.la \
+ $(LIBOSMOCORE_LIBS) $(LIBOSMOCODEC_LIBS)
+
trau_sync_trau_sync_test_SOURCES = trau_sync/trau_sync_test.c
trau_sync_trau_sync_test_LDADD = $(top_builddir)/src/libosmotrau.la \
$(LIBOSMOCORE_LIBS)
@@ -72,6 +77,10 @@
subchan_demux/subchan_demux_test.ok \
ipa_recv/ipa_recv_test.ok \
rtp_test/rtp_test.ok \
+ trau_conv/trau16_efr.in trau_conv/trau16_efr_std.ok \
+ trau_conv/trau16_efr_twts001.ok \
+ trau_conv/trau16_fr.in trau_conv/trau16_fr_std.ok \
+ trau_conv/trau16_fr_twts001.ok \
trau_sync/trau_sync_test.ok trau_sync/trau_sync_test.err \
trau_pcu_ericsson/trau_pcu_ericsson_test.ok
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 818e4fa..2528eb8 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -42,3 +42,27 @@
cat $abs_srcdir/trau_pcu_ericsson/trau_pcu_ericsson_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/trau_pcu_ericsson/trau_pcu_ericsson_test], [0], [expout], [ignore])
AT_CLEANUP
+
+AT_SETUP([trau2rtp_fr_std])
+AT_KEYWORDS([trau2rtp_fr_std])
+cat $abs_srcdir/trau_conv/trau16_fr_std.ok > expout
+AT_CHECK([$abs_top_builddir/tests/trau_conv/trau16_to_rtp $abs_srcdir/trau_conv/trau16_fr.in ul std], [0], [expout], [ignore])
+AT_CLEANUP
+
+AT_SETUP([trau2rtp_fr_twts001])
+AT_KEYWORDS([trau2rtp_fr_twts001])
+cat $abs_srcdir/trau_conv/trau16_fr_twts001.ok > expout
+AT_CHECK([$abs_top_builddir/tests/trau_conv/trau16_to_rtp $abs_srcdir/trau_conv/trau16_fr.in ul tw-ts-001], [0], [expout], [ignore])
+AT_CLEANUP
+
+AT_SETUP([trau2rtp_efr_std])
+AT_KEYWORDS([trau2rtp_efr_std])
+cat $abs_srcdir/trau_conv/trau16_efr_std.ok > expout
+AT_CHECK([$abs_top_builddir/tests/trau_conv/trau16_to_rtp $abs_srcdir/trau_conv/trau16_efr.in ul std], [0], [expout], [ignore])
+AT_CLEANUP
+
+AT_SETUP([trau2rtp_efr_twts001])
+AT_KEYWORDS([trau2rtp_efr_twts001])
+cat $abs_srcdir/trau_conv/trau16_efr_twts001.ok > expout
+AT_CHECK([$abs_top_builddir/tests/trau_conv/trau16_to_rtp $abs_srcdir/trau_conv/trau16_efr.in ul tw-ts-001], [0], [expout], [ignore])
+AT_CLEANUP
diff --git a/tests/trau_conv/trau16_efr.in b/tests/trau_conv/trau16_efr.in
new file mode 100644
index 0000000..a0a3fa0
--- /dev/null
+++ b/tests/trau_conv/trau16_efr.in
@@ -0,0 +1,68 @@
+# This file is an input to trau16_to_rtp unit test program, containing
+# TRAU-16k Abis-UL frames for TCH/EFS.
+#
+# All test frames presented here have been taken from these Abis E1 captures:
+#
+# https://osmocom.org/projects/retro-gsm/wiki/InSite_UL_captures
+#
+# The extraction of hex-encoded TRAU frames from E1 timeslot *.bin captures
+# was done with trau-parse program (-r option) developed in this repository:
+#
+# https://www.freecalypso.org/hg/gsm-net-reveng/
+
+# A few BFI frames from channel start-up, including one in TAF position
+
+ID efr-dtx.bin frame 0x8e11
+0000e808c0e1ab5dbb94ef0ee7c6967ce3b5846ec1b19ededdbab7ddd5b48e51acd6bde2aefab2ff
+ID efr-dtx.bin frame 0x8eb1
+0000e808f4d7b875e9538027a20597dc8affe571f92ba6fe986af0fe98cd97e3c138cda2fe45daff
+ID efr-dtx.bin frame 0x8f51
+0000e809c4b6d46fa0a6c763fa80fb499311b22eb576a68da81b971cd89fe22ebe4190908ee9caff
+
+# Some good speech frames
+
+ID efr-dtx.bin frame 0x9311
+0000e8c0ecc6e6d39ae5ac008013b21780ec800080008002aad6800080008036eb00800080008eff
+ID efr-dtx.bin frame 0x93b1
+0000e8c0c5959c70daf191608000800081abb8ccf580a07c873fb977a81cc410f1588c7fdd61ceff
+ID efr-dtx.bin frame 0x9451
+0000e8c0d01dc9f2f67a885ff583d73fa9daf2cca28a91babde68c43a24efc32aa69ad8af003caff
+
+# A good speech frame in TAF position
+
+ID efr-dtx.bin frame 0x9e51
+0000e8c1c9dfd7d1dfbff22fe2dceb339454b771e18ba09ddbccab2ce3dc821386be9b1d9fe9c6ff
+
+# Entry into DTXu pause
+
+ID efr-dtx.bin frame 0x3cad1
+0000ebe4ca1b97f3b45086fffffc8000c68efffffe008046c07fffffe0008451fffcffe08004e2ff
+ID efr-dtx.bin frame 0x3cb71
+0000ebecca31d987973086fffffc9b0ace8effffff20804ec07fffffe12084d1ffffffe28b0ce2ff
+ID efr-dtx.bin frame 0x3cc11
+0000ebe8f23dea94e91ec4229aacfe968207e8d7ba6bb402ec02d8e6b00c83a0fe44dd50ae84eaff
+
+# SID update in TAF position, with half-blocks before and after
+
+ID efr-dtx.bin frame 0x430b1
+0000ebeccf36da92c6a086fffffca494d68efffffe4ba056c07ffffff0048551fffcffe0a485a2ff
+ID efr-dtx.bin frame 0x43151
+0000ebe5cf36da92c6a086fffffc8000d68efffffe008056c07fffffe0008551fffcffe08005a2ff
+ID efr-dtx.bin frame 0x431f1
+0000ebeccf36da92c6a086fffffcc340d68efffffe04d0d6c07fffffe0818551fffdffe0d84da2ff
+
+# FACCH activity in the middle of DTXu pause, includes a BFI-no-data frame
+# in which buffered bit content is still (invalid) SID, but is marked as
+# SID=0 in out-of-band flag bits.
+
+ID efr-dtx-dtmf.bin frame 0x4d471
+0000ebecd090a131e71086fffffca494ce8efffffe4ba04ec07ffffff00484d1fffcffe0a484e2ff
+ID efr-dtx-dtmf.bin frame 0x4d511
+0000ebe8c7e5a131e70da61ffffca494cc79fffffe4ba04d9214fffff00484c7fffcffe0a484feff
+
+# Another similar occurrence, but this time it was SID=1 initially
+
+ID efr-dtx-dtmf.bin frame 0x53a51
+0000ebead10eba68ada886f7fbfca494ca8cfffffe4ba04ac07ffffff0048491fffcffe0a485c2ff
+ID efr-dtx-dtmf.bin frame 0x53af1
+0000ebe8cf05b311adada617fbfca494c87afffffe4ba04ac214fffff00484affffcffe0a485deff
diff --git a/tests/trau_conv/trau16_efr_std.ok b/tests/trau_conv/trau16_efr_std.ok
new file mode 100644
index 0000000..1f09a0b
--- /dev/null
+++ b/tests/trau_conv/trau16_efr_std.ok
@@ -0,0 +1,110 @@
+ID efr-dtx.bin frame 0x8e11
+0000e808c0e1ab5dbb94ef0ee7c6967ce3b5846ec1b19ededdbab7ddd5b48e51acd6bde2aefab2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx.bin frame 0x8eb1
+0000e808f4d7b875e9538027a20597dc8affe571f92ba6fe986af0fe98cd97e3c138cda2fe45daff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx.bin frame 0x8f51
+0000e809c4b6d46fa0a6c763fa80fb499311b22eb576a68da81b971cd89fe22ebe4190908ee9caff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx.bin frame 0x9311
+0000e8c0ecc6e6d39ae5ac008013b21780ec800080008002aad6800080008036eb00800080008eff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 31
+ EFR frame:
+ LPC 89 141 310 153 43
+ 342 0 0 0 0 1 3 3 1 0 2 7 0
+ 54 0 0 0 0 0 0 0 0 0 0 0 0
+ 342 11 0 0 0 0 0 0 0 0 0 0 0
+ 54 11 0 0 0 0 0 0 0 0 0 0 0
+ SID recompute: 0
+ID efr-dtx.bin frame 0x93b1
+0000e8c0c5959c70daf191608000800081abb8ccf580a07c873fb977a81cc410f1588c7fdd61ceff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 31
+ EFR frame:
+ LPC 11 42 227 133 43
+ 72 11 0 0 0 0 0 0 0 0 0 0 0
+ 21 11 8 12 12 14 11 0 0 1 0 0 31
+ 57 15 11 9 7 7 5 0 0 7 1 0 16
+ 7 1 5 8 1 8 15 7 5 6 5 4 6
+ SID recompute: 0
+ID efr-dtx.bin frame 0x9451
+0000e8c0d01dc9f2f67a885ff583d73fa9daf2cca28a91babde68c43a24efc32aa69ad8af003caff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 31
+ EFR frame:
+ LPC 32 59 79 151 25
+ 132 2 15 15 5 8 3 5 3 4 7 7 10
+ 45 7 2 12 12 4 5 0 5 0 4 3 14
+ 495 3 0 12 4 3 4 2 2 3 5 7 16
+ 18 10 6 9 5 11 1 2 7 0 0 0 14
+ SID recompute: 0
+ID efr-dtx.bin frame 0x9e51
+0000e8c1c9dfd7d1dfbff22fe2dceb339454b771e18ba09ddbccab2ce3dc821386be9b1d9fe9c6ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 31
+ EFR frame:
+ LPC 19 191 190 141 62
+ 505 1 7 14 2 13 12 6 5 4 6 3 5
+ 42 3 7 7 1 12 3 0 5 5 0 1 7
+ 222 6 2 11 2 12 12 3 6 7 0 0 8
+ 24 6 11 14 3 6 3 5 1 7 7 5 6
+ SID recompute: 0
+ID efr-dtx.bin frame 0x3cad1
+0000ebe4ca1b97f3b45086fffffc8000c68efffffe008046c07fffffe0008451fffcffe08004e2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 31
+ EFR frame:
+ LPC 20 54 191 155 17
+ 3 7 15 15 15 15 12 0 0 0 0 0 17
+ 7 7 15 15 15 15 12 0 0 0 0 0 17
+ 3 15 15 15 15 15 12 0 0 0 0 0 17
+ 15 15 15 12 15 15 12 0 0 0 0 0 19
+ SID recompute: 2
+ID efr-dtx.bin frame 0x3cb71
+0000ebecca31d987973086fffffc9b0ace8effffff20804ec07fffffe12084d1ffffffe28b0ce2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx.bin frame 0x3cc11
+0000ebe8f23dea94e91ec4229aacfe968207e8d7ba6bb402ec02d8e6b00c83a0fe44dd50ae84eaff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx.bin frame 0x430b1
+0000ebeccf36da92c6a086fffffca494d68efffffe4ba056c07ffffff0048551fffcffe0a485a2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx.bin frame 0x43151
+0000ebe5cf36da92c6a086fffffc8000d68efffffe008056c07fffffe0008551fffcffe08005a2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 31
+ EFR frame:
+ LPC 30 109 212 148 26
+ 3 7 15 15 15 15 12 0 0 0 0 0 21
+ 7 7 15 15 15 15 12 0 0 0 0 0 21
+ 3 15 15 15 15 15 12 0 0 0 0 0 21
+ 15 15 15 12 15 15 12 0 0 0 0 0 21
+ SID recompute: 2
+ID efr-dtx.bin frame 0x431f1
+0000ebeccf36da92c6a086fffffcc340d68efffffe04d0d6c07fffffe0818551fffdffe0d84da2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx-dtmf.bin frame 0x4d471
+0000ebecd090a131e71086fffffca494ce8efffffe4ba04ec07ffffff00484d1fffcffe0a484e2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx-dtmf.bin frame 0x4d511
+0000ebe8c7e5a131e70da61ffffca494cc79fffffe4ba04d9214fffff00484c7fffcffe0a484feff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx-dtmf.bin frame 0x53a51
+0000ebead10eba68ada886f7fbfca494ca8cfffffe4ba04ac07ffffff0048491fffcffe0a485c2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
+ID efr-dtx-dtmf.bin frame 0x53af1
+0000ebe8cf05b311adada617fbfca494c87afffffe4ba04ac214fffff00484affffcffe0a485deff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 0
diff --git a/tests/trau_conv/trau16_efr_twts001.ok b/tests/trau_conv/trau16_efr_twts001.ok
new file mode 100644
index 0000000..14dfe9d
--- /dev/null
+++ b/tests/trau_conv/trau16_efr_twts001.ok
@@ -0,0 +1,204 @@
+ID efr-dtx.bin frame 0x8e11
+0000e808c0e1ab5dbb94ef0ee7c6967ce3b5846ec1b19ededdbab7ddd5b48e51acd6bde2aefab2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 1 194 346 235 46
+ 311 8 7 6 7 12 6 1 3 1 7 4 24
+ 26 8 4 6 14 8 3 3 0 4 7 5 23
+ 237 13 3 7 13 13 10 5 5 5 0 1 25
+ 10 12 13 6 7 11 12 2 2 7 3 7 9
+ SID recompute: 0
+ID efr-dtx.bin frame 0x8eb1
+0000e808f4d7b875e9538027a20597dc8affe571f92ba6fe986af0fe98cd97e3c138cda2fe45daff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 105 174 451 174 37
+ 192 1 3 10 2 0 5 1 3 7 3 4 2
+ 63 14 5 7 1 15 2 2 5 5 1 5 31
+ 195 5 7 0 15 14 3 0 6 3 2 2 31
+ 28 1 3 8 9 11 4 2 7 7 1 0 22
+ SID recompute: 0
+ID efr-dtx.bin frame 0x8f51
+0000e809c4b6d46fa0a6c763fa80fb499311b22eb576a68da81b971cd89fe22ebe4190908ee9caff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE3
+ EFR frame:
+ LPC 9 109 163 122 2
+ 419 11 1 15 10 8 0 7 5 5 1 1 4
+ 8 11 2 2 14 6 10 7 3 1 1 5 3
+ 320 13 9 7 1 12 11 0 4 7 7 4 8
+ 51 14 4 1 2 1 2 0 0 7 3 5 6
+ SID recompute: 0
+ID efr-dtx.bin frame 0x9311
+0000e8c0ecc6e6d39ae5ac008013b21780ec800080008002aad6800080008036eb00800080008eff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE0
+ EFR frame:
+ LPC 89 141 310 153 43
+ 342 0 0 0 0 1 3 3 1 0 2 7 0
+ 54 0 0 0 0 0 0 0 0 0 0 0 0
+ 342 11 0 0 0 0 0 0 0 0 0 0 0
+ 54 11 0 0 0 0 0 0 0 0 0 0 0
+ SID recompute: 0
+ID efr-dtx.bin frame 0x93b1
+0000e8c0c5959c70daf191608000800081abb8ccf580a07c873fb977a81cc410f1588c7fdd61ceff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE0
+ EFR frame:
+ LPC 11 42 227 133 43
+ 72 11 0 0 0 0 0 0 0 0 0 0 0
+ 21 11 8 12 12 14 11 0 0 1 0 0 31
+ 57 15 11 9 7 7 5 0 0 7 1 0 16
+ 7 1 5 8 1 8 15 7 5 6 5 4 6
+ SID recompute: 0
+ID efr-dtx.bin frame 0x9451
+0000e8c0d01dc9f2f67a885ff583d73fa9daf2cca28a91babde68c43a24efc32aa69ad8af003caff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE0
+ EFR frame:
+ LPC 32 59 79 151 25
+ 132 2 15 15 5 8 3 5 3 4 7 7 10
+ 45 7 2 12 12 4 5 0 5 0 4 3 14
+ 495 3 0 12 4 3 4 2 2 3 5 7 16
+ 18 10 6 9 5 11 1 2 7 0 0 0 14
+ SID recompute: 0
+ID efr-dtx.bin frame 0x9e51
+0000e8c1c9dfd7d1dfbff22fe2dceb339454b771e18ba09ddbccab2ce3dc821386be9b1d9fe9c6ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE1
+ EFR frame:
+ LPC 19 191 190 141 62
+ 505 1 7 14 2 13 12 6 5 4 6 3 5
+ 42 3 7 7 1 12 3 0 5 5 0 1 7
+ 222 6 2 11 2 12 12 3 6 7 0 0 8
+ 24 6 11 14 3 6 3 5 1 7 7 5 6
+ SID recompute: 0
+ID efr-dtx.bin frame 0x3cad1
+0000ebe4ca1b97f3b45086fffffc8000c68efffffe008046c07fffffe0008451fffcffe08004e2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE0
+ EFR frame:
+ LPC 20 54 191 155 17
+ 3 7 15 15 15 15 12 0 0 0 0 0 17
+ 7 7 15 15 15 15 12 0 0 0 0 0 17
+ 3 15 15 15 15 15 12 0 0 0 0 0 17
+ 15 15 15 12 15 15 12 0 0 0 0 0 19
+ SID recompute: 2
+ID efr-dtx.bin frame 0x3cb71
+0000ebecca31d987973086fffffc9b0ace8effffff20804ec07fffffe12084d1ffffffe28b0ce2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 20 99 204 57 28
+ 3 7 15 15 15 15 12 1 5 4 1 2 19
+ 7 7 15 15 15 15 14 2 0 0 0 0 19
+ 3 15 15 15 15 15 12 1 1 0 0 0 19
+ 15 15 15 15 15 15 12 2 0 5 4 1 19
+ SID recompute: 2
+ID efr-dtx.bin frame 0x3cc11
+0000ebe8f23dea94e91ec4229aacfe968207e8d7ba6bb402ec02d8e6b00c83a0fe44dd50ae84eaff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 100 123 340 166 36
+ 418 1 1 1 10 10 12 7 7 2 2 6 0
+ 3 14 8 13 7 7 4 6 5 5 5 0 0
+ 352 1 5 8 14 6 6 0 0 3 0 0 14
+ 7 14 4 4 11 10 10 0 2 7 2 0 19
+ SID recompute: 0
+ID efr-dtx.bin frame 0x430b1
+0000ebeccf36da92c6a086fffffca494d68efffffe4ba056c07ffffff0048551fffcffe0a485a2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 30 109 212 148 26
+ 3 7 15 15 15 15 12 2 2 2 2 4 21
+ 7 7 15 15 15 15 12 4 5 5 0 0 21
+ 3 15 15 15 15 15 14 0 0 1 0 0 21
+ 15 15 15 12 15 15 12 0 2 2 2 0 21
+ SID recompute: 2
+ID efr-dtx.bin frame 0x43151
+0000ebe5cf36da92c6a086fffffc8000d68efffffe008056c07fffffe0008551fffcffe08005a2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE1
+ EFR frame:
+ LPC 30 109 212 148 26
+ 3 7 15 15 15 15 12 0 0 0 0 0 21
+ 7 7 15 15 15 15 12 0 0 0 0 0 21
+ 3 15 15 15 15 15 12 0 0 0 0 0 21
+ 15 15 15 12 15 15 12 0 0 0 0 0 21
+ SID recompute: 2
+ID efr-dtx.bin frame 0x431f1
+0000ebeccf36da92c6a086fffffcc340d68efffffe04d0d6c07fffffe0818551fffdffe0d84da2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 30 109 212 148 26
+ 3 7 15 15 15 15 12 4 1 5 0 0 21
+ 7 7 15 15 15 15 12 0 2 2 4 1 21
+ 3 15 15 15 15 15 12 0 4 0 2 0 21
+ 15 15 15 13 15 15 12 0 5 4 1 1 21
+ SID recompute: 2
+ID efr-dtx-dtmf.bin frame 0x4d471
+0000ebecd090a131e71086fffffca494ce8efffffe4ba04ec07ffffff00484d1fffcffe0a484e2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 33 32 265 142 28
+ 3 7 15 15 15 15 12 2 2 2 2 4 19
+ 7 7 15 15 15 15 12 4 5 5 0 0 19
+ 3 15 15 15 15 15 14 0 0 1 0 0 19
+ 15 15 15 12 15 15 12 0 2 2 2 0 19
+ SID recompute: 2
+ID efr-dtx-dtmf.bin frame 0x4d511
+0000ebe8c7e5a131e70da61ffffca494cc79fffffe4ba04d9214fffff00484c7fffcffe0a484feff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 15 202 265 142 28
+ 339 0 15 15 15 15 12 2 2 2 2 4 19
+ 60 15 15 15 15 15 12 4 5 5 0 0 19
+ 144 10 7 15 15 15 14 0 0 1 0 0 19
+ 63 15 15 12 15 15 12 0 2 2 2 0 19
+ SID recompute: 1
+ID efr-dtx-dtmf.bin frame 0x53a51
+0000ebead10eba68ada886f7fbfca494ca8cfffffe4ba04ac07ffffff0048491fffcffe0a485c2ff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 34 28 467 66 54
+ 3 7 11 15 11 15 12 2 2 2 2 4 18
+ 6 7 15 15 15 15 12 4 5 5 0 0 18
+ 3 15 15 15 15 15 14 0 0 1 0 0 18
+ 15 15 15 12 15 15 12 0 2 2 2 0 22
+ SID recompute: 1
+ID efr-dtx-dtmf.bin frame 0x53af1
+0000ebe8cf05b311adada617fbfca494c87afffffe4ba04ac214fffff00484affffcffe0a485deff
+ TRAU frame type: EFR
+ osmo_trau2rtp() result: 32
+ TW-TS-001 TEH octet: 0xE2
+ EFR frame:
+ LPC 30 10 408 138 54
+ 339 0 11 15 11 15 12 2 2 2 2 4 18
+ 61 7 15 15 15 15 12 4 5 5 0 0 18
+ 16 10 7 15 15 15 14 0 0 1 0 0 18
+ 63 15 15 12 15 15 12 0 2 2 2 0 22
+ SID recompute: 1
diff --git a/tests/trau_conv/trau16_fr.in b/tests/trau_conv/trau16_fr.in
new file mode 100644
index 0000000..2b3f20a
--- /dev/null
+++ b/tests/trau_conv/trau16_fr.in
@@ -0,0 +1,57 @@
+# This file is an input to trau16_to_rtp unit test program, containing
+# TRAU-16k Abis-UL frames for TCH/FS.
+#
+# All test frames presented here have been taken from these Abis E1 captures:
+#
+# https://osmocom.org/projects/retro-gsm/wiki/InSite_UL_captures
+#
+# The extraction of hex-encoded TRAU frames from E1 timeslot *.bin captures
+# was done with trau-parse program (-r option) developed in this repository:
+#
+# https://www.freecalypso.org/hg/gsm-net-reveng/
+
+# A few BFI frames from channel start-up
+
+ID fr1-dtx.bin frame 0x6ed1
+0000880885a5a009e1b8f6aaba318cb4f67fca1ac37fc94df1fba117e9e48c1bf5cff04ad135eeff
+ID fr1-dtx.bin frame 0x6f71
+000088088499e0ade1bcf769ba318cb4f64dcc9ac37fc94df4dda117e9e48c18f5d7f04ad135eeff
+ID fr1-dtx.bin frame 0x7011
+00008808f493a0ed81d7ef67cda2d099d74f89badd7ac666d9fef3d3fe9b9c758fa591d0d14886ff
+
+# BFI frame in TAF position
+
+ID fr1-dtx.bin frame 0x71f1
+00008809c6998721f08e995ac68aeb4db9efd0eece95b7749eeedfaefadea54f9bbbd65ba0a6deff
+
+# Some good speech frames
+
+ID fr1-dtx.bin frame 0x7511
+000088b0bd72ba9a94288012a492a492a2808124c924c9248710edb69468b5b5bc12a49ca685c6ff
+ID fr1-dtx.bin frame 0x75b1
+000088b08c0fce6ee368831ba4edd833a38f82e4e46b8eb8ec68eba1d3d29c8ec50b86139d8792ff
+ID fr1-dtx.bin frame 0x7651
+000088b0cc29bedc9c46a83ce650af55cee8c234e947943caa90ea92e2cecba6ed05e663b1cfb2ff
+
+# A good example of DTXu: SID frame not in TAF position, followed by one that
+# is in TAF position, followed by half-block BFI, followed by regular BFI.
+
+ID fr1-dtx.bin frame 0x8051
+000088b4b58ee6ee92008000800080008000800080008000800080008000800080008000800082ff
+ID fr1-dtx.bin frame 0x80f1
+000088b5b50ae6e6dc008000800080008000800080008000800080008000800080008000800082ff
+ID fr1-dtx.bin frame 0x8191
+000088bcf48ae6ee9c0080009240800180028000800280008000c9008024880080008248c02082ff
+ID fr1-dtx.bin frame 0x8231
+000088b8ce61b2b2c02d88cdc752c173890ef796f49ac82fd0e0a925e874d8c59751db08b9a1faff
+
+# A good speech frame in TAF position
+
+ID fr1-dtx.bin frame 0x8ff1
+000088b19cabee19a8569052aa16b922fa9a86ab97b38d46e990a5b9e5b1fc54e904de938adceaff
+
+# A BFI-no-data frame whose buffered bit content erroneously triggers
+# SID detection, but is marked as SID=0 in out-of-band flag bits
+
+ID fr1-dtx.bin frame 0x104d1
+000088b8ee49c3b2e00691e58000800080f1889fa000800086948004c8008000821b90009000caff
diff --git a/tests/trau_conv/trau16_fr_std.ok b/tests/trau_conv/trau16_fr_std.ok
new file mode 100644
index 0000000..584bade
--- /dev/null
+++ b/tests/trau_conv/trau16_fr_std.ok
@@ -0,0 +1,94 @@
+ID fr1-dtx.bin frame 0x6ed1
+0000880885a5a009e1b8f6aaba318cb4f67fca1ac37fc94df1fba117e9e48c1bf5cff04ad135eeff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 0
+ID fr1-dtx.bin frame 0x6f71
+000088088499e0ade1bcf769ba318cb4f64dcc9ac37fc94df4dda117e9e48c18f5d7f04ad135eeff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 0
+ID fr1-dtx.bin frame 0x7011
+00008808f493a0ed81d7ef67cda2d099d74f89badd7ac666d9fef3d3fe9b9c758fa591d0d14886ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 0
+ID fr1-dtx.bin frame 0x71f1
+00008809c6998721f08e995ac68aeb4db9efd0eece95b7749eeedfaefadea54f9bbbd65ba0a6deff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 0
+ID fr1-dtx.bin frame 0x7511
+000088b0bd72ba9a94288012a492a492a2808124c924c9248710edb69468b5b5bc12a49ca685c6ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 33
+ FR frame:
+ LARc 30 29 18 11 9 5 4 2
+ 40 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 4
+ 40 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 4
+ 64 3 0 2 3 3 3 3 3 4 2 4 5 0 6 2 3
+ 43 3 3 32 4 4 4 4 4 3 4 4 5 0 2 3 4
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x75b1
+000088b08c0fce6ee368831ba4edd833a38f82e4e46b8eb8ec68eba1d3d29c8ec50b86139d8792ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 33
+ FR frame:
+ LARc 24 32 15 14 6 7 3 4
+ 45 0 0 24 4 5 5 4 4 3 3 3 3 0 6 4 5
+ 56 0 3 3 2 7 4 4 1 1 6 2 3 4 3 5 3
+ 108 0 2 5 3 5 3 1 4 5 4 7 2 2 4 3 2
+ 92 0 2 2 5 1 4 1 4 4 1 7 6 0 6 1 1
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x7651
+000088b0cc29bedc9c46a83ce650af55cee8c234e947943caa90ea92e2cecba6ed05e663b1cfb2ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 33
+ FR frame:
+ LARc 25 40 20 15 11 3 4 3
+ 68 1 2 2 6 3 6 4 1 5 0 4 6 3 5 2 3
+ 110 1 1 4 2 4 5 4 5 4 2 4 3 2 1 4 7
+ 40 1 1 2 3 5 2 2 2 3 4 6 4 3 1 5 3
+ 89 1 3 2 2 7 4 1 3 4 5 1 6 1 7 5 1
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x8051
+000088b4b58ee6ee92008000800080008000800080008000800080008000800080008000800082ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 33
+ FR frame:
+ LARc 22 35 27 12 7 7 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ SID recompute: 2
+ID fr1-dtx.bin frame 0x80f1
+000088b5b50ae6e6dc008000800080008000800080008000800080008000800080008000800082ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 33
+ FR frame:
+ LARc 22 33 26 12 7 6 5 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ SID recompute: 2
+ID fr1-dtx.bin frame 0x8191
+000088bcf48ae6ee9c0080009240800180028000800280008000c9008024880080008248c02082ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 0
+ID fr1-dtx.bin frame 0x8231
+000088b8ce61b2b2c02d88cdc752c173890ef796f49ac82fd0e0a925e874d8c59751db08b9a1faff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 0
+ID fr1-dtx.bin frame 0x8ff1
+000088b19cabee19a8569052aa16b922fa9a86ab97b38d46e990a5b9e5b1fc54e904de938adceaff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 33
+ FR frame:
+ LARc 28 42 30 14 8 9 2 1
+ 84 1 0 1 5 4 4 2 1 4 6 4 3 2 2 4 6
+ 43 2 1 1 3 5 2 3 2 7 5 1 3 4 5 2 4
+ 45 2 1 2 2 2 3 7 4 3 2 3 3 4 7 3 4
+ 74 1 1 2 2 2 7 5 4 4 1 2 5 5 3 6 2
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x104d1
+000088b8ee49c3b2e00691e58000800080f1889fa000800086948004c8008000821b90009000caff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 0
diff --git a/tests/trau_conv/trau16_fr_twts001.ok b/tests/trau_conv/trau16_fr_twts001.ok
new file mode 100644
index 0000000..a26439b
--- /dev/null
+++ b/tests/trau_conv/trau16_fr_twts001.ok
@@ -0,0 +1,156 @@
+ID fr1-dtx.bin frame 0x6ed1
+0000880885a5a009e1b8f6aaba318cb4f67fca1ac37fc94df1fba117e9e48c1bf5cff04ad135eeff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE2
+ FR frame:
+ LARc 16 11 21 0 0 9 3 0
+ 59 0 3 45 2 5 4 3 1 6 0 1 6 4 6 2 6
+ 77 3 3 39 2 0 3 5 0 6 6 7 7 4 4 2 6
+ 30 2 3 55 2 0 1 2 7 3 1 7 1 1 0 3 0
+ 118 3 2 14 7 7 1 0 1 5 2 1 2 6 2 7 6
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x6f71
+000088088499e0ade1bcf769ba318cb4f64dcc9ac37fc94df4dda117e9e48c18f5d7f04ad135eeff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE2
+ FR frame:
+ LARc 16 50 28 0 5 11 3 0
+ 123 0 3 29 3 1 5 3 1 6 0 1 6 4 6 2 6
+ 77 0 3 38 1 1 3 5 0 6 6 7 7 4 4 2 6
+ 94 0 3 46 2 0 1 2 7 3 1 7 1 1 0 3 0
+ 70 3 2 46 6 7 1 0 1 5 2 1 2 6 2 7 6
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x7011
+00008808f493a0ed81d7ef67cda2d099d74f89badd7ac666d9fef3d3fe9b9c758fa591d0d14886ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE2
+ FR frame:
+ LARc 23 18 22 0 7 11 0 0
+ 87 3 3 30 3 6 3 6 6 2 4 2 1 4 4 1 3
+ 93 0 3 35 4 5 3 5 6 5 6 3 5 0 3 6 4
+ 53 2 3 31 7 4 7 2 6 7 7 2 6 6 4 3 4
+ 43 0 3 23 2 1 1 6 5 0 2 1 2 1 1 0 4
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x71f1
+00008809c6998721f08e995ac68aeb4db9efd0eece95b7749eeedfaefadea54f9bbbd65ba0a6deff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE3
+ FR frame:
+ LARc 49 50 4 28 4 8 7 0
+ 98 1 0 19 5 5 2 4 5 0 5 6 2 3 1 3 5
+ 115 1 3 23 0 7 6 5 4 3 1 5 2 3 7 6 5
+ 112 1 3 29 5 7 3 5 3 7 5 6 6 3 2 2 5
+ 60 2 1 55 5 3 5 1 5 5 5 0 4 2 6 2 7
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x7511
+000088b0bd72ba9a94288012a492a492a2808124c924c9248710edb69468b5b5bc12a49ca685c6ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE0
+ FR frame:
+ LARc 30 29 18 11 9 5 4 2
+ 40 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 4
+ 40 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 4
+ 64 3 0 2 3 3 3 3 3 4 2 4 5 0 6 2 3
+ 43 3 3 32 4 4 4 4 4 3 4 4 5 0 2 3 4
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x75b1
+000088b08c0fce6ee368831ba4edd833a38f82e4e46b8eb8ec68eba1d3d29c8ec50b86139d8792ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE0
+ FR frame:
+ LARc 24 32 15 14 6 7 3 4
+ 45 0 0 24 4 5 5 4 4 3 3 3 3 0 6 4 5
+ 56 0 3 3 2 7 4 4 1 1 6 2 3 4 3 5 3
+ 108 0 2 5 3 5 3 1 4 5 4 7 2 2 4 3 2
+ 92 0 2 2 5 1 4 1 4 4 1 7 6 0 6 1 1
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x7651
+000088b0cc29bedc9c46a83ce650af55cee8c234e947943caa90ea92e2cecba6ed05e663b1cfb2ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE0
+ FR frame:
+ LARc 25 40 20 15 11 3 4 3
+ 68 1 2 2 6 3 6 4 1 5 0 4 6 3 5 2 3
+ 110 1 1 4 2 4 5 4 5 4 2 4 3 2 1 4 7
+ 40 1 1 2 3 5 2 2 2 3 4 6 4 3 1 5 3
+ 89 1 3 2 2 7 4 1 3 4 5 1 6 1 7 5 1
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x8051
+000088b4b58ee6ee92008000800080008000800080008000800080008000800080008000800082ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE0
+ FR frame:
+ LARc 22 35 27 12 7 7 4 4
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ SID recompute: 2
+ID fr1-dtx.bin frame 0x80f1
+000088b5b50ae6e6dc008000800080008000800080008000800080008000800080008000800082ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE1
+ FR frame:
+ LARc 22 33 26 12 7 6 5 3
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ SID recompute: 2
+ID fr1-dtx.bin frame 0x8191
+000088bcf48ae6ee9c0080009240800180028000800280008000c9008024880080008248c02082ff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE2
+ FR frame:
+ LARc 23 34 26 12 7 7 4 3
+ 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1
+ 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0
+ 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 1 0
+ 0 0 0 0 0 0 0 1 1 1 2 0 0 2 0 0 0
+ SID recompute: 2
+ID fr1-dtx.bin frame 0x8231
+000088b8ce61b2b2c02d88cdc752c173890ef796f49ac82fd0e0a925e874d8c59751db08b9a1faff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE2
+ FR frame:
+ LARc 57 12 20 9 13 4 1 0
+ 104 2 0 34 1 3 3 4 3 5 4 2 0 2 7 4 1
+ 18 0 3 29 7 1 5 5 3 1 1 3 5 4 0 4 6
+ 23 0 3 1 2 1 1 1 5 3 1 4 3 1 5 1 6
+ 40 2 2 43 0 3 3 3 0 1 4 3 6 2 0 7 3
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x8ff1
+000088b19cabee19a8569052aa16b922fa9a86ab97b38d46e990a5b9e5b1fc54e904de938adceaff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE1
+ FR frame:
+ LARc 28 42 30 14 8 9 2 1
+ 84 1 0 1 5 4 4 2 1 4 6 4 3 2 2 4 6
+ 43 2 1 1 3 5 2 3 2 7 5 1 3 4 5 2 4
+ 45 2 1 2 2 2 3 7 4 3 2 3 3 4 7 3 4
+ 74 1 1 2 2 2 7 5 4 4 1 2 5 5 3 6 2
+ SID recompute: 0
+ID fr1-dtx.bin frame 0x104d1
+000088b8ee49c3b2e00691e58000800080f1889fa000800086948004c8008000821b90009000caff
+ TRAU frame type: FR
+ osmo_trau2rtp() result: 34
+ TW-TS-001 TEH octet: 0xE2
+ FR frame:
+ LARc 59 36 12 24 13 4 3 0
+ 64 1 0 49 3 2 1 0 0 0 0 0 0 0 0 0 0
+ 96 3 0 34 0 1 7 3 1 0 0 0 0 0 0 0 0
+ 64 1 1 10 0 0 0 0 1 1 1 0 0 0 0 0 0
+ 0 0 0 33 5 1 1 0 0 0 0 1 0 0 0 2 2
+ SID recompute: 1
diff --git a/tests/trau_conv/trau16_to_rtp.c b/tests/trau_conv/trau16_to_rtp.c
new file mode 100644
index 0000000..9884e89
--- /dev/null
+++ b/tests/trau_conv/trau16_to_rtp.c
@@ -0,0 +1,405 @@
+/*
+ * This program is a libosmotrau unit test for osmo_trau_frame_decode_16k()
+ * and osmo_trau2rtp() functions. It reads input in the form of hex lines,
+ * with each line representing a TRAU-16k frame as a string of 80 hex digits.
+ * For each test frame thus read, we first call osmo_trau_frame_decode_16k()
+ * and print the frame type decoded by that function. We then call
+ * osmo_trau2rtp() and report its integer result, as in length of returned
+ * RTP payload or error code. Finally, for known frame types (initially
+ * FR and EFR speech) we break the RTP payload into an array of codec
+ * parameters and print them out in the same format as used in Themyscira
+ * Wireless GSM codec libraries and utilities.
+ *
+ * Author: Mychaela N. Falconia <falcon@freecalypso.org>, 2024 - however,
+ * Mother Mychaela's contributions are NOT subject to copyright.
+ * No rights reserved, all rights relinquished.
+ *
+ * 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.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/codec/codec.h>
+#include <osmocom/trau/trau_frame.h>
+#include <osmocom/trau/trau_rtp.h>
+#include <osmocom/gsm/rtp_extensions.h>
+
+static enum osmo_trau_frame_direction direction;
+static struct osmo_trau2rtp_state trau2rtp_st;
+
+/*
+ * The following function has been copied from Themyscira libgsmfr2 -
+ * but it is mostly generated code, produced with 'sweet' utility
+ * from classic libgsm source.
+ */
+static void gsmfr_unpack_to_array(const uint8_t *frame, int16_t *params)
+{
+ const uint8_t *c = frame;
+ unsigned sub;
+
+ params[0] = (*c++ & 0xF) << 2;
+ params[0] |= (*c >> 6) & 0x3;
+ params[1] = *c++ & 0x3F;
+ params[2] = (*c >> 3) & 0x1F;
+ params[3] = (*c++ & 0x7) << 2;
+ params[3] |= (*c >> 6) & 0x3;
+ params[4] = (*c >> 2) & 0xF;
+ params[5] = (*c++ & 0x3) << 2;
+ params[5] |= (*c >> 6) & 0x3;
+ params[6] = (*c >> 3) & 0x7;
+ params[7] = *c++ & 0x7;
+ params += 8;
+ for (sub = 0; sub < 4; sub++) {
+ params[0] = (*c >> 1) & 0x7F;
+ params[1] = (*c++ & 0x1) << 1;
+ params[1] |= (*c >> 7) & 0x1;
+ params[2] = (*c >> 5) & 0x3;
+ params[3] = (*c++ & 0x1F) << 1;
+ params[3] |= (*c >> 7) & 0x1;
+ params[4] = (*c >> 4) & 0x7;
+ params[5] = (*c >> 1) & 0x7;
+ params[6] = (*c++ & 0x1) << 2;
+ params[6] |= (*c >> 6) & 0x3;
+ params[7] = (*c >> 3) & 0x7;
+ params[8] = *c++ & 0x7;
+ params[9] = (*c >> 5) & 0x7;
+ params[10] = (*c >> 2) & 0x7;
+ params[11] = (*c++ & 0x3) << 1;
+ params[11] |= (*c >> 7) & 0x1;
+ params[12] = (*c >> 4) & 0x7;
+ params[13] = (*c >> 1) & 0x7;
+ params[14] = (*c++ & 0x1) << 2;
+ params[14] |= (*c >> 6) & 0x3;
+ params[15] = (*c >> 3) & 0x7;
+ params[16] = *c++ & 0x7;
+ params += 17;
+ }
+}
+
+/*
+ * The following function has been copied from Themyscira libgsmefr -
+ * but it is mostly generated code, produced with 'sweet' utility
+ * from classic libgsm source.
+ */
+static void EFR_frame2params(const uint8_t *frame, int16_t *params)
+{
+ const uint8_t *c = frame;
+
+ /* EFR_MAGIC = (*c >> 4) & 0xF; */
+ params[0] = (*c++ & 0xF) << 3;
+ params[0] |= (*c >> 5) & 0x7;
+ params[1] = (*c++ & 0x1F) << 3;
+ params[1] |= (*c >> 5) & 0x7;
+ params[2] = (*c++ & 0x1F) << 4;
+ params[2] |= (*c >> 4) & 0xF;
+ params[3] = (*c++ & 0xF) << 4;
+ params[3] |= (*c >> 4) & 0xF;
+ params[4] = (*c++ & 0xF) << 2;
+ params[4] |= (*c >> 6) & 0x3;
+ params[5] = (*c++ & 0x3F) << 3;
+ params[5] |= (*c >> 5) & 0x7;
+ params[6] = (*c >> 1) & 0xF;
+ params[7] = (*c++ & 0x1) << 3;
+ params[7] |= (*c >> 5) & 0x7;
+ params[8] = (*c >> 1) & 0xF;
+ params[9] = (*c++ & 0x1) << 3;
+ params[9] |= (*c >> 5) & 0x7;
+ params[10] = (*c >> 1) & 0xF;
+ params[11] = (*c++ & 0x1) << 3;
+ params[11] |= (*c >> 5) & 0x7;
+ params[12] = (*c >> 2) & 0x7;
+ params[13] = (*c++ & 0x3) << 1;
+ params[13] |= (*c >> 7) & 0x1;
+ params[14] = (*c >> 4) & 0x7;
+ params[15] = (*c >> 1) & 0x7;
+ params[16] = (*c++ & 0x1) << 2;
+ params[16] |= (*c >> 6) & 0x3;
+ params[17] = (*c >> 1) & 0x1F;
+ params[18] = (*c++ & 0x1) << 5;
+ params[18] |= (*c >> 3) & 0x1F;
+ params[19] = (*c++ & 0x7) << 1;
+ params[19] |= (*c >> 7) & 0x1;
+ params[20] = (*c >> 3) & 0xF;
+ params[21] = (*c++ & 0x7) << 1;
+ params[21] |= (*c >> 7) & 0x1;
+ params[22] = (*c >> 3) & 0xF;
+ params[23] = (*c++ & 0x7) << 1;
+ params[23] |= (*c >> 7) & 0x1;
+ params[24] = (*c >> 3) & 0xF;
+ params[25] = *c++ & 0x7;
+ params[26] = (*c >> 5) & 0x7;
+ params[27] = (*c >> 2) & 0x7;
+ params[28] = (*c++ & 0x3) << 1;
+ params[28] |= (*c >> 7) & 0x1;
+ params[29] = (*c >> 4) & 0x7;
+ params[30] = (*c++ & 0xF) << 1;
+ params[30] |= (*c >> 7) & 0x1;
+ params[31] = (*c++ & 0x7F) << 2;
+ params[31] |= (*c >> 6) & 0x3;
+ params[32] = (*c >> 2) & 0xF;
+ params[33] = (*c++ & 0x3) << 2;
+ params[33] |= (*c >> 6) & 0x3;
+ params[34] = (*c >> 2) & 0xF;
+ params[35] = (*c++ & 0x3) << 2;
+ params[35] |= (*c >> 6) & 0x3;
+ params[36] = (*c >> 2) & 0xF;
+ params[37] = (*c++ & 0x3) << 2;
+ params[37] |= (*c >> 6) & 0x3;
+ params[38] = (*c >> 3) & 0x7;
+ params[39] = *c++ & 0x7;
+ params[40] = (*c >> 5) & 0x7;
+ params[41] = (*c >> 2) & 0x7;
+ params[42] = (*c++ & 0x3) << 1;
+ params[42] |= (*c >> 7) & 0x1;
+ params[43] = (*c >> 2) & 0x1F;
+ params[44] = (*c++ & 0x3) << 4;
+ params[44] |= (*c >> 4) & 0xF;
+ params[45] = *c++ & 0xF;
+ params[46] = (*c >> 4) & 0xF;
+ params[47] = *c++ & 0xF;
+ params[48] = (*c >> 4) & 0xF;
+ params[49] = *c++ & 0xF;
+ params[50] = (*c >> 4) & 0xF;
+ params[51] = (*c >> 1) & 0x7;
+ params[52] = (*c++ & 0x1) << 2;
+ params[52] |= (*c >> 6) & 0x3;
+ params[53] = (*c >> 3) & 0x7;
+ params[54] = *c++ & 0x7;
+ params[55] = (*c >> 5) & 0x7;
+ params[56] = *c++ & 0x1F;
+}
+
+static void decode_fr(const uint8_t *rtp_pl, int conv_result)
+{
+ int16_t params[76];
+ int i, j, p;
+
+ if (conv_result <= 0)
+ return;
+ switch (conv_result) {
+ case 1:
+ /* The only valid 1-byte payload is TEH by itself
+ * in the case of TW-TS-001 output. */
+ if ((rtp_pl[0] & 0xF0) != 0xE0)
+ goto inv_payload;
+ printf(" TW-TS-001 TEH octet: 0x%02X\n", rtp_pl[0]);
+ return;
+ case GSM_FR_BYTES:
+ if ((rtp_pl[0] & 0xF0) != 0xD0)
+ goto inv_payload;
+ /* standard FR payload without TW-TS-001 */
+ break;
+ case GSM_FR_BYTES+1:
+ if ((rtp_pl[0] & 0xF0) != 0xE0)
+ goto inv_payload;
+ if ((rtp_pl[1] & 0xF0) != 0xD0)
+ goto inv_payload;
+ /* TW-TS-001 extended RTP payload for FR */
+ printf(" TW-TS-001 TEH octet: 0x%02X\n", rtp_pl[0]);
+ rtp_pl++;
+ break;
+ default:
+ goto inv_payload;
+ }
+
+ printf(" FR frame:\n");
+ gsmfr_unpack_to_array(rtp_pl, params);
+ /* print frame in the same format as used in ThemWi tools */
+ p = 0;
+ printf(" LARc");
+ for (i = 0; i < 8; i++)
+ printf(" %d", params[p++]);
+ putchar('\n');
+ for (i = 0; i < 4; i++) {
+ printf(" ");
+ for (j = 0; j < 17; j++)
+ printf(" %d", params[p++]);
+ putchar('\n');
+ }
+ printf(" SID recompute: %d\n", (int) osmo_fr_sid_classify(rtp_pl));
+ return;
+
+inv_payload:
+ printf(" Error: conversion result is not a valid FR payload\n");
+}
+
+static void decode_efr(const uint8_t *rtp_pl, int conv_result)
+{
+ int16_t params[57];
+ int i, j, p;
+
+ if (conv_result <= 0)
+ return;
+ switch (conv_result) {
+ case 1:
+ /* The only valid 1-byte payload is TEH by itself
+ * in the case of TW-TS-001 output. */
+ if ((rtp_pl[0] & 0xF0) != 0xE0)
+ goto inv_payload;
+ printf(" TW-TS-001 TEH octet: 0x%02X\n", rtp_pl[0]);
+ return;
+ case GSM_EFR_BYTES:
+ if ((rtp_pl[0] & 0xF0) != 0xC0)
+ goto inv_payload;
+ /* standard EFR payload without TW-TS-001 */
+ break;
+ case GSM_EFR_BYTES+1:
+ if ((rtp_pl[0] & 0xF0) != 0xE0)
+ goto inv_payload;
+ if ((rtp_pl[1] & 0xF0) != 0xC0)
+ goto inv_payload;
+ /* TW-TS-001 extended RTP payload for EFR */
+ printf(" TW-TS-001 TEH octet: 0x%02X\n", rtp_pl[0]);
+ rtp_pl++;
+ break;
+ default:
+ goto inv_payload;
+ }
+
+ printf(" EFR frame:\n");
+ EFR_frame2params(rtp_pl, params);
+ /* print frame in the same format as used in ThemWi tools */
+ p = 0;
+ printf(" LPC");
+ for (i = 0; i < 5; i++)
+ printf(" %d", params[p++]);
+ putchar('\n');
+ for (i = 0; i < 4; i++) {
+ printf(" ");
+ for (j = 0; j < 13; j++)
+ printf(" %d", params[p++]);
+ putchar('\n');
+ }
+ printf(" SID recompute: %d\n", (int) osmo_efr_sid_classify(rtp_pl));
+ return;
+
+inv_payload:
+ printf(" Error: conversion result is not a valid EFR payload\n");
+}
+
+static void process_record(const char *hex_str)
+{
+ uint8_t input_bytes[40];
+ ubit_t trau_bits[320];
+ struct osmo_trau_frame tf;
+ uint8_t rtp_pl[160]; /* maximum length for CSD */
+ int decode_result, conv_result;
+
+ /* In the output, we reprint each input line followed by
+ * our analysis thereof. */
+ printf("%s\n", hex_str);
+ osmo_hexparse(hex_str, input_bytes, sizeof(input_bytes));
+ osmo_pbit2ubit(trau_bits, input_bytes, sizeof(trau_bits));
+ decode_result = osmo_trau_frame_decode_16k(&tf, trau_bits, direction);
+ if (decode_result < 0) {
+ printf(" osmo_trau_frame_decode_16k() returned %d\n",
+ decode_result);
+ return;
+ }
+ printf(" TRAU frame type: %s\n", osmo_trau_frame_type_name(tf.type));
+ trau2rtp_st.type = tf.type;
+ conv_result = osmo_trau2rtp(rtp_pl, sizeof(rtp_pl), &tf, &trau2rtp_st);
+ printf(" osmo_trau2rtp() result: %d\n", conv_result);
+ /* additional decoding for specific frame types */
+ switch (tf.type) {
+ case OSMO_TRAU16_FT_FR:
+ decode_fr(rtp_pl, conv_result);
+ break;
+ case OSMO_TRAU16_FT_EFR:
+ decode_efr(rtp_pl, conv_result);
+ break;
+ default:
+ break; /* do nothing */
+ }
+}
+
+static void process_line(char *linebuf, const char *infname, int lineno)
+{
+ char *cp = linebuf, *hex_str;
+ int ndig;
+
+ while (isspace(*cp))
+ cp++;
+ if (*cp == '\0' || *cp == '#')
+ return;
+ /* pass ID lines through to output */
+ if (!strncmp(cp, "ID", 2)) {
+ fputs(cp, stdout);
+ return;
+ }
+ /* expect string of 80 hex digits */
+ hex_str = cp;
+ for (ndig = 0; ndig < 80; ndig++) {
+ if (!isxdigit(*cp))
+ goto inv;
+ cp++;
+ }
+ if (*cp) {
+ if (!isspace(*cp))
+ goto inv;
+ *cp++ = '\0';
+ }
+ /* must be end of non-comment line */
+ while (isspace(*cp))
+ cp++;
+ if (*cp != '\0' && *cp != '#')
+ goto inv;
+
+ process_record(hex_str);
+ return;
+
+inv: fprintf(stderr, "%s line %d: invalid syntax\n", infname, lineno);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ const char *infname;
+ FILE *inf;
+ char linebuf[256];
+ int lineno;
+
+ if (argc != 4)
+ goto usage;
+ infname = argv[1];
+ inf = fopen(infname, "r");
+ if (!inf) {
+ perror(infname);
+ exit(1);
+ }
+ if (!strcmp(argv[2], "ul"))
+ direction = OSMO_TRAU_DIR_UL;
+ else if (!strcmp(argv[2], "dl"))
+ direction = OSMO_TRAU_DIR_DL;
+ else
+ goto usage;
+ if (!strcmp(argv[3], "std"))
+ trau2rtp_st.rtp_extensions = 0;
+ else if (!strcmp(argv[3], "tw-ts-001"))
+ trau2rtp_st.rtp_extensions = OSMO_RTP_EXT_TWTS001;
+ else
+ goto usage;
+
+ for (lineno = 1; fgets(linebuf, sizeof(linebuf), inf); lineno++)
+ process_line(linebuf, infname, lineno);
+ fclose(inf);
+ exit(0);
+
+usage: fprintf(stderr, "usage: %s input-file ul|dl std|tw-ts-001\n", argv[0]);
+ exit(1);
+}
To view, visit change 38139. To unsubscribe, or for help writing mail filters, visit settings.