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