diff --git a/.gitignore b/.gitignore index bf0f844c7..34d55b8ec 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ src/osmo-bts-oc2g/misc/.dirstamp tests/atconfig tests/package.m4 tests/amr/amr_test +tests/csd/csd_test tests/agch/agch_test tests/paging/paging_test tests/cipher/cipher_test diff --git a/configure.ac b/configure.ac index 82074d46c..b2b651aee 100644 --- a/configure.ac +++ b/configure.ac @@ -445,6 +445,7 @@ AC_OUTPUT( tests/power/Makefile tests/meas/Makefile tests/amr/Makefile + tests/csd/Makefile doc/Makefile doc/examples/Makefile doc/manuals/Makefile diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index 0b4058d2e..cbd0fc37a 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -24,6 +24,7 @@ noinst_HEADERS = \ tx_power.h \ control_if.h \ cbch.h \ + csd_v110.h \ l1sap.h \ lchan.h \ power_control.h \ diff --git a/include/osmo-bts/csd_v110.h b/include/osmo-bts/csd_v110.h new file mode 100644 index 000000000..f6be0ae2b --- /dev/null +++ b/include/osmo-bts/csd_v110.h @@ -0,0 +1,23 @@ +#pragma once + +/* RFC4040 "clearmode" RTP payload length */ +#define RFC4040_RTP_PLEN 160 + +struct gsm_lchan; + +struct csd_v110_frame_desc { + uint16_t num_blocks; + uint16_t num_bits; +}; + +struct csd_v110_lchan_desc { + struct csd_v110_frame_desc fr; + struct csd_v110_frame_desc hr; +}; + +extern const struct csd_v110_lchan_desc csd_v110_lchan_desc[256]; + +int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp, + const uint8_t *data, size_t data_len); +int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data, + const uint8_t *rtp, size_t rtp_len); diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 5cd7909e1..d13415d15 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -51,6 +51,7 @@ libbts_a_SOURCES = \ bts_ctrl_commands.c \ bts_ctrl_lookup.c \ bts_shutdown_fsm.c \ + csd_v110.c \ l1sap.c \ cbch.c \ power_control.c \ diff --git a/src/common/bts.c b/src/common/bts.c index 7257f37b2..1f0040c44 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -875,7 +875,7 @@ static bool bts_supports_cm_data(const struct gsm_bts *bts, switch (bts->variant) { case BTS_OSMO_TRX: switch (cm->chan_rate) { - case RSL_CMOD_CSD_T_14k4: + /* TODO: RSL_CMOD_CSD_T_14k4 */ case RSL_CMOD_CSD_T_9k6: if (cm->chan_rt != RSL_CMOD_CRT_TCH_Bm) return false; /* invalid */ diff --git a/src/common/csd_v110.c b/src/common/csd_v110.c new file mode 100644 index 000000000..6800761eb --- /dev/null +++ b/src/common/csd_v110.c @@ -0,0 +1,157 @@ +/* + * (C) 2023 by sysmocom - s.f.m.c. GmbH + * Author: Vadim Yanitskiy + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* key is enum gsm48_chan_mode, so assuming a value in range 0..255 */ +const struct csd_v110_lchan_desc csd_v110_lchan_desc[256] = { +#if 0 + [GSM48_CMODE_DATA_14k5] = { + /* TCH/F14.4: 290 bits every 20 ms (14.5 kbit/s) */ + .fr = { .num_blocks = 1, .num_bits = 290 }, + }, +#endif + [GSM48_CMODE_DATA_12k0] = { + /* TCH/F9.6: 4 * 60 bits every 20 ms (12.0 kbit/s) */ + .fr = { .num_blocks = 4, .num_bits = 60 }, + }, + [GSM48_CMODE_DATA_6k0] = { + /* TCH/F4.8: 2 * 60 bits every 20 ms (6.0 kbit/s) */ + .fr = { .num_blocks = 2, .num_bits = 60 }, + /* TCH/H4.8: 4 * 60 bits every 40 ms (6.0 kbit/s) */ + .hr = { .num_blocks = 4, .num_bits = 60 }, + }, + [GSM48_CMODE_DATA_3k6] = { + /* TCH/F2.4: 2 * 36 bits every 20 ms (3.6 kbit/s) */ + .fr = { .num_blocks = 2, .num_bits = 36 }, + /* TCH/H2.4: 4 * 36 bits every 40 ms (3.6 kbit/s) */ + .hr = { .num_blocks = 4, .num_bits = 36 }, + }, +}; + +int csd_v110_rtp_encode(const struct gsm_lchan *lchan, uint8_t *rtp, + const uint8_t *data, size_t data_len) +{ + const struct csd_v110_frame_desc *desc; + ubit_t ra_bits[80 * 4]; + + OSMO_ASSERT(lchan->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc)); + if (lchan->type == GSM_LCHAN_TCH_F) + desc = &csd_v110_lchan_desc[lchan->tch_mode].fr; + else + desc = &csd_v110_lchan_desc[lchan->tch_mode].hr; + if (OSMO_UNLIKELY(desc->num_blocks == 0)) + return -ENOTSUP; + + /* handle empty/incomplete frames gracefully */ + if (OSMO_UNLIKELY(data_len < (desc->num_blocks * desc->num_bits))) + return -ENODATA; + + /* RA1'/RA1: convert to an intermediate data rate */ + for (unsigned int i = 0; i < desc->num_blocks; i++) { + struct osmo_v110_decoded_frame df; + + /* convert modified V.110 frames to normal V.110 frames */ + if (desc->num_bits == 60) + osmo_csd_12k_6k_decode_frame(&df, &data[i * 60], 60); + else /* desc->num_bits == 36 */ + osmo_csd_3k6_decode_frame(&df, &data[i * 36], 36); + + /* FIXME: E1 .. E3 must be set by out-of-band knowledge! */ + memset(&df.e_bits[0], 0, 3); + + osmo_v110_encode_frame(&ra_bits[i * 80], 80, &df); + } + + /* RA1/RA2: convert from an intermediate rate to 64 kbit/s */ + if (desc->num_blocks == 4) { + /* 4 * 80 bits (16 kbit/s) => 2 bits per octet */ + for (unsigned int i = 0, j = 0; i < RFC4040_RTP_PLEN; i++) { + rtp[i] = (0xff >> 2); + rtp[i] |= (ra_bits[j++] << 7); + rtp[i] |= (ra_bits[j++] << 6); + } + } else { + /* 2 * 80 bits (8 kbit/s) => 1 bit per octet */ + for (unsigned int i = 0; i < RFC4040_RTP_PLEN; i++) { + rtp[i] = (0xff >> 1); + rtp[i] |= (ra_bits[i] << 7); + } + } + + return RFC4040_RTP_PLEN; +} + +int csd_v110_rtp_decode(const struct gsm_lchan *lchan, uint8_t *data, + const uint8_t *rtp, size_t rtp_len) +{ + const struct csd_v110_frame_desc *desc; + ubit_t ra_bits[80 * 4]; + + OSMO_ASSERT(lchan->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc)); + if (lchan->type == GSM_LCHAN_TCH_F) + desc = &csd_v110_lchan_desc[lchan->tch_mode].fr; + else + desc = &csd_v110_lchan_desc[lchan->tch_mode].hr; + if (OSMO_UNLIKELY(desc->num_blocks == 0)) + return -ENOTSUP; + + if (OSMO_UNLIKELY(rtp_len != RFC4040_RTP_PLEN)) + return -EINVAL; + + /* RA1/RA2: convert from 64 kbit/s to an intermediate rate */ + if (desc->num_blocks == 4) { + /* 4 * 80 bits (16 kbit/s) => 2 bits per octet */ + for (unsigned int i = 0, j = 0; i < RFC4040_RTP_PLEN; i++) { + ra_bits[j++] = (rtp[i] >> 7); + ra_bits[j++] = (rtp[i] >> 6) & 0x01; + } + } else { + /* 2 * 80 bits (8 kbit/s) => 1 bit per octet */ + for (unsigned int i = 0; i < RFC4040_RTP_PLEN; i++) + ra_bits[i] = (rtp[i] >> 7); + } + + /* RA1'/RA1: convert to an intermediate data rate */ + for (unsigned int i = 0; i < desc->num_blocks; i++) { + struct osmo_v110_decoded_frame df; + + /* convert modified V.110 frames to normal V.110 frames */ + osmo_v110_decode_frame(&df, &ra_bits[i * 80], 80); + if (desc->num_bits == 60) + osmo_csd_12k_6k_encode_frame(&data[i * 60], 60, &df); + else /* desc->num_bits == 36 */ + osmo_csd_3k6_encode_frame(&data[i * 36], 36, &df); + } + + return desc->num_blocks * desc->num_bits; +} diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 61fb3ee78..13d271eab 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -58,6 +58,7 @@ #include #include #include +#include /* determine the CCCH block number based on the frame number */ unsigned int l1sap_fn2ccch_block(uint32_t fn) @@ -1829,9 +1830,27 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, return 1; } +static void send_ul_rtp_packet_data(struct gsm_lchan *lchan, uint32_t fn, + const uint8_t *data, uint16_t data_len) +{ + uint8_t rtp_pl[RFC4040_RTP_PLEN]; + int rc; + + rc = csd_v110_rtp_encode(lchan, &rtp_pl[0], data, data_len); + if (rc < 0) + return; + + osmo_rtp_send_frame_ext(lchan->abis_ip.rtp_socket, + &rtp_pl[0], sizeof(rtp_pl), + fn_ms_adj(fn, lchan), + lchan->rtp_tx_marker); + /* Only clear the marker bit once we have sent a RTP packet with it */ + lchan->rtp_tx_marker = false; +} + /* a helper function for the logic in l1sap_tch_ind() */ -static void send_ul_rtp_packet(struct gsm_lchan *lchan, uint32_t fn, - const uint8_t *rtp_pl, uint16_t rtp_pl_len) +static void send_ul_rtp_packet_speech(struct gsm_lchan *lchan, uint32_t fn, + const uint8_t *rtp_pl, uint16_t rtp_pl_len) { if (lchan->abis_ip.osmux.use) { lchan_osmux_send_frame(lchan, rtp_pl, rtp_pl_len, @@ -1859,7 +1878,7 @@ static void send_rtp_rfc5993(struct gsm_lchan *lchan, uint32_t fn, else toc = 0x00; msgb_push_u8(msg, toc); - send_ul_rtp_packet(lchan, fn, msg->data, msg->len); + send_ul_rtp_packet_speech(lchan, fn, msg->data, msg->len); } /* A helper function for l1sap_tch_ind(): handling BFI @@ -1884,7 +1903,7 @@ static void tch_ul_bfi_handler(struct gsm_lchan *lchan, /* did it actually give us some output? */ if (rc > 0) { /* yes, send it out in RTP */ - send_ul_rtp_packet(lchan, fn, ecu_out, rc); + send_ul_rtp_packet_speech(lchan, fn, ecu_out, rc); return; } } @@ -1892,7 +1911,7 @@ static void tch_ul_bfi_handler(struct gsm_lchan *lchan, /* Are we in rtp continuous-streaming special mode? If so, send out * a BFI packet as zero-length RTP payload. */ if (lchan->ts->trx->bts->rtp_nogaps_mode) { - send_ul_rtp_packet(lchan, fn, NULL, 0); + send_ul_rtp_packet_speech(lchan, fn, NULL, 0); return; } @@ -1948,11 +1967,21 @@ static int l1sap_tch_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, if (lchan->ecu_state) osmo_ecu_frame_in(lchan->ecu_state, false, msg->data, msg->len); /* hand msg to RTP code for transmission */ - if (bts->emit_hr_rfc5993 && lchan->type == GSM_LCHAN_TCH_H && - lchan->tch_mode == GSM48_CMODE_SPEECH_V1) - send_rtp_rfc5993(lchan, fn, msg); - else - send_ul_rtp_packet(lchan, fn, msg->data, msg->len); + switch (lchan->rsl_cmode) { + case RSL_CMOD_SPD_SPEECH: + if (bts->emit_hr_rfc5993 && lchan->type == GSM_LCHAN_TCH_H && + lchan->tch_mode == GSM48_CMODE_SPEECH_V1) + send_rtp_rfc5993(lchan, fn, msg); + else + send_ul_rtp_packet_speech(lchan, fn, msg->data, msg->len); + break; + case RSL_CMOD_SPD_DATA: + send_ul_rtp_packet_data(lchan, fn, msg->data, msg->len); + break; + case RSL_CMOD_SPD_SIGN: + default: /* shall not happen */ + OSMO_ASSERT(0); + } /* if loopback is enabled, also queue received RTP data */ if (lchan->loopback) { /* add new frame to queue, make sure the queue doesn't get too long */ @@ -2247,10 +2276,23 @@ void l1sap_rtp_rx_cb(struct osmo_rtp_socket *rs, const uint8_t *rtp_pl, OSMO_ASSERT(0); } - msg = l1sap_msgb_alloc(rtp_pl_len); + msg = l1sap_msgb_alloc(512); if (!msg) return; - memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len); + + if (lchan->rsl_cmode == RSL_CMOD_SPD_DATA) { + int rc = csd_v110_rtp_decode(lchan, msg->tail, + rtp_pl, rtp_pl_len); + if (rc > 0) { + msgb_put(msg, rc); + } else { + msgb_free(msg); + return; + } + } else { + memcpy(msgb_put(msg, rtp_pl_len), rtp_pl, rtp_pl_len); + } + msgb_pull(msg, sizeof(struct osmo_phsap_prim)); /* Store RTP header Marker bit in control buffer */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 100c5d487..8d175be89 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = paging cipher agch misc handover tx_power power meas ta_control amr +SUBDIRS = paging cipher agch misc handover tx_power power meas ta_control amr csd if ENABLE_SYSMOBTS SUBDIRS += sysmobts diff --git a/tests/csd/Makefile.am b/tests/csd/Makefile.am new file mode 100644 index 000000000..2041dd7de --- /dev/null +++ b/tests/csd/Makefile.am @@ -0,0 +1,25 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS = \ + -Wall \ + $(LIBOSMOCORE_CFLAGS) \ + $(LIBOSMOGSM_CFLAGS) \ + $(LIBOSMOCODEC_CFLAGS) \ + $(LIBOSMOABIS_CFLAGS) \ + $(LIBOSMOTRAU_CFLAGS) \ + $(LIBOSMONETIF_CFLAGS) \ + $(NULL) +AM_LDFLAGS = -no-install +LDADD = \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCODEC_LIBS) \ + $(LIBOSMOTRAU_LIBS) \ + $(LIBOSMOABIS_LIBS) \ + $(LIBOSMONETIF_LIBS) \ + $(NULL) + +check_PROGRAMS = csd_test +EXTRA_DIST = csd_test.err + +csd_test_SOURCES = csd_test.c +csd_test_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD) diff --git a/tests/csd/csd_test.c b/tests/csd/csd_test.c new file mode 100644 index 000000000..16995b1b2 --- /dev/null +++ b/tests/csd/csd_test.c @@ -0,0 +1,138 @@ +/* + * (C) 2023 by sysmocom - s.f.m.c. GmbH + * Author: Vadim Yanitskiy + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define BBUF_MAX 290 + +struct test_case { + const char *name; + enum gsm_chan_t lchan_type; + enum gsm48_chan_mode tch_mode; +}; + +static const struct test_case tests[] = { + { + .name = "TCH/F14.4", + .lchan_type = GSM_LCHAN_TCH_F, + .tch_mode = GSM48_CMODE_DATA_14k5, + }, + { + .name = "TCH/F9.6", + .lchan_type = GSM_LCHAN_TCH_F, + .tch_mode = GSM48_CMODE_DATA_12k0, + }, + { + .name = "TCH/F4.8", + .lchan_type = GSM_LCHAN_TCH_F, + .tch_mode = GSM48_CMODE_DATA_6k0, + }, + { + .name = "TCH/H4.8", + .lchan_type = GSM_LCHAN_TCH_H, + .tch_mode = GSM48_CMODE_DATA_6k0, + }, + { + .name = "TCH/F2.4", + .lchan_type = GSM_LCHAN_TCH_F, + .tch_mode = GSM48_CMODE_DATA_3k6, + }, + { + .name = "TCH/H2.4", + .lchan_type = GSM_LCHAN_TCH_H, + .tch_mode = GSM48_CMODE_DATA_3k6, + }, +}; + +static void exec_test_case(const struct test_case *tc) +{ + const struct csd_v110_frame_desc *desc; + uint8_t rtp[RFC4040_RTP_PLEN] = { 0 }; + ubit_t data_enc[BBUF_MAX]; + ubit_t data_dec[BBUF_MAX]; + int rc; + + /* obtain a V.110 frame description for the given channel type/rate */ + OSMO_ASSERT(tc->tch_mode < ARRAY_SIZE(csd_v110_lchan_desc)); + if (tc->lchan_type == GSM_LCHAN_TCH_F) + desc = &csd_v110_lchan_desc[tc->tch_mode].fr; + else + desc = &csd_v110_lchan_desc[tc->tch_mode].hr; + + /* total number of bits carried by a radio interface block */ + const unsigned int bit_num = desc->num_bits * desc->num_blocks; + if (bit_num == 0) { + fprintf(stderr, "[i] Skipping '%s' (not implemented)\n", tc->name); + return; + } + + fprintf(stderr, "[i] Testing '%s' (bitnum=%u)\n", tc->name, bit_num); + + struct gsm_lchan lchan = { + .type = tc->lchan_type, + .tch_mode = tc->tch_mode, + }; + + /* populate the data_enc[] buffer with some bits */ + OSMO_ASSERT(bit_num <= BBUF_MAX); + for (unsigned int i = 0; i < bit_num; i++) + data_enc[i] = i & 0x01; + + /* encode an RTP frame and print it */ + rc = csd_v110_rtp_encode(&lchan, &rtp[0], &data_enc[0], bit_num); + fprintf(stderr, "[i] csd_v110_rtp_encode() returns %d\n", rc); + if (rc != RFC4040_RTP_PLEN) + return; + /* print the encoded RTP frame (16 bytes per row) */ + for (unsigned int i = 0; i < sizeof(rtp) / 16; i++) + fprintf(stderr, " %s\n", osmo_hexdump(&rtp[i * 16], 16)); + + /* decode the encoded RTP frame */ + rc = csd_v110_rtp_decode(&lchan, &data_dec[0], &rtp[0], sizeof(rtp)); + fprintf(stderr, "[i] csd_v110_rtp_decode() returns %d\n", rc); + if (rc != bit_num) + return; + /* compare data_dec[] vs data_enc[] */ + for (unsigned int i = 0; i < bit_num; i++) { + if (data_dec[i] == data_enc[i]) + continue; + fprintf(stderr, "[!] Data mismatch @ %03u: D%u vs E%u\n", + i, data_dec[i], data_enc[i]); + } +} + +int main(int argc, char **argv) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(tests); i++) + exec_test_case(&tests[i]); + + return 0; +} diff --git a/tests/csd/csd_test.err b/tests/csd/csd_test.err new file mode 100644 index 000000000..bc9747cc7 --- /dev/null +++ b/tests/csd/csd_test.err @@ -0,0 +1,66 @@ +[i] Skipping 'TCH/F14.4' (not implemented) +[i] Testing 'TCH/F9.6' (bitnum=240) +[i] csd_v110_rtp_encode() returns 160 + 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf + ff 7f 7f 7f bf 3f 7f 7f bf bf bf bf ff 7f 7f 7f + bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf + ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf 3f 7f 7f + bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f + 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf + ff 7f 7f 7f bf 3f 7f 7f bf bf bf bf ff 7f 7f 7f + bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf + ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf 3f 7f 7f + bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f +[i] csd_v110_rtp_decode() returns 240 +[i] Testing 'TCH/F4.8' (bitnum=120) +[i] csd_v110_rtp_encode() returns 160 + 7f 7f 7f 7f 7f 7f 7f 7f ff 7f ff 7f ff 7f ff 7f + ff ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff 7f + ff ff 7f ff 7f ff 7f ff ff 7f 7f 7f 7f ff 7f ff + ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff + ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff + 7f 7f 7f 7f 7f 7f 7f 7f ff 7f ff 7f ff 7f ff 7f + ff ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff 7f + ff ff 7f ff 7f ff 7f ff ff 7f 7f 7f 7f ff 7f ff + ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff + ff 7f ff 7f ff 7f ff 7f ff ff 7f ff 7f ff 7f ff +[i] csd_v110_rtp_decode() returns 120 +[i] Testing 'TCH/H4.8' (bitnum=240) +[i] csd_v110_rtp_encode() returns 160 + 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf + ff 7f 7f 7f bf 3f 7f 7f bf bf bf bf ff 7f 7f 7f + bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf + ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf 3f 7f 7f + bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f + 3f 3f 3f 3f bf bf bf bf ff 7f 7f 7f bf bf bf bf + ff 7f 7f 7f bf 3f 7f 7f bf bf bf bf ff 7f 7f 7f + bf bf bf bf ff 7f 7f 7f 3f 3f 3f 3f bf bf bf bf + ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f bf 3f 7f 7f + bf bf bf bf ff 7f 7f 7f bf bf bf bf ff 7f 7f 7f +[i] csd_v110_rtp_decode() returns 240 +[i] Testing 'TCH/F2.4' (bitnum=72) +[i] csd_v110_rtp_encode() returns 160 + 7f 7f 7f 7f 7f 7f 7f 7f ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f 7f 7f ff 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + 7f 7f 7f 7f 7f 7f 7f 7f ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f 7f 7f ff 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff + ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff ff 7f 7f ff +[i] csd_v110_rtp_decode() returns 72 +[i] Testing 'TCH/H2.4' (bitnum=144) +[i] csd_v110_rtp_encode() returns 160 + 3f 3f 3f 3f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f + bf 7f bf 7f bf 3f 7f 7f bf 7f bf 7f bf 7f bf 7f + bf 7f bf 7f bf 7f bf 7f 3f 3f 3f 3f bf 7f bf 7f + bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 3f 7f 7f + bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f + 3f 3f 3f 3f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f + bf 7f bf 7f bf 3f 7f 7f bf 7f bf 7f bf 7f bf 7f + bf 7f bf 7f bf 7f bf 7f 3f 3f 3f 3f bf 7f bf 7f + bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 3f 7f 7f + bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f bf 7f +[i] csd_v110_rtp_decode() returns 144 diff --git a/tests/testsuite.at b/tests/testsuite.at index 7e6ec4b8f..a7012b182 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -70,3 +70,9 @@ cat $abs_srcdir/amr/amr_test.ok > expout cat $abs_srcdir/amr/amr_test.err > experr AT_CHECK([$abs_top_builddir/tests/amr/amr_test], [], [expout], [experr]) AT_CLEANUP + +AT_SETUP([csd]) +AT_KEYWORDS([csd]) +cat $abs_srcdir/csd/csd_test.err > experr +AT_CHECK([$abs_top_builddir/tests/csd/csd_test], [], [ignore], [experr]) +AT_CLEANUP