FreeCalypso > hg > gsm-codec-lib
comparison doc/FR1-library-API @ 535:bf7bbc7d494f
doc/FR1-library-API: document new additions
| author | Mychaela Falconia <falcon@freecalypso.org> |
|---|---|
| date | Fri, 20 Sep 2024 07:27:18 +0000 |
| parents | 59751c8fc773 |
| children | a3300483ae74 |
comparison
equal
deleted
inserted
replaced
| 534:516e84085a15 | 535:bf7bbc7d494f |
|---|---|
| 27 function: | 27 function: |
| 28 | 28 |
| 29 struct gsmfr_0610_state *gsmfr_0610_create(void); | 29 struct gsmfr_0610_state *gsmfr_0610_create(void); |
| 30 | 30 |
| 31 This function allocates dynamic memory for the state structure with malloc() | 31 This function allocates dynamic memory for the state structure with malloc() |
| 32 (the size of the struct is internal to the library and not exposed) and returns | 32 and returns a pointer to the allocated and initialized struct if successful, or |
| 33 a pointer to the allocated and initialized struct if successful, or NULL if | 33 NULL if malloc() fails. The state structure is malloc'ed as a single chunk, |
| 34 malloc() fails. The state structure is malloc'ed as a single chunk, hence when | 34 hence when you are done with it, simply free() it. |
| 35 you are done with it, simply free() it. | |
| 36 | 35 |
| 37 The initialization or reset portion of gsmfr_0610_create() operation can always | 36 The initialization or reset portion of gsmfr_0610_create() operation can always |
| 38 be repeated with this function: | 37 be repeated with this function: |
| 39 | 38 |
| 40 void gsmfr_0610_reset(struct gsmfr_0610_state *state); | 39 void gsmfr_0610_reset(struct gsmfr_0610_state *state); |
| 40 | |
| 41 To support applications that need (or prefer) to use some different method of | |
| 42 managing their memory allocations, the library also exports this const datum: | |
| 43 | |
| 44 extern const unsigned gsmfr_0610_state_size; | |
| 45 | |
| 46 Using this feature, one can replace gsmfr_0610_create() with something like the | |
| 47 following (example for applications based on Osmocom libraries): | |
| 48 | |
| 49 struct gsmfr_0610_state *st; | |
| 50 st = talloc_size(ctx, gsmfr_0610_state_size); | |
| 51 if (st) | |
| 52 gsmfr_0610_reset(st); | |
| 41 | 53 |
| 42 Immediately after gsmfr_0610_create() or gsmfr_0610_reset(), the "virgin" state | 54 Immediately after gsmfr_0610_create() or gsmfr_0610_reset(), the "virgin" state |
| 43 structure can be used either for the encoder or for the decoder; however, once | 55 structure can be used either for the encoder or for the decoder; however, once |
| 44 that state struct has been passed to functions of either group, it can only be | 56 that state struct has been passed to functions of either group, it can only be |
| 45 used for that functional group. | 57 used for that functional group. |
| 112 | 124 |
| 113 The Rx DTX preprocessor is its own stateful element, independent from the 06.10 | 125 The Rx DTX preprocessor is its own stateful element, independent from the 06.10 |
| 114 decoder to which it is usually coupled. Libgsmfr2 provides a "fulldec" wrapper | 126 decoder to which it is usually coupled. Libgsmfr2 provides a "fulldec" wrapper |
| 115 that incorporates both elements, but the ability to use the Rx DTX preprocessor | 127 that incorporates both elements, but the ability to use the Rx DTX preprocessor |
| 116 by itself still remains, unchanged from our previous libgsmfrp offering. One | 128 by itself still remains, unchanged from our previous libgsmfrp offering. One |
| 117 potential application for this preprocessor by itself, without immediately | 129 significant application for this preprocessor by itself, without immediately |
| 118 following it with the GSM 06.10 decode step, is the possibility of implementing | 130 following it with the GSM 06.10 decode step, is the TFO/TrFO transform of 3GPP |
| 119 the TFO/TrFO transform of 3GPP TS 28.062 section C.3.2.1.1 for GSM-FR: our Rx | 131 TS 28.062 section C.3.2.1.1 for GSM-FR: our Rx DTX preprocessor does exactly |
| 120 DTX preprocessor does exactly what that section calls for, specifically in | 132 what that section calls for, specifically in "case 1" where the input UL frame |
| 121 "case 1" where the input UL frame stream may contain SIDs and BFI frame gaps, | 133 stream may contain SIDs and BFI frame gaps, but the output must be 100% valid |
| 122 but the output must be 100% valid frames and SID-free. | 134 frames and SID-free. The current version of libgsmfr2 includes some additional |
| 135 provisions for using our preprocessor block as a TFO transform in both non-DTXd | |
| 136 and DTXd-enabled configurations, as detailed in a later section of this | |
| 137 document. | |
| 123 | 138 |
| 124 The state structure for this block is struct gsmfr_preproc_state, and it is | 139 The state structure for this block is struct gsmfr_preproc_state, and it is |
| 125 allocated with this function: | 140 allocated with this function: |
| 126 | 141 |
| 127 struct gsmfr_preproc_state *gsmfr_preproc_create(void); | 142 struct gsmfr_preproc_state *gsmfr_preproc_create(void); |
| 129 Like other state structures in Themyscira GSM codec libraries, this opaque | 144 Like other state structures in Themyscira GSM codec libraries, this opaque |
| 130 state is malloc'ed as a single chunk and can be simply freed afterward. A | 145 state is malloc'ed as a single chunk and can be simply freed afterward. A |
| 131 reset function is also provided: | 146 reset function is also provided: |
| 132 | 147 |
| 133 void gsmfr_preproc_reset(struct gsmfr_preproc_state *state); | 148 void gsmfr_preproc_reset(struct gsmfr_preproc_state *state); |
| 149 | |
| 150 There is also a public const datum with the size of this structure, allowing | |
| 151 use of talloc and other alternative schemes: | |
| 152 | |
| 153 extern const unsigned gsmfr_preproc_state_size; | |
| 134 | 154 |
| 135 Preprocessing good frames | 155 Preprocessing good frames |
| 136 ------------------------- | 156 ------------------------- |
| 137 | 157 |
| 138 For every good traffic frame (BFI=0) you receive from the radio subsystem, you | 158 For every good traffic frame (BFI=0) you receive from the radio subsystem, you |
| 146 deviates from the SID codeword by 16 or more bits, per GSM 06.31 section 6.1.1), | 166 deviates from the SID codeword by 16 or more bits, per GSM 06.31 section 6.1.1), |
| 147 then the frame (considered a good speech frame) will be left unmodified (i.e., | 167 then the frame (considered a good speech frame) will be left unmodified (i.e., |
| 148 it is to be passed unchanged to the GSM 06.10 decoder), but preprocessor state | 168 it is to be passed unchanged to the GSM 06.10 decoder), but preprocessor state |
| 149 will be updated. OTOH, if the received frame is classified as either valid or | 169 will be updated. OTOH, if the received frame is classified as either valid or |
| 150 invalid SID per GSM 06.31, then the output frame will contain comfort noise | 170 invalid SID per GSM 06.31, then the output frame will contain comfort noise |
| 151 generated by the preprocessor using a PRNG, or a silence frame in one particular | 171 generated by the preprocessor using a PRNG, or a speech muting or silence frame |
| 152 corner case. | 172 in some corner cases involving invalid SID. |
| 153 | 173 |
| 154 GSM-FR RTP (originally libgsm) 0xD magic: the upper nibble of the first byte | 174 GSM-FR RTP (originally libgsm) 0xD magic: the upper nibble of the first byte |
| 155 can be anything on input to gsmfr_preproc_good_frame(), but the output frame | 175 can be anything on input to gsmfr_preproc_good_frame(), but the output frame |
| 156 will always have the correct magic in it. | 176 will always have the correct magic in it. |
| 157 | 177 |
| 178 There is also a variant of this function (implemented as a wrapper) that applies | |
| 179 homing logic: | |
| 180 | |
| 181 void gsmfr_preproc_good_frame_hm(struct gsmfr_preproc_state *state, | |
| 182 uint8_t *frame); | |
| 183 | |
| 184 This function operates just like plain gsmfr_preproc_good_frame() except for | |
| 185 one difference: if the input matches the decoder homing frame (DHF), the state | |
| 186 is reset with an internal call to gsmfr_preproc_reset(). (Because the DHF is | |
| 187 still a good speech frame, it is always passed through to the output unchanged | |
| 188 by both functions - the only difference is the effect on subsequent state.) | |
| 189 The homing version of good frame preproc is intended for TFO applications, and | |
| 190 is invoked internally by gsmfr_tfo_xfrm_main() function described in a later | |
| 191 section of this document. | |
| 192 | |
| 158 Handling BFI conditions | 193 Handling BFI conditions |
| 159 ----------------------- | 194 ----------------------- |
| 160 | 195 |
| 161 If you received a lost/missing frame indication instead of a good traffic frame, | 196 If you received a lost/missing frame indication instead of a good traffic frame, |
| 162 call this preprocessor function: | 197 call one of these preprocessor functions: |
| 163 | 198 |
| 164 void gsmfr_preproc_bfi(struct gsmfr_preproc_state *state, int taf, | 199 void gsmfr_preproc_bfi(struct gsmfr_preproc_state *state, int taf, |
| 165 uint8_t *frame_out); | 200 uint8_t *frame_out); |
| 201 | |
| 202 or | |
| 203 | |
| 204 void gsmfr_preproc_bfi_bits(struct gsmfr_preproc_state *state, | |
| 205 const uint8_t *bad_frame, int taf, | |
| 206 uint8_t *frame_out); | |
| 207 | |
| 208 gsmfr_preproc_bfi_bits() should be called if you received payload bits along | |
| 209 with the BFI flag; plain gsmfr_preproc_bfi() should be called if you received | |
| 210 BFI with no data. The bad frame passed to gsmfr_preproc_bfi_bits() is used | |
| 211 only to check if the BFI should be handled as an invalid SID rather than the | |
| 212 more common case of an unusable frame - see GSM 06.31 for definitions of these | |
| 213 terms. Past the SID check, the bad frame content is a don't-care, and there is | |
| 214 no provision for making any use of erroneous frames like in EFR. | |
| 166 | 215 |
| 167 TAF is a flag defined in GSM 06.31 section 6.1.1; if you don't have this flag, | 216 TAF is a flag defined in GSM 06.31 section 6.1.1; if you don't have this flag, |
| 168 pass 0 - you will lose the function of comfort noise muting in the event of | 217 pass 0 - you will lose the function of comfort noise muting in the event of |
| 169 prolonged SID loss, but all other Rx DTX functions will still work the same. | 218 prolonged SID loss, but all other Rx DTX functions will still work the same. |
| 170 | 219 |
| 171 With this function the 33-byte frame buffer is only an output, i.e., prior | 220 With both functions the 33-byte buffer pointed to by frame_out is only an |
| 172 buffer content is a don't-care and there is no provision for making any use of | 221 output, i.e., prior buffer content is a don't-care. The frame generated by the |
| 173 erroneous frames like in EFR. The frame generated by the preprocessor may be | 222 preprocessor may be substitution/muting, comfort noise or silence depending on |
| 174 substitution/muting, comfort noise or silence depending on the state. | 223 the state. |
| 224 | |
| 225 gsmfr_preproc_bfi_bits() arguments bad_frame and frame_out can point to the | |
| 226 same memory: the function finishes analyzing bad_frame input before it starts | |
| 227 writing to frame_out. | |
| 175 | 228 |
| 176 GSM-FR full decoder | 229 GSM-FR full decoder |
| 177 =================== | 230 =================== |
| 178 | 231 |
| 179 The full decoder is a high-level feature of libgsmfr2, incorporating both the | 232 The full decoder is a high-level feature of libgsmfr2, incorporating both the |
| 186 | 239 |
| 187 struct gsmfr_fulldec_state *gsmfr_fulldec_create(void); | 240 struct gsmfr_fulldec_state *gsmfr_fulldec_create(void); |
| 188 | 241 |
| 189 void gsmfr_fulldec_reset(struct gsmfr_fulldec_state *state); | 242 void gsmfr_fulldec_reset(struct gsmfr_fulldec_state *state); |
| 190 | 243 |
| 244 extern const unsigned gsmfr_fulldec_state_size; | |
| 245 | |
| 191 The reset function internally calls gsmfr_0610_reset() and | 246 The reset function internally calls gsmfr_0610_reset() and |
| 192 gsmfr_preproc_reset(), initializing both processing blocks. | 247 gsmfr_preproc_reset(), initializing both processing blocks. |
| 193 | 248 |
| 194 Frame processing functions are also straightforward: | 249 Frame processing functions are also straightforward: |
| 195 | 250 |
| 197 const uint8_t *frame, int16_t *pcm); | 252 const uint8_t *frame, int16_t *pcm); |
| 198 | 253 |
| 199 void gsmfr_fulldec_bfi(struct gsmfr_fulldec_state *state, int taf, | 254 void gsmfr_fulldec_bfi(struct gsmfr_fulldec_state *state, int taf, |
| 200 int16_t *pcm); | 255 int16_t *pcm); |
| 201 | 256 |
| 202 These functions follow the same pattern as gsmfr_preproc_good_frame() and | 257 void gsmfr_fulldec_bfi_bits(struct gsmfr_fulldec_state *state, |
| 203 gsmfr_preproc_bfi(), but the output is a 160-sample linear PCM buffer. Also | 258 const uint8_t *bad_frame, int taf, int16_t *pcm); |
| 204 note that the frame input to gsmfr_fulldec_good_frame() is const, unlike the | 259 |
| 205 situation with gsmfr_preproc_good_frame() - the copying into a scratchpad | 260 These functions follow the same pattern as gsmfr_preproc_good_frame(), |
| 206 buffer (on the stack) happens inside this "fulldec" wrapper. | 261 gsmfr_preproc_bfi() and gsmfr_preproc_bfi_bits(), but the output is a 160-sample |
| 262 linear PCM buffer. Also note that the frame input to gsmfr_fulldec_good_frame() | |
| 263 is const, unlike the situation with gsmfr_preproc_good_frame() - the copying | |
| 264 into a scratchpad buffer (on the stack) happens inside this "fulldec" wrapper. | |
| 207 | 265 |
| 208 The "fulldec" layer also adds the decoder homing feature: | 266 The "fulldec" layer also adds the decoder homing feature: |
| 209 gsmfr_fulldec_good_frame() detects decoder homing frames and invokes | 267 gsmfr_fulldec_good_frame() detects decoder homing frames and invokes |
| 210 gsmfr_fulldec_reset() when required, and also implements EHF output per the | 268 gsmfr_fulldec_reset() when required, and also implements EHF output per the |
| 211 spec. | 269 spec. |
| 270 | |
| 271 Full decoder RTP input | |
| 272 ---------------------- | |
| 273 | |
| 274 If a network element is receiving GSM-FR input via RTP and needs to feed this | |
| 275 input to the decoder, the RTP payload handler needs to support both the basic | |
| 276 RTP format of ETSI TS 101 318 (also RFC 3551) and the extended RTP format of | |
| 277 TW-TS-001. Depending on the format received, and depending on bit flags in the | |
| 278 TEH octet in the case of TW-TS-001, one of the 3 main processing functions | |
| 279 listed above will need to be called. Seeing that this complex logic should be | |
| 280 abstracted away from applications into the library, we've added the following | |
| 281 wrapper function: | |
| 282 | |
| 283 int gsmfr_fulldec_rtp_in(struct gsmfr_fulldec_state *state, | |
| 284 const uint8_t *rtp_pl, unsigned rtp_pl_len, | |
| 285 int16_t *pcm); | |
| 286 | |
| 287 The input is the received RTP payload: array of bytes and length. It is | |
| 288 acceptable to pass 0 as rtp_pl_len, in which case rtp_pl pointer can be NULL. | |
| 289 The function proceeds as follows: | |
| 290 | |
| 291 * If the input is valid RTP format for GSM-FR (either basic or extended), it is | |
| 292 passed to the appropriate main processing function. Unlike the permissive | |
| 293 stance taken in lower-level functions, RTP input validation includes a check | |
| 294 of 0xD signature of GSM-FR, as well as validation of TEH octet signature and | |
| 295 consistency in the case of TW-TS-001. The return value is 0, indicating that | |
| 296 good input was received. | |
| 297 | |
| 298 * If the input is a zero-length payload (rtp_pl_len is 0, rtp_pl may be NULL), | |
| 299 it is treated like BFI-no-data with TAF=0. The return value is 0, meaning | |
| 300 that this input is still considered valid. | |
| 301 | |
| 302 * All other inputs are considered invalid. Linear PCM output is still generated | |
| 303 by calling gsmfr_fulldec_bfi(), but the return value is -1, signaling invalid | |
| 304 RTP input. | |
| 305 | |
| 306 TFO transform | |
| 307 ============= | |
| 308 | |
| 309 "TFO transform" is the term adopted by Themyscira Wireless for the non-trivial | |
| 310 transform on GSM codec frames called for by the TFO spec, 3GPP TS 28.062 | |
| 311 section C.3.2.1.1. For each of the 3 classic GSM codecs, this transform can | |
| 312 operate in two modes: | |
| 313 | |
| 314 DTXd=0: the input UL frame stream from call leg A may contain SIDs and BFI | |
| 315 frame gaps, but the output to call leg B DL must be 100% valid frames and | |
| 316 SID-free. | |
| 317 | |
| 318 DTXd=1: the output to call leg B DL is allowed to contain both good speech and | |
| 319 valid SID frames, just like the output of a DTX-enabled speech encoder. | |
| 320 Furthermore, it can be presumed that network operators who enable DTXd seek to | |
| 321 reap its benefits in terms of radio interference reduction, hence the | |
| 322 DTXd-enabled TFO transform should actually make use of DTXd capability. | |
| 323 | |
| 324 In the case of GSM-FR codec, the TFO transform with DTXd=0 is identical to the | |
| 325 Rx DTX preprocessor part of the standard endpoint decoder, hence our "preproc" | |
| 326 block is directly suited to serve as such. OTOH, the case of DTXd=1 is | |
| 327 different: heeding the implied need to actually make use of DTXd when possible | |
| 328 requires implementing a transform that is not the same as the preprocessor to | |
| 329 be applied just prior to local GSM 06.10 decoding, hence the DTXd-enabled TFO | |
| 330 transform is a different entity. | |
| 331 | |
| 332 The approach implemented in Themyscira libgsmfr2 is a hybrid: | |
| 333 | |
| 334 * The preprocessor block described earlier in this document functions both as | |
| 335 the necessary component of the full endpoint decoder and as the TFO transform | |
| 336 for DTXd=0. | |
| 337 | |
| 338 * TFO transform for DTXd=1 is implemented as a two-step process: | |
| 339 | |
| 340 1) Regular main processing functions of the preproc block produce output that | |
| 341 is SID-free, containing synthetic "speech" frames in the case of comfort | |
| 342 noise or silence. | |
| 343 | |
| 344 2) A special post-processor function needs to be called immediately afterward. | |
| 345 This function selectively transforms some output frames into SIDs based on | |
| 346 a flag set in the state structure. | |
| 347 | |
| 348 In order to make this approach possible, all main processing functions of the | |
| 349 preproc block do a little bit of extra housekeeping to keep track of whether or | |
| 350 not their output can be replaced with SID, logic that is unnecessary when this | |
| 351 block functions as part of the full endpoint decoder or as non-DTXd TFO | |
| 352 transform. However, this logic is very simple and the overhead is very light. | |
| 353 | |
| 354 TFO transform API | |
| 355 ----------------- | |
| 356 | |
| 357 The state structure was already described earlier: it is | |
| 358 struct gsmfr_preproc_state, created either with gsmfr_preproc_create() or by | |
| 359 externally allocating the needed memory based on gsmfr_preproc_state_size and | |
| 360 then initializing it with gsmfr_preproc_reset(). The following API functions | |
| 361 are then available: | |
| 362 | |
| 363 int gsmfr_tfo_xfrm_main(struct gsmfr_preproc_state *state, | |
| 364 const uint8_t *rtp_in, unsigned rtp_in_len, | |
| 365 uint8_t *frame_out); | |
| 366 | |
| 367 int gsmfr_tfo_xfrm_dtxd(struct gsmfr_preproc_state *state, uint8_t *frame_out); | |
| 368 | |
| 369 gsmfr_tfo_xfrm_main() is the TFO transform counterpart to | |
| 370 gsmfr_fulldec_rtp_in(), described in detail earlier. It is also possible (and | |
| 371 allowed) to call gsmfr_preproc_* main processing functions directly, but the | |
| 372 RTP wrapper is convenient for the same reasons as in the case of the full | |
| 373 decoder. In this mode of usage, the only difference between the full decoder | |
| 374 and the TFO transform is that the former emits linear PCM output, whereas the | |
| 375 latter emits 33-byte GSM-FR codec frames to be sent to call leg B downlink. | |
| 376 | |
| 377 If DTXd is in use, then the call to gsmfr_tfo_xfrm_main() needs to be directly | |
| 378 followed by a call to gsmfr_tfo_xfrm_dtxd(), operating on the same output buffer | |
| 379 with the same state structure. The output will then be changed to SID when | |
| 380 appropriate for the current state. | |
| 381 | |
| 382 TFO transform homing | |
| 383 -------------------- | |
| 384 | |
| 385 3GPP specs are silent on whether or not TFO transforms should implement homing, | |
| 386 i.e., whether or not they should reset to home state when a decoder homing frame | |
| 387 passes through. However, at Themyscira Wireless we believe in building | |
| 388 deterministic systems whose bit-exact behavior can be modeled and relied upon; | |
| 389 for this reason, our implementation of TFO transform does include in-band | |
| 390 homing. In accord with this design decision, gsmfr_tfo_xfrm_main() internally | |
| 391 calls gsmfr_preproc_good_frame_hm() described earlier instead of plain | |
| 392 gsmfr_preproc_good_frame(). | |
| 393 | |
| 394 With DTXd=1, if a stream of DHFs is input to the TFO transform, the same stream | |
| 395 of DHFs will appear on the output, i.e., DTXd won't kick in. (The same behavior | |
| 396 occurs in a standard 3GPP-compliant speech encoder whose input is a stream of | |
| 397 0xD5 octets in PCMA or 0xFE in PCMU.) However, any BFIs following this DHF | |
| 398 will be immediately converted to SID, under the same conditions when our TFO | |
| 399 transform with DTXd=0 emits silence frames of GSM 06.11. | |
| 212 | 400 |
| 213 Stateless utility functions | 401 Stateless utility functions |
| 214 =========================== | 402 =========================== |
| 215 | 403 |
| 216 Conversions between RTP packed format and broken-down codec parameters are | 404 Conversions between RTP packed format and broken-down codec parameters are |
