Harald Welte | cd90ed2 | 2020-05-14 14:58:52 +0200 | [diff] [blame] | 1 | /* TRAU frame to RTP conversion */ |
| 2 | |
| 3 | /* (C) 2009,2020 by Harald Welte <laforge@gnumonks.org> |
| 4 | * All Rights Reserved |
| 5 | * |
| 6 | * SPDX-License-Identifier: GPL-2.0+ |
| 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by |
| 10 | * the Free Software Foundation; either version 2 of the License, or |
| 11 | * (at your option) any later version. |
| 12 | * |
| 13 | * This program is distributed in the hope that it will be useful, |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | * GNU General Public License for more details. |
| 17 | * |
| 18 | * You should have received a copy of the GNU General Public License |
| 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 20 | * |
| 21 | */ |
| 22 | |
| 23 | #include <errno.h> |
| 24 | #include <stdlib.h> |
| 25 | #include <string.h> |
| 26 | |
| 27 | #include <osmocom/core/crc8gen.h> |
| 28 | #include <osmocom/codec/codec.h> |
| 29 | |
| 30 | #include <osmocom/trau/trau_frame.h> |
| 31 | #include <osmocom/trau/trau_rtp.h> |
| 32 | |
| 33 | /* this corresponds to the bit-lengths of the individual codec |
| 34 | * parameters as indicated in Table 1.1 of TS 46.010 */ |
| 35 | static const uint8_t gsm_fr_map[] = { |
| 36 | 6, 6, 5, 5, 4, 4, 3, 3, |
| 37 | 7, 2, 2, 6, 3, 3, 3, 3, |
| 38 | 3, 3, 3, 3, 3, 3, 3, 3, |
| 39 | 3, 7, 2, 2, 6, 3, 3, 3, |
| 40 | 3, 3, 3, 3, 3, 3, 3, 3, |
| 41 | 3, 3, 7, 2, 2, 6, 3, 3, |
| 42 | 3, 3, 3, 3, 3, 3, 3, 3, |
| 43 | 3, 3, 3, 7, 2, 2, 6, 3, |
| 44 | 3, 3, 3, 3, 3, 3, 3, 3, |
| 45 | 3, 3, 3, 3 |
| 46 | }; |
| 47 | |
| 48 | |
| 49 | /* |
| 50 | * EFR TRAU parity |
| 51 | * |
| 52 | * g(x) = x^3 + x^1 + 1 |
| 53 | */ |
| 54 | static const struct osmo_crc8gen_code gsm0860_efr_crc3 = { |
| 55 | .bits = 3, |
| 56 | .poly = 0x3, |
| 57 | .init = 0x0, |
| 58 | .remainder = 0x7, |
| 59 | }; |
| 60 | |
| 61 | /* re-combine EFR parity bits */ |
| 62 | static inline void efr_parity_bits_1(ubit_t *check_bits, const ubit_t *d_bits) |
| 63 | { |
| 64 | memcpy(check_bits + 0 , d_bits + 0, 22); |
| 65 | memcpy(check_bits + 22 , d_bits + 24, 3); |
| 66 | check_bits[25] = d_bits[28]; |
| 67 | } |
| 68 | |
| 69 | static inline void efr_parity_bits_2(ubit_t *check_bits, const ubit_t *d_bits) |
| 70 | { |
| 71 | memcpy(check_bits + 0 , d_bits + 42, 10); |
| 72 | memcpy(check_bits + 10 , d_bits + 90, 2); |
| 73 | } |
| 74 | |
| 75 | static inline void efr_parity_bits_3(ubit_t *check_bits, const ubit_t *d_bits) |
| 76 | { |
| 77 | memcpy(check_bits + 0 , d_bits + 98, 5); |
| 78 | check_bits[5] = d_bits[104]; |
| 79 | memcpy(check_bits + 6 , d_bits + 143, 2); |
| 80 | } |
| 81 | |
| 82 | static inline void efr_parity_bits_4(ubit_t *check_bits, const ubit_t *d_bits) |
| 83 | { |
| 84 | memcpy(check_bits + 0 , d_bits + 151, 10); |
| 85 | memcpy(check_bits + 10 , d_bits + 199, 2); |
| 86 | } |
| 87 | |
| 88 | static inline void efr_parity_bits_5(ubit_t *check_bits, const ubit_t *d_bits) |
| 89 | { |
| 90 | memcpy(check_bits + 0 , d_bits + 207, 5); |
| 91 | check_bits[5] = d_bits[213]; |
| 92 | memcpy(check_bits + 6 , d_bits + 252, 2); |
| 93 | } |
| 94 | |
| 95 | //static const uint8_t c_bits_check_fr[] = { 0, 0, 0, 1, 0 }; |
| 96 | //static const uint8_t c_bits_check_efr[] = { 1, 1, 0, 1, 0 }; |
| 97 | |
| 98 | /*! Generate the 33 bytes RTP payload for GSM-FR from a decoded TRAU frame. |
| 99 | * \param[out] out caller-provided output buffer |
| 100 | * \param[in] out_len length of out buffer in bytes |
| 101 | * \param[in] fr input TRAU frame in decoded form |
| 102 | * \returns number of bytes generated in 'out'; negative on error. */ |
| 103 | static int trau2rtp_fr(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf) |
| 104 | { |
| 105 | int i, j, k, l, o; |
| 106 | |
| 107 | if (tf->type != OSMO_TRAU16_FT_FR) |
| 108 | return -EINVAL; |
| 109 | |
| 110 | /* FR Data Bits according to TS 48.060 Section 5.5.1.1.2 */ |
| 111 | |
| 112 | if (tf->c_bits[11]) /* BFI */ |
| 113 | return 0; |
| 114 | |
| 115 | if (out_len < GSM_FR_BYTES) |
| 116 | return -ENOSPC; |
| 117 | |
| 118 | out[0] = 0xd << 4; |
| 119 | /* reassemble d-bits */ |
| 120 | i = 0; /* counts bits */ |
| 121 | j = 4; /* counts output bits */ |
| 122 | k = gsm_fr_map[0]-1; /* current number bit in element */ |
| 123 | l = 0; /* counts element bits */ |
| 124 | o = 0; /* offset input bits */ |
| 125 | while (i < 260) { |
| 126 | out[j/8] |= (tf->d_bits[k+o] << (7-(j%8))); |
| 127 | /* to avoid out-of-bounds access in gsm_fr_map[++l] */ |
| 128 | if (i == 259) |
| 129 | break; |
| 130 | if (--k < 0) { |
| 131 | o += gsm_fr_map[l]; |
| 132 | k = gsm_fr_map[++l]-1; |
| 133 | } |
| 134 | i++; |
| 135 | j++; |
| 136 | } |
| 137 | |
| 138 | return GSM_FR_BYTES; |
| 139 | } |
| 140 | |
| 141 | /* See Section 5.2 of RFC5993 */ |
| 142 | enum rtp_hr_ietf_ft { |
| 143 | FT_GOOD_SPEECH = 0, |
| 144 | FT_GOOD_SID = 2, |
| 145 | FT_NO_DATA = 7, |
| 146 | }; |
| 147 | |
| 148 | static const uint8_t rtp_hr_sid[14] = { 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
| 149 | |
| 150 | /*! Generate the 14 bytes ETSI TS 101 318 RTP payload for HR from a decoded 16k TRAU frame. |
| 151 | * Note that thsi differs from the IETF RFC5993 format. However, as OsmoBTS implements |
| 152 | * the TS 101 318 format, we also use the same format here. osmo-mgw can convert them. |
| 153 | * \param[out] out caller-provided output buffer |
| 154 | * \param[in] out_len length of out buffer in bytes |
| 155 | * \param[in] tf input TRAU frame in decoded form |
| 156 | * \returns number of bytes generated in 'out'; negative on error. */ |
| 157 | static int trau2rtp_hr16(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf) |
| 158 | { |
| 159 | unsigned int i; |
| 160 | |
| 161 | if (tf->type != OSMO_TRAU16_FT_HR) |
| 162 | return -EINVAL; |
| 163 | |
| 164 | /* HR Data Bits according to TS 48.061 Section 5.1.4.1.1 */ |
| 165 | |
| 166 | if (tf->dir == OSMO_TRAU_DIR_UL && tf->c_bits[11]) /* C12: BFI */ |
| 167 | goto bad_frame; |
| 168 | |
| 169 | if (out_len < GSM_HR_BYTES) |
| 170 | return -ENOSPC; |
| 171 | |
| 172 | /* TS 101 318 Section 5.2: The order of occurrence of the codec parameters in the buffer is |
| 173 | * the same as order of occurrence over the Abis as defined in annex B of ETS 300 969 |
| 174 | * [which is 3GPP TS 46.020 */ |
| 175 | osmo_ubit2pbit(out, tf->d_bits, 112); |
| 176 | |
| 177 | if (tf->c_bits[12] || tf->c_bits[13]) { |
| 178 | /* Generate SID frame as per TS 101 318 Section 5.2.2 */ |
| 179 | for (i = 0; i < sizeof(rtp_hr_sid); i++) |
| 180 | out[i] = out[i] | rtp_hr_sid[i]; |
| 181 | } |
| 182 | |
| 183 | return GSM_HR_BYTES; |
| 184 | |
| 185 | bad_frame: |
| 186 | return 0; |
| 187 | } |
| 188 | |
| 189 | /*! Generate the 31 bytes RTP payload for GSM-EFR from a decoded TRAU frame. |
| 190 | * \param[out] out caller-provided output buffer |
| 191 | * \param[in] out_len length of out buffer in bytes |
| 192 | * \param[in] fr input TRAU frame in decoded form |
| 193 | * \returns number of bytes generated in 'out'; negative on error. */ |
| 194 | static int trau2rtp_efr(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf) |
| 195 | { |
| 196 | int i, j, rc; |
| 197 | ubit_t check_bits[26]; |
| 198 | |
| 199 | if (tf->type != OSMO_TRAU16_FT_EFR) |
| 200 | return -EINVAL; |
| 201 | |
| 202 | /* FR Data Bits according to TS 48.060 Section 5.5.1.1.2 */ |
| 203 | |
| 204 | if (tf->c_bits[11]) /* BFI */ |
| 205 | return 0; |
| 206 | |
| 207 | if (out_len < GSM_EFR_BYTES) |
| 208 | return -ENOSPC; |
| 209 | |
| 210 | if (tf->c_bits[11]) /* BFI */ |
| 211 | goto bad_frame; |
| 212 | |
| 213 | out[0] = 0xc << 4; |
| 214 | /* reassemble d-bits */ |
| 215 | for (i = 1, j = 4; i < 39; i++, j++) |
| 216 | out[j/8] |= (tf->d_bits[i] << (7-(j%8))); |
| 217 | efr_parity_bits_1(check_bits, tf->d_bits); |
| 218 | rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 26, |
| 219 | tf->d_bits + 39); |
| 220 | if (rc) |
| 221 | goto bad_frame; |
| 222 | for (i = 42, j = 42; i < 95; i++, j++) |
| 223 | out[j/8] |= (tf->d_bits[i] << (7-(j%8))); |
| 224 | efr_parity_bits_2(check_bits, tf->d_bits); |
| 225 | rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12, |
| 226 | tf->d_bits + 95); |
| 227 | if (rc) |
| 228 | goto bad_frame; |
| 229 | for (i = 98, j = 95; i < 148; i++, j++) |
| 230 | out[j/8] |= (tf->d_bits[i] << (7-(j%8))); |
| 231 | efr_parity_bits_3(check_bits, tf->d_bits); |
| 232 | rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8, |
| 233 | tf->d_bits + 148); |
| 234 | if (rc) |
| 235 | goto bad_frame; |
| 236 | for (i = 151, j = 145; i < 204; i++, j++) |
| 237 | out[j/8] |= (tf->d_bits[i] << (7-(j%8))); |
| 238 | efr_parity_bits_4(check_bits, tf->d_bits); |
| 239 | rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 12, |
| 240 | tf->d_bits + 204); |
| 241 | if (rc) |
| 242 | goto bad_frame; |
| 243 | for (i = 207, j = 198; i < 257; i++, j++) |
| 244 | out[j/8] |= (tf->d_bits[i] << (7-(j%8))); |
| 245 | efr_parity_bits_5(check_bits, tf->d_bits); |
| 246 | rc = osmo_crc8gen_check_bits(&gsm0860_efr_crc3, check_bits, 8, |
| 247 | tf->d_bits + 257); |
| 248 | if (rc) |
| 249 | goto bad_frame; |
| 250 | |
| 251 | return GSM_EFR_BYTES; |
| 252 | bad_frame: |
| 253 | return 0; |
| 254 | } |
| 255 | |
| 256 | /* TS 48.060 Section 5.5.1.1.2 */ |
| 257 | static int rtp2trau_fr(struct osmo_trau_frame *tf, const uint8_t *data, size_t data_len) |
| 258 | { |
| 259 | int i, j, k, l, o; |
| 260 | |
| 261 | /* data_len == 0 for BFI frame */ |
| 262 | if (data_len < GSM_FR_BYTES && data_len != 0) |
| 263 | return -EINVAL; |
| 264 | |
| 265 | if (data_len && data[0] >> 4 != 0xd) |
| 266 | return -EINVAL; |
| 267 | |
| 268 | tf->type = OSMO_TRAU16_FT_FR; |
| 269 | |
| 270 | /* FR Data Bits according to TS 48.060 Section 5.5.1.1.2 */ |
| 271 | |
| 272 | /* FIXME: Generate SID frames? */ |
| 273 | |
| 274 | /* set c-bits and t-bits */ |
| 275 | if (tf->dir == OSMO_TRAU_DIR_UL) { |
| 276 | /* C1 .. C5 */ |
| 277 | tf->c_bits[0] = 0; |
| 278 | tf->c_bits[1] = 0; |
| 279 | tf->c_bits[2] = 0; |
| 280 | tf->c_bits[3] = 1; |
| 281 | tf->c_bits[4] = 0; |
| 282 | } else { |
| 283 | /* C1 .. C5 */ |
| 284 | tf->c_bits[0] = 1; |
| 285 | tf->c_bits[1] = 1; |
| 286 | tf->c_bits[2] = 1; |
| 287 | tf->c_bits[3] = 0; |
| 288 | tf->c_bits[4] = 0; |
| 289 | } |
| 290 | memset(&tf->c_bits[5], 0, 6); /* C6 .. C11: Time Alignment */ |
| 291 | if (tf->dir == OSMO_TRAU_DIR_UL) { |
| 292 | if (data_len == 0) |
| 293 | tf->c_bits[11] = 1; /* C12: BFI */ |
| 294 | else |
| 295 | tf->c_bits[11] = 0; /* C12: BFI */ |
| 296 | tf->c_bits[12] = 0; /* C13: SID=0 */ |
| 297 | tf->c_bits[13] = 0; /* C14: SID=0 */ |
| 298 | tf->c_bits[14] = 0; /* C15: TAF (SACCH or not) */ |
| 299 | tf->c_bits[15] = 1; /* C16: spare */ |
| 300 | tf->c_bits[16] = 0; /* C17: DTXd not applied */ |
| 301 | } else { |
| 302 | memset(&tf->c_bits[11], 1, 10); /* C12 .. C15: spare */ |
| 303 | tf->c_bits[15] = 1; /* C16: SP=1 */ |
| 304 | } |
| 305 | memset(&tf->c_bits[17], 1, 4); /* C18 .. C12: spare */ |
| 306 | memset(&tf->t_bits[0], 1, 4); |
| 307 | |
| 308 | if (!data_len) |
| 309 | return 0; |
| 310 | |
| 311 | /* reassemble d-bits */ |
| 312 | i = 0; /* counts bits */ |
| 313 | j = 4; /* counts input bits */ |
| 314 | k = gsm_fr_map[0]-1; /* current number bit in element */ |
| 315 | l = 0; /* counts element bits */ |
| 316 | o = 0; /* offset output bits */ |
| 317 | while (i < 260) { |
| 318 | tf->d_bits[k+o] = (data[j/8] >> (7-(j%8))) & 1; |
| 319 | /* to avoid out-of-bounds access in gsm_fr_map[++l] */ |
| 320 | if (i == 259) |
| 321 | break; |
| 322 | if (--k < 0) { |
| 323 | o += gsm_fr_map[l]; |
| 324 | k = gsm_fr_map[++l]-1; |
| 325 | } |
| 326 | i++; |
| 327 | j++; |
| 328 | } |
| 329 | |
| 330 | return 0; |
| 331 | } |
| 332 | |
| 333 | /* does the RTP HR payload resemble a SID frame or not */ |
| 334 | static bool is_rtp_hr_sid(const uint8_t *data, const uint8_t data_len) |
| 335 | { |
| 336 | int i; |
| 337 | |
| 338 | if (data_len < GSM_HR_BYTES) |
| 339 | return false; |
| 340 | |
| 341 | for (i = 0; i < GSM_HR_BYTES; i++) { |
| 342 | if ((data[i] & rtp_hr_sid[i]) != rtp_hr_sid[i]) |
| 343 | return false; |
| 344 | } |
| 345 | return true; |
| 346 | } |
| 347 | |
| 348 | static int rtp2trau_hr16(struct osmo_trau_frame *tf, const uint8_t *data, size_t data_len) |
| 349 | { |
| 350 | if (data_len < GSM_HR_BYTES && data_len != 0) |
| 351 | return -EINVAL; |
| 352 | |
| 353 | tf->type = OSMO_TRAU16_FT_HR; |
| 354 | |
| 355 | if (tf->dir == OSMO_TRAU_DIR_UL) { |
| 356 | /* C1 .. C5 */ |
| 357 | tf->c_bits[0] = 0; |
| 358 | tf->c_bits[1] = 0; |
| 359 | tf->c_bits[2] = 0; |
| 360 | tf->c_bits[3] = 1; |
| 361 | tf->c_bits[4] = 1; |
| 362 | } else { |
| 363 | /* C1 .. C5 */ |
| 364 | tf->c_bits[0] = 1; |
| 365 | tf->c_bits[1] = 1; |
| 366 | tf->c_bits[2] = 1; |
| 367 | tf->c_bits[3] = 0; |
| 368 | tf->c_bits[4] = 1; |
| 369 | } |
| 370 | /* C6.. C11: Time Alignment */ |
| 371 | memset(tf->c_bits + 5, 0, 6); |
| 372 | if (tf->dir == OSMO_TRAU_DIR_UL) { |
| 373 | /* BFI */ |
| 374 | if (data_len == 0) |
| 375 | tf->c_bits[11] = 1; |
| 376 | else |
| 377 | tf->c_bits[11] = 0; |
| 378 | if (is_rtp_hr_sid(data, data_len)) { |
| 379 | /* SID=2 is a valid SID frame */ |
| 380 | tf->c_bits[12] = 1; |
| 381 | tf->c_bits[13] = 0; |
| 382 | } else { |
| 383 | tf->c_bits[12] = 0; |
| 384 | tf->c_bits[13] = 0; |
| 385 | } |
| 386 | /* FIXME: C15: TAF */ |
| 387 | tf->c_bits[15] = 0; /* C16: SP */ |
| 388 | tf->c_bits[16] = 0; /* C17: DTXd shall not be applied */ |
| 389 | } else { |
| 390 | tf->c_bits[11] = 0; /* C12: UFE */ |
| 391 | tf->c_bits[12] = 1; /* C13: spare */ |
| 392 | tf->c_bits[13] = 1; /* C14: spare */ |
| 393 | tf->c_bits[14] = 1; /* C15: spare */ |
| 394 | if (is_rtp_hr_sid(data, data_len)) |
| 395 | tf->c_bits[15] = 0; /* C16: SP */ |
| 396 | else |
| 397 | tf->c_bits[15] = 1; /* C16: SP */ |
| 398 | tf->c_bits[16] = 1; /* C17: spare */ |
| 399 | } |
| 400 | memset(tf->c_bits+17, 1, 4); /* C18..C21: spare */ |
| 401 | memset(&tf->t_bits[0], 1, 4); |
| 402 | if (tf->dir == OSMO_TRAU_DIR_UL) |
| 403 | tf->ufi = 0; |
| 404 | else |
| 405 | tf->ufi = 1; |
| 406 | /* CRC is computed by TRAU frame encoder */ |
| 407 | if (data_len) |
| 408 | memcpy(tf->d_bits, data, GSM_HR_BYTES); |
| 409 | |
| 410 | return 0; |
| 411 | } |
| 412 | |
| 413 | /* TS 48.060 Section 5.5.1.1.2 */ |
| 414 | static int rtp2trau_efr(struct osmo_trau_frame *tf, const uint8_t *data, size_t data_len) |
| 415 | { |
| 416 | int i, j; |
| 417 | ubit_t check_bits[26]; |
| 418 | |
| 419 | /* data_len == 0 for BFI frame */ |
| 420 | if (data_len < GSM_EFR_BYTES && data_len != 0) |
| 421 | return -EINVAL; |
| 422 | |
| 423 | if (data_len && data[0] >> 4 != 0xc) |
| 424 | return -EINVAL; |
| 425 | |
| 426 | tf->type = OSMO_TRAU16_FT_EFR; |
| 427 | |
| 428 | /* FR Data Bits according to TS 48.060 Section 5.5.1.1.2 */ |
| 429 | |
| 430 | /* set c-bits and t-bits */ |
| 431 | tf->c_bits[0] = 1; |
| 432 | tf->c_bits[1] = 1; |
| 433 | tf->c_bits[2] = 0; |
| 434 | tf->c_bits[3] = 1; |
| 435 | tf->c_bits[4] = 0; |
| 436 | |
| 437 | memset(&tf->c_bits[5], 0, 6); /* C6 .. C11: Time Alignment */ |
| 438 | if (tf->dir == OSMO_TRAU_DIR_UL) { |
| 439 | if (data_len == 0) |
| 440 | tf->c_bits[11] = 1; /* C12: BFI=1 */ |
| 441 | else |
| 442 | tf->c_bits[11] = 0; /* C12: BFI=1 */ |
| 443 | /* FIXME: Generate SID frames? */ |
| 444 | tf->c_bits[12] = 0; /* C13: SID=0 */ |
| 445 | tf->c_bits[13] = 0; /* C14: SID=0 */ |
| 446 | tf->c_bits[14] = 0; /* C15: TAF (SACCH) */ |
| 447 | tf->c_bits[15] = 1; /* C16: spare */ |
| 448 | tf->c_bits[16] = 0; /* C17: DTXd applied */ |
| 449 | } else { |
| 450 | tf->c_bits[11] = 1; /* C12: UFE (good uplink) */ |
| 451 | memset(&tf->c_bits[12], 1, 3); /* C13 .. C15: spare */ |
| 452 | tf->c_bits[15] = 1; /* C16: SP=1 */ |
| 453 | tf->c_bits[16] = 1; /* C17: spare */ |
| 454 | } |
| 455 | memset(&tf->c_bits[17], 1, 4); /* C18 .. C21: spare */ |
| 456 | memset(&tf->t_bits[0], 1, 4); |
| 457 | |
| 458 | if (data_len == 0) |
| 459 | return 0; |
| 460 | |
| 461 | /* reassemble d-bits */ |
| 462 | tf->d_bits[0] = 1; |
| 463 | for (i = 1, j = 4; i < 39; i++, j++) |
| 464 | tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; |
| 465 | efr_parity_bits_1(check_bits, tf->d_bits); |
| 466 | osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 26, |
| 467 | tf->d_bits + 39); |
| 468 | for (i = 42, j = 42; i < 95; i++, j++) |
| 469 | tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; |
| 470 | efr_parity_bits_2(check_bits, tf->d_bits); |
| 471 | osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12, |
| 472 | tf->d_bits + 95); |
| 473 | for (i = 98, j = 95; i < 148; i++, j++) |
| 474 | tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; |
| 475 | efr_parity_bits_3(check_bits, tf->d_bits); |
| 476 | osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8, |
| 477 | tf->d_bits + 148); |
| 478 | for (i = 151, j = 145; i < 204; i++, j++) |
| 479 | tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; |
| 480 | efr_parity_bits_4(check_bits, tf->d_bits); |
| 481 | osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 12, |
| 482 | tf->d_bits + 204); |
| 483 | for (i = 207, j = 198; i < 257; i++, j++) |
| 484 | tf->d_bits[i] = (data[j/8] >> (7-(j%8))) & 1; |
| 485 | efr_parity_bits_5(check_bits, tf->d_bits); |
| 486 | osmo_crc8gen_set_bits(&gsm0860_efr_crc3, check_bits, 8, |
| 487 | tf->d_bits + 257); |
| 488 | |
| 489 | return 0; |
| 490 | } |
| 491 | |
| 492 | #if 0 |
| 493 | static inline memcpy_inc(uint8_t *out, const uint8_t *in, size_t len, unsigned int *idx) |
| 494 | { |
| 495 | memcpy_inc(out, in, len); |
| 496 | *idx += len; |
| 497 | } |
| 498 | |
| 499 | static int amr_speech_extract_sbits(ubit_t *s_bits, const struct osmo_trau_frame *tf, |
| 500 | enum osmo_amr_mode mode) |
| 501 | { |
| 502 | unsigned int s_idx = 0; |
| 503 | |
| 504 | switch (mode) { |
| 505 | case AMR_4_75: |
| 506 | memcpy_inc(s_bits + s_idx, tf->d_bits + 44, 67 - 44, &s_idx); |
| 507 | memcpy_inc(s_bits + s_idx, tf->d_bits + 67, 92 - 67, &s_idx); |
| 508 | memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 108 - 95, &s_idx); |
| 509 | memcpy_inc(s_bits + s_idx, tf->d_bits + 111, 132 - 111, &s_idx); |
| 510 | memcpy_inc(s_bits + s_idx, tf->d_bits + 135, 148 - 135, &s_idx); |
| 511 | break; |
| 512 | case AMR_5_15: |
| 513 | memcpy_inc(s_bits + s_idx, tf->d_bits + 46, 96 - 46, &s_idx); |
| 514 | memcpy_inc(s_bits + s_idx, tf->d_bits + 69, 92 - 69, &s_idx); |
| 515 | memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 114 - 95, &s_idx); |
| 516 | memcpy_inc(s_bits + s_idx, tf->d_bits + 117, 136 - 117, &s_idx); |
| 517 | memcpy_inc(s_bits + s_idx, tf->d_bits + 139, 158 - 139, &s_idx); |
| 518 | break; |
| 519 | case AMR_5_90: |
| 520 | memcpy_inc(s_bits + s_idx, tf->d_bits + 41, 67 - 41, &s_idx); |
| 521 | memcpy_inc(s_bits + s_idx, tf->d_bits + 67, 92 - 67, &s_idx); |
| 522 | memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 116 - 95, &s_idx); |
| 523 | memcpy_inc(s_bits + s_idx, tf->d_bits + 119, 144 - 119, &s_idx); |
| 524 | memcpy_inc(s_bits + s_idx, tf->d_bits + 147, 168 - 147, &s_idx); |
| 525 | break; |
| 526 | case AMR_6_70: |
| 527 | memcpy_inc(s_bits + s_idx, tf->d_bits + 37, 63 - 37, &s_idx); |
| 528 | memcpy_inc(s_bits + s_idx, tf->d_bits + 63, 92 - 63, &s_idx); |
| 529 | memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 120 - 95, &s_idx); |
| 530 | memcpy_inc(s_bits + s_idx, tf->d_bits + 123, 152 - 123, &s_idx); |
| 531 | memcpy_inc(s_bits + s_idx, tf->d_bits + 155, 180 - 155, &s_idx); |
| 532 | break; |
| 533 | case AMR_7_40: |
| 534 | memcpy_inc(s_bits + s_idx, tf->d_bits + 34, 60 - 34, &s_idx); |
| 535 | memcpy_inc(s_bits + s_idx, tf->d_bits + 60, 92 - 60, &s_idx); |
| 536 | memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 124 - 95, &s_idx); |
| 537 | memcpy_inc(s_bits + s_idx, tf->d_bits + 127, 159 - 127, &s_idx); |
| 538 | memcpy_inc(s_bits + s_idx, tf->d_bits + 162, 191 - 162, &s_idx); |
| 539 | break; |
| 540 | case AMR_7_95: |
| 541 | memcpy_inc(s_bits + s_idx, tf->d_bits + 31, 58 - 31, &s_idx); |
| 542 | memcpy_inc(s_bits + s_idx, tf->d_bits + 58, 92 - 58, &s_idx); |
| 543 | memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 127 - 95, &s_idx); |
| 544 | memcpy_inc(s_bits + s_idx, tf->d_bits + 130, 164 - 130, &s_idx); |
| 545 | memcpy_inc(s_bits + s_idx, tf->d_bits + 167, 199 - 167, &s_idx); |
| 546 | break; |
| 547 | case AMR_10_2: |
| 548 | memcpy_inc(s_bits + s_idx, tf->d_bits + 20, 46 - 20, &s_idx); /* D21..D46 */ |
| 549 | memcpy_inc(s_bits + s_idx, tf->d_bits + 46, 92 - 46, &s_idx); |
| 550 | memcpy_inc(s_bits + s_idx, tf->d_bits + 95, 138 - 95, &s_idx); |
| 551 | memcpy_inc(s_bits + s_idx, tf->d_bits + 141, 187 - 141, &s_idx); |
| 552 | memcpy_inc(s_bits + s_idx, tf->d_bits + 190, 233 - 190, &s_idx); |
| 553 | break; |
| 554 | case AMR_12_2: |
| 555 | memcpy_inc(s_bits + s_idx, tf->d_bits + 0, 38 - 0, &s_idx); /* D1..D38 */ |
| 556 | memcpy_inc(s_bits + s_idx, tf->d_bits + 38, 91 - 38, &s_idx); /* D39..D91 */ |
| 557 | memcpy_inc(s_bits + s_idx, tf->d_bits + 94, 144 - 94, &s_idx); /* D95..D144 */ |
| 558 | memcpy_inc(s_bits + s_idx, tf->d_bits + 147, 200 - 147, &s_idx);/* D148..D200 */ |
| 559 | memcpy_inc(s_bits + s_idx, tf->d_bits + 203, 253 - 203, &s_idx);/* D204..D253 */ |
| 560 | break; |
| 561 | } |
| 562 | |
| 563 | return s_idx; |
| 564 | } |
| 565 | |
| 566 | /* TS 48.060 Section 5.5.1.2.2 */ |
| 567 | static int trau2rtp_16(uint8_t *out, const struct osmo_trau_frame *tf, enum osmo_amr_mode last_cmi) |
| 568 | { |
| 569 | enum osmo_amr_mode mode = last_cmi; |
| 570 | uint8_t frame_class = tf->c_bits[21] << 1 | tf->c_bits[20]; |
| 571 | uint8_t cmr_cmi = tf->c_bits[23] << 2 | tf->c_bits[24] << 1 | tf->cb_bits[25]; |
| 572 | uint8_t no_speech_cls; |
| 573 | uint8_t s_bits[242]; |
| 574 | uint8_t d_bits[242]; |
| 575 | unsigned int s_idx = 0; |
| 576 | ubit_t rif = FIXME; |
| 577 | |
| 578 | if (tf->type != OSMO_TRAU16_FT_AMR) |
| 579 | return -EINVAL; |
| 580 | |
| 581 | if (rif == 0) |
| 582 | mode = cmr_cmi; |
| 583 | |
| 584 | switch (frame_class) { |
| 585 | case 0: // no speech |
| 586 | no_speech_cls = tf->d_bits[32] << 2 | tf->d_bits[33] << 1 | tf->d_bits[34]; |
| 587 | cmi_abs = tf->d_bits[35] << 2 | tf->d_bits[36] < 1 || tf->d_bits[37]; |
| 588 | cmr_abs = tf->d_bits[38] << 2 | tf->d_bits[39] < 1 || tf->d_bits[40]; |
| 589 | switch (no_speech_cls) { |
| 590 | case 7: // sid first |
| 591 | break; |
| 592 | case 6: // onset |
| 593 | break; |
| 594 | case 5: // sid_update |
| 595 | break; |
| 596 | case 4: // sid_bad |
| 597 | break; |
| 598 | case 0: // no_data |
| 599 | break; |
| 600 | } |
| 601 | break; |
| 602 | case 1: // speech bad |
| 603 | break; |
| 604 | case 2: |
| 605 | case 3: |
| 606 | /* Extract the s-bits from the TRAU frame */ |
| 607 | amr_speech_extract_sbits(s_bits, tf, mode); |
| 608 | /* Convert the s-bits to d-bits */ |
| 609 | osmo_amr_s_to_d(d_bits, s_bits, mode); |
| 610 | break; |
| 611 | } |
| 612 | } |
| 613 | |
| 614 | int trau2rtp_amr(uint8_t *out, const struct osmo_trau_frame *tf, enum osmo_amr_mode last_cmi)) |
| 615 | { |
| 616 | switch (tf->type) { |
| 617 | case OSMO_TRAU16_FT_AMR: |
| 618 | return trau2rtp_16(out, tf, last_cmi); |
| 619 | case OSMO_TRAU8_AMR_LOW: |
| 620 | case OSMO_TRAU8_AMR_6k7: |
| 621 | case OSMO_TRAU8_AMR_7k4: |
| 622 | default: |
| 623 | return -EINVAL; |
| 624 | } |
| 625 | } |
| 626 | #endif |
| 627 | |
| 628 | int osmo_trau2rtp(uint8_t *out, size_t out_len, const struct osmo_trau_frame *tf, |
| 629 | struct osmo_trau2rtp_state *st) |
| 630 | { |
| 631 | switch (tf->type) { |
| 632 | case OSMO_TRAU16_FT_FR: |
| 633 | return trau2rtp_fr(out, out_len, tf); |
| 634 | case OSMO_TRAU16_FT_EFR: |
| 635 | return trau2rtp_efr(out, out_len, tf); |
| 636 | case OSMO_TRAU16_FT_HR: |
| 637 | return trau2rtp_hr16(out, out_len, tf); |
| 638 | default: |
| 639 | return -EINVAL; |
| 640 | } |
| 641 | } |
| 642 | |
| 643 | int osmo_rtp2trau(struct osmo_trau_frame *tf, const uint8_t *rtp, size_t rtp_len, |
| 644 | struct osmo_trau2rtp_state *st) |
| 645 | { |
| 646 | switch (st->type) { |
| 647 | case OSMO_TRAU16_FT_FR: |
| 648 | return rtp2trau_fr(tf, rtp, rtp_len); |
| 649 | case OSMO_TRAU16_FT_EFR: |
| 650 | return rtp2trau_efr(tf, rtp, rtp_len); |
| 651 | case OSMO_TRAU16_FT_HR: |
| 652 | return rtp2trau_hr16(tf, rtp, rtp_len); |
| 653 | default: |
| 654 | return -EINVAL; |
| 655 | } |
| 656 | } |