falconia has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-abis/+/37287?usp=email )
Change subject: trau_rtp_conv: add support for HRv1 in 8k format ...................................................................... trau_rtp_conv: add support for HRv1 in 8k format GSM 08.61 defines two alternative Abis transport formats for HRv1 codec, using either 16 kbit/s or 8 kbit/s submultiplexing, as chosen by each BSS hardware manufacturer. libosmotrau previously supported TRAU<->RTP conversion only for 16k format - add support for HRv1 in 8k submux format. Change-Id: I8ee01b73360501ca380a8695cbc7070ceaaba1be --- M src/trau/trau_rtp_conv.c 1 file changed, 186 insertions(+), 0 deletions(-) Approvals: Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve fixeria: Looks good to me, approved diff --git a/src/trau/trau_rtp_conv.c b/src/trau/trau_rtp_conv.c index 91bf228..d149264 100644 --- a/src/trau/trau_rtp_conv.c +++ b/src/trau/trau_rtp_conv.c @@ -249,6 +249,110 @@ return 0; } +static bool hr8_xc_bits_good_parity(const ubit_t *xc_bits) +{ + int i; + unsigned int sum = 0; + + for (i = 0; i < 6; i++) + sum += xc_bits[i]; + if (sum & 1) + return true; /* odd sum good */ + else + return false; /* even sum bad */ +} + +static void twts002_hr8_set_extra_flags(uint8_t *out, const struct osmo_trau_frame *tf) +{ + if (tf->c_bits[8]) /* DTXd */ + out[0] |= 0x08; + if (tf->xc_bits[4]) /* UFI */ + out[0] |= 0x02; +} + +/*! Generate an RFC 5993 or TW-TS-002 RTP payload for HRv1 + * from a decoded 8k TRAU frame. + * \param[out] out caller-provided output buffer + * \param[in] out_len length of out buffer in bytes + * \param[in] tf input TRAU frame in decoded form + * \param[in] emit_twts002 self-explanatory + * \returns number of bytes generated in 'out'; negative on error. */ +static int trau2rtp_hr8(uint8_t *out, size_t out_len, + const struct osmo_trau_frame *tf, bool emit_twts002) +{ + unsigned xc1_4; + + /* function interface preliminaries */ + if (tf->type != OSMO_TRAU8_SPEECH) + return -EINVAL; + if (out_len < GSM_HR_BYTES_RTP_RFC5993) + return -ENOSPC; + + /* Before considering anything else, if we have bad parity in + * frame classification bits or bad CRC in payload bits, + * we treat this frame as totally invalid: BFI with no data. */ + if (!hr8_xc_bits_good_parity(tf->xc_bits) || + osmo_crc8gen_check_bits(&gsm0860_efr_crc3, tf->d_bits, 44, + tf->crc_bits)) + goto bad_frame; + + /* classify this frame per XC1..XC4 */ + xc1_4 = (tf->xc_bits[0] << 3) | (tf->xc_bits[1] << 2) | + (tf->xc_bits[2] << 1) | (tf->xc_bits[3] << 0); + switch (xc1_4) { + case 0: + /* good speech frame (BFI=0, SID=0) */ + out[0] = FT_GOOD_SPEECH << 4; + if (emit_twts002) + twts002_hr8_set_extra_flags(out, tf); + osmo_ubit2pbit(out + 1, tf->d_bits, 112); + return GSM_HR_BYTES_RTP_RFC5993; + case 1: + /* valid SID frame (BFI=0, SID=2) */ + out[0] = FT_GOOD_SID << 4; + if (emit_twts002) + twts002_hr8_set_extra_flags(out, tf); + osmo_ubit2pbit(out + 1, tf->d_bits, 112); + /* RFC 5993 requires SID frames to be perfect, error-free */ + if (!emit_twts002) + osmo_hr_sid_reset(out + 1); + return GSM_HR_BYTES_RTP_RFC5993; + case 4: + case 5: + /* invalid SID frame (multiple BFI/SID combinations) */ + /* can be represented only in TW-TS-002, not in RFC 5993 */ + if (!emit_twts002) + return 0; + out[0] = FT_INVALID_SID << 4; + twts002_hr8_set_extra_flags(out, tf); + /* XC4 is TAF with this frame type */ + if (tf->xc_bits[3]) + out[0] |= 0x01; + return 1; /* short format per TW-TS-002 */ + case 6: + case 7: + /* bad speech frame (BFI=1, SID=0) */ + if (!emit_twts002) + return 0; + out[0] = FT_BFI_WITH_DATA << 4; + twts002_hr8_set_extra_flags(out, tf); + /* XC4 is TAF with this frame type */ + if (tf->xc_bits[3]) + out[0] |= 0x01; + osmo_ubit2pbit(out + 1, tf->d_bits, 112); + return GSM_HR_BYTES_RTP_RFC5993; + default: +bad_frame: + /* received garbage, emit BFI with no data */ + if (emit_twts002) { + out[0] = FT_NO_DATA << 4; + twts002_hr8_set_extra_flags(out, tf); + return 1; + } else + return 0; + } +} + /*! Generate the 31 bytes RTP payload for GSM-EFR from a decoded TRAU frame. * \param[out] out caller-provided output buffer * \param[in] out_len length of out buffer in bytes @@ -524,6 +628,69 @@ return 0; } +static int rtp2trau_hr8(struct osmo_trau_frame *tf, const uint8_t *data, size_t data_len) +{ + /* accept both TS 101 318 and RFC 5993 payloads */ + switch (data_len) { + case GSM_HR_BYTES: + break; + case GSM_HR_BYTES_RTP_RFC5993: + data++; + data_len--; + break; + case 0: + /* accept no-data input */ + break; + default: + return -EINVAL; + } + + /* FIXME: implement TRAU-UL frame generation if and when + * someone actually needs it in a program that uses + * this library. */ + if (tf->dir != OSMO_TRAU_DIR_DL) + return -ENOTSUP; + + tf->type = OSMO_TRAU8_SPEECH; + + /* C1..C5 */ + tf->c_bits[0] = 0; + tf->c_bits[1] = 0; + tf->c_bits[2] = 0; + tf->c_bits[3] = 1; /* UFE: good uplink */ + tf->c_bits[4] = 0; /* odd parity */ + /* C6..C9: spare bits */ + memset(tf->c_bits + 5, 1, 4); + + /* XC1..XC6 */ + if (osmo_hr_check_sid(data, data_len)) { + tf->xc_bits[0] = 0; + tf->xc_bits[1] = 0; + tf->xc_bits[2] = 0; + tf->xc_bits[3] = 1; + tf->xc_bits[4] = 0; + tf->xc_bits[5] = 0; /* odd parity */ + } else { + tf->xc_bits[0] = 0; + tf->xc_bits[1] = 0; + tf->xc_bits[2] = 0; + tf->xc_bits[3] = 0; + tf->xc_bits[4] = 0; + tf->xc_bits[5] = 1; /* odd parity */ + } + + memset(&tf->t_bits[0], 1, 2); + + if (data_len) + osmo_pbit2ubit(tf->d_bits, data, GSM_HR_BYTES * 8); + else + memset(tf->d_bits, 0, GSM_HR_BYTES * 8); + /* CRC is *not* computed by TRAU frame encoder - we have to do it */ + osmo_crc8gen_set_bits(&gsm0860_efr_crc3, tf->d_bits, 44, tf->crc_bits); + + return 0; +} + /* TS 48.060 Section 5.5.1.1.2 */ static int rtp2trau_efr(struct osmo_trau_frame *tf, const uint8_t *data, size_t data_len) { @@ -801,6 +968,8 @@ return trau2rtp_efr(out, out_len, tf, check_twts001(st)); case OSMO_TRAU16_FT_HR: return trau2rtp_hr16(out, out_len, tf, check_twts002(st)); + case OSMO_TRAU8_SPEECH: + return trau2rtp_hr8(out, out_len, tf, check_twts002(st)); default: return -EINVAL; } @@ -816,6 +985,8 @@ return rtp2trau_efr(tf, rtp, rtp_len); case OSMO_TRAU16_FT_HR: return rtp2trau_hr16(tf, rtp, rtp_len); + case OSMO_TRAU8_SPEECH: + return rtp2trau_hr8(tf, rtp, rtp_len); default: return -EINVAL; } -- To view, visit https://gerrit.osmocom.org/c/libosmo-abis/+/37287?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: libosmo-abis Gerrit-Branch: master Gerrit-Change-Id: I8ee01b73360501ca380a8695cbc7070ceaaba1be Gerrit-Change-Number: 37287 Gerrit-PatchSet: 3 Gerrit-Owner: falconia <fal...@freecalypso.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: falconia <fal...@freecalypso.org> Gerrit-Reviewer: fixeria <vyanits...@sysmocom.de> Gerrit-Reviewer: laforge <lafo...@osmocom.org> Gerrit-Reviewer: pespin <pes...@sysmocom.de> Gerrit-MessageType: merged