l1sap: proper rate adaptation for CSD (RFC4040 'clearmode')

Since 95407f3f osmo-bts-trx supports scheduling all CSD specific
channel rates, however the rate adaptation was missing.

On the radio interface we deal with CSD-modified V.110 frames, which
need to be converted to normal 80-bit V.110 frames (RA1'/RA1), which
in turn need to be batched and sent in RFC4040 "clearmode" 160 octet
RTP payloads (RA1/RA2 as per I.460).

Note that this patch comments out TCH/F14.4 in bts_supports_cm_data(),
so that all channel allocations for this mode would be NACKed.  The
reason for this is that the rate adaptation functions for TCH/F14.4
are different than the RA1'/RA1 and the RA1/RA2.

For more information, see:

* 3GPP TS 44.021, section 8 (functions RA1'/RA1)
* ITU-T I.460, section 1.1 "Rate adaption of 8, 16 and 32 kbit/s streams"

Change-Id: I5e3701ad52d5d428fd02caff037881045f2d0a02
Related: OS#1572
This commit is contained in:
Vadim Yanitskiy 2023-07-19 19:13:58 +07:00
parent 97d3bd3e62
commit d1f8f3429c
13 changed files with 475 additions and 14 deletions

1
.gitignore vendored
View File

@ -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

View File

@ -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

View File

@ -24,6 +24,7 @@ noinst_HEADERS = \
tx_power.h \
control_if.h \
cbch.h \
csd_v110.h \
l1sap.h \
lchan.h \
power_control.h \

View File

@ -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);

View File

@ -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 \

View File

@ -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 */

157
src/common/csd_v110.c Normal file
View File

@ -0,0 +1,157 @@
/*
* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <errno.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsm44021.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/isdn/v110.h>
#include <osmo-bts/csd_v110.h>
#include <osmo-bts/lchan.h>
/* 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;
}

View File

@ -58,6 +58,7 @@
#include <osmo-bts/pcuif_proto.h>
#include <osmo-bts/cbch.h>
#include <osmo-bts/asci.h>
#include <osmo-bts/csd_v110.h>
/* 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 */

View File

@ -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

25
tests/csd/Makefile.am Normal file
View File

@ -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)

138
tests/csd/csd_test.c Normal file
View File

@ -0,0 +1,138 @@
/*
* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <errno.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/isdn/v110.h>
#include <osmo-bts/csd_v110.h>
#include <osmo-bts/lchan.h>
#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;
}

66
tests/csd/csd_test.err Normal file
View File

@ -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

View File

@ -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