comparison doc/FR1-Rx-DTX @ 135:22601ae99434

doc/FR1-Rx-DTX article written
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 11 Dec 2022 07:51:10 +0000
parents
children aa4cdab30dc8
comparison
equal deleted inserted replaced
134:170e03b20337 135:22601ae99434
1 At the level of provided functionality and architectural structure, ETSI GSM
2 specifications for DTX (discontinuous transmission) are very symmetric between
3 FR and EFR: the same DTX functionality is specified for both codecs, with the
4 same overall architecture. However, there is one important difference: in the
5 case of EFR the complete implementation of all DTX functions (for both Tx and
6 Rx) forms an integral and inseparable part of the reference codec (implemented
7 in C) from the beginning, whereas in the case of FR1 the addition of DTX is
8 somewhat of an afterthought. GSM 06.10 defines a "pure" FR codec without any
9 DTX functions, and this most basic spec can be and has been implemented in this
10 "pure" form - classic Unix libgsm from 1990s is a proper, fully compliant
11 implementation of GSM 06.10, but only this spec, without any DTX. In contrast,
12 there has never existed a "pure" implementation of GSM 06.60 EFR codec without
13 associated Tx and Rx DTX functions. Furthermore, there is an important
14 distinction between Tx and Rx DTX handlers for FR1:
15
16 * Anyone who seeks to implement Tx DTX for FR1 would have to dig into the guts
17 of GSM 06.10 encoder and augment it with VAD and SID encoding functions per
18 GSM 06.32 and 06.12 specs.
19
20 * In contrast, the Rx DTX handler for FR1 is modular: the way it is specified
21 in GSM 06.11, 06.12 and 06.31 is a front-end to unmodified GSM 06.10 decoder.
22 On the Rx side, the interface from the radio subsystem to the Rx DTX handler
23 consists of 260 bits of frame plus BFI and TAF flags (the spec also defines a
24 SID flag, but it is determined from frame payload bits), and then the
25 interface from the Rx DTX handler to the GSM 06.10 decoder is another FR frame
26 of 260 bits.
27
28 What are the implications of this situation for the GSM published-source
29 software community? Prior to the present libgsmfrp offering, there has always
30 been libgsm, but no Rx DTX handler. If you are working with a GSM uplink RTP
31 stream from a BTS or a GSM downlink frame stream read out of TI Calypso DSP or
32 some other GSM MS PHY, feeding that stream directly to libgsm (without passing
33 through an Rx DTX handler) is NOT acceptable: a "bare" GSM 06.10 decoder won't
34 recognize SID frames and won't produce the expected comfort noise output, and
35 what are you going to do in those 20 ms windows in which no good traffic frame
36 was received? The situation becomes especially bad (unkind on ears) if you are
37 reading received downlink frames out of TI Calypso DSP: the DSP's buffer will
38 have *some* bit content in every 20 ms window, but naturally this bit content
39 will be garbage during those frame windows when no good frame was received;
40 feeding that garbage to libgsm produces noises that are very unkind on ears.
41
42 The correct solution is to implement an Rx DTX handler, pass the stream of
43 frames and flags from the BTS or the MS PHY to this handler first, and then pass
44 the output of this handler to libgsm 06.10 decoder. Themyscira libgsmfrp is a
45 Free Software implementation of Rx DTX handler for GSM FR, implementing SID
46 classification, comfort noise generation and error concealment.
47
48 Effect of extra preprocessing
49 =============================
50
51 One key detail deserves extra emphasis before going into library API details:
52 if the input to libgsmfrp consists entirely of good speech frames (no SID frames
53 and no BFIs), then the preprocessor becomes an identity transform. Therefore,
54 if the output of our libgsmfrp preprocessor were to be fed to an additional
55 instance of the same further down the processing chain, no extra transformation
56 of any kind will happen.
57
58 Using libgsmfrp
59 ===============
60
61 The external public interface to Themyscira libgsmfrp consists of a single
62 header file <gsm_fr_preproc.h>; it should be installed in the same system
63 include directory as <gsm.h> from libgsm. Please note that <gsm_fr_preproc.h>
64 includes <gsm.h>, as needed for gsm_byte and gsm_frame defined types.
65
66 The dialect of C we chose for libgsmfrp is ANSI C (function prototypes), const
67 qualifier is used where appropriate; however, unlike libgsmefr, the interface
68 to libgsmfrp is defined in terms of gsm_byte type defined in <gsm.h>, included
69 from <gsm_fr_preproc.h>.
70
71 State allocation and freeing
72 ============================
73
74 The Rx DTX handler is stateful, hence you will need to allocate a preprocessor
75 state structure in addition to the usual libgsm state structure for your GSM FR
76 Rx session. The necessary function is:
77
78 extern struct gsmfr_preproc_state *gsmfr_preproc_create(void);
79
80 struct gsmfr_preproc_state is an opaque structure to library users: you only get
81 a pointer which you remember and pass around, but <gsm_fr_preproc.h> does not
82 give you a full definition of this struct. As a library user, you don't even
83 get to know the size of this struct, hence the necessary malloc() operation
84 happens inside gsmfr_preproc_create(). However, the structure is malloc'ed as
85 a single chunk, hence when you are done with it, simply call free() on the
86 pointer you got from gsmfr_preproc_create().
87
88 gsmfr_preproc_create() can fail if the malloc() call inside fails, in which case
89 it returns NULL.
90
91 Preprocessing good frames
92 =========================
93
94 For every good traffic frame (BFI=0) you receive from the radio subsystem, you
95 need to call this preprocessor function:
96
97 extern void gsmfr_preproc_good_frame(struct gsmfr_preproc_state *state,
98 gsm_byte *frame);
99
100 The second argument is both input and output, i.e., the frame is modified in
101 place. If the received frame is not SID (specifically, if the SID field
102 deviates from the SID codeword by 16 or more bits, per GSM 06.31 section 6.1.1),
103 then the frame (considered a good speech frame) will be left unmodified (i.e.,
104 it is to be passed unchanged to the GSM 06.10 decoder), but preprocessor state
105 will be updated. OTOH, if the received frame is classified as either valid or
106 invalid SID per GSM 06.31, then the output frame will contain comfort noise
107 generated by the preprocessor using a PRNG, or a silence frame in one particular
108 corner case.
109
110 GSM-FR RTP (or libgsm) 0xD magic: the upper nibble of the first byte can be
111 anything on input to gsmfr_preproc_good_frame(), but the output frame will
112 always have the correct magic in it.
113
114 Handling BFI conditions
115 =======================
116
117 If you received a lost/missing frame indication instead of a good traffic frame,
118 call this preprocessor function:
119
120 extern void gsmfr_preproc_bfi(struct gsmfr_preproc_state *state, int taf,
121 gsm_byte *frame_out);
122
123 TAF is a flag defined in GSM 06.31 section 6.1.1; if you don't have this flag,
124 pass 0 - you will lose the function of comfort noise muting in the event of
125 prolonged SID loss, but all other Rx DTX functions will still work the same.
126
127 With this function the 33-byte frame buffer is only an output, i.e., prior
128 buffer content is a don't-care and there is no provision for making any use of
129 erroneous frames like in EFR. The frame generated by the preprocessor may be
130 substitution/muting, comfort noise or silence depending on the state.
131
132 Other miscellaneous functions
133 =============================
134
135 extern void gsmfr_preproc_reset(struct gsmfr_preproc_state *state);
136
137 This function resets the preprocessor state to what it is right out of
138 gsmfr_preproc_create(), which is naturally just a combination of malloc() and
139 gsmfr_proproc_reset(). Given that our Rx DTX handler state is much simpler
140 than, for example, EFR codec state, there does not seem to be any need for
141 explicit resets, but the reset function is made public for the sake of
142 completeness.
143
144 extern int gsmfr_preproc_sid_classify(const gsm_byte *frame);
145
146 This function analyzes an RTP-encoded FR frame (the upper nibble of the first
147 byte is NOT checked for 0xD signature) for the SID codeword of GSM 06.12 and
148 classifies the frame as SID=0, SID=1 or SID=2 per the rules of GSM 06.31
149 section 6.1.1.
150
151 Silence frame datum
152 ===================
153
154 extern const gsm_frame gsmfr_preproc_silence_frame;
155
156 Many implementors make the mistake of thinking that a GSM FR silence frame is a
157 frame of 260 zero bits, but the official specs disagree: the silence frame given
158 in GSM 06.11 (3GPP TS 46.011, at the very end of the spec) is quite different.
159 Themyscira libgsmfrp implements the correct silence frame per the spec, and that
160 datum is also made public.