FreeCalypso > hg > gsm-codec-lib
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. |