comparison doc/EFR-library-API @ 123:92fdb499b5c3

doc/EFR-library-API article written
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 10 Dec 2022 22:01:14 +0000
parents
children 1c529bb31219
comparison
equal deleted inserted replaced
122:b33f2168fdec 123:92fdb499b5c3
1 The external public interface to Themyscira libgsmefr consists of a single
2 header file <gsm_efr.h>; it should be installed in the same system include
3 directory as <gsm.h> from classic libgsm (1990s free software product) for the
4 original FR codec, and the API of libgsmefr is modeled after that of libgsm.
5
6 The dialect of C we chose for libgsmefr is ANSI C (function prototypes), const
7 qualifier is used where appropriate, and the interface is defined in terms of
8 <stdint.h> types; <gsm_efr.h> includes <stdint.h>.
9
10 State allocation and freeing
11 ============================
12
13 In order to use the EFR encoder, you will need to allocate an encoder state
14 structure, and to use the EFR decoder, you will need to allocate a decoder state
15 structure. The necessary state allocation functions are:
16
17 extern struct EFR_encoder_state *EFR_encoder_create(int dtx);
18 extern struct EFR_decoder_state *EFR_decoder_create(void);
19
20 struct EFR_encoder_state and struct EFR_decoder_state are opaque structures to
21 library users: you only get pointers which you remember and pass around, but
22 <gsm_efr.h> does not give you full definitions of these structs. As a library
23 user, you don't even get to know the size of these structs, hence the necessary
24 malloc() operation happens inside EFR_encoder_create() and EFR_decoder_create().
25 However, each structure is malloc'ed as a single chunk, hence when you are done
26 with it, simply call free() to relinquish each encoder or decoder state
27 instance.
28
29 EFR_encoder_create() and EFR_decoder_create() functions can fail if the malloc()
30 call inside fails, in which case the two libgsmefr functions in question return
31 NULL.
32
33 The dtx argument to EFR_encoder_create() is a Boolean flag represented as an
34 int; it tells the EFR encoder whether it should operate with DTX enabled (run
35 GSM 06.82 VAD and emit SID frames instead of speech frames per GSM 06.81) or DTX
36 disabled (skip VAD and always emit speech frames).
37
38 Using the EFR encoder
39 =====================
40
41 To encode one 20 ms audio frame per EFR, call EFR_encode_frame():
42
43 extern void EFR_encode_frame(struct EFR_encoder_state *st, const int16_t *pcm,
44 uint8_t *frame, int *sp, int *vad);
45
46 You need to provide an encoder state structure allocated earlier with
47 EFR_encoder_create(), a block of 160 linear PCM samples, and an output buffer of
48 31 bytes (EFR_RTP_FRAME_LEN constant also defined in <gsm_efr.h>) into which the
49 encoded EFR frame will be written; the frame format is that defined in ETSI TS
50 101 318 for EFR in RTP, including the 0xC signature in the upper nibble of the
51 first byte.
52
53 The last two arguments of type (int *) are optional pointers to extra output
54 flags SP and VAD, defined in GSM 06.81 section 5.1.1; either pointer or both of
55 them can be NULL if these extra output flags aren't needed. Both of these flags
56 are needed in order to test our libgsmefr encoder implementation against
57 official ETSI test sequences (GSM 06.54), but they typically aren't needed
58 otherwise.
59
60 Using the EFR decoder
61 =====================
62
63 The main interface to our EFR decoder is this function:
64
65 extern void EFR_decode_frame(struct EFR_decoder_state *st, const uint8_t *frame,
66 int bfi, int taf, int16_t *pcm);
67
68 The inputs consist of 244 bits of frame payload (the 4 upper bits of the first
69 byte are ignored - there is NO enforcement of 0xC signature in our frame
70 decoder) and BFI and TAF flags defined in GSM 06.81 section 6.1.1. Note the
71 absence of a SID flag argument: EFR_decode_frame() calls our own utility
72 function EFR_sid_classify() to determine SID from the frame itself per the rules
73 of GSM 06.81 section 6.1.1.
74
75 Many EFR decoder applications will also be faced with a situation where they
76 receive a frame gap (no data at all), and they need to run the EFR decoder with
77 BFI=1, but don't have any frame-bits input. If you find yourself in this
78 situation, call the following function:
79
80 extern void EFR_decode_bfi_nodata(struct EFR_decoder_state *st, int taf,
81 int16_t *pcm);
82
83 EFR_decode_bfi_nodata() is equivalent to calling EFR_decode_frame() with a frame
84 buffer of 31 zero bytes (or 0xC signature followed by 244 zero bits) and BFI=1,
85 but is slightly more efficient in that the internal steps of EFR_frame2params()
86 and EFR_sid_classify() are skipped, and the made-up "frame" of 244 zero bits is
87 passed to the decoder core at the params array level.
88
89 Note that the official EFR decoder from ETSI, which we've replicated in our
90 librified form in libgsmefr, does make use of some presumed-invalid frame data
91 bits under BFI=1 conditions: see the description in GSM 06.61 section 6.1, where
92 the last sentence reads "The received fixed codebook excitation pulses from the
93 erroneous frame are always used as such." With our current implementation, the
94 "erroneous frame" in the case of completely lost or missing frames is a made-up
95 frame of 244 zero bits; the question of whether this approach is good enough or
96 if we need to do something more complex remains for further study.
97
98 Stateless utility functions
99 ===========================
100
101 All functions in this section are stateless (no encoder state or decoder state
102 structure is needed); they merely manipulate bit fields.
103
104 extern void EFR_frame2params(const uint8_t *frame, int16_t *params);
105
106 This function unpacks an EFR codec frame in ETSI TS 101 318 RTP encoding (the
107 upper nibble of the first byte is NOT checked, i.e., there is NO enforcement of
108 0xC signature) into an array of 57 (EFR_NUM_PARAMS) parameter words for the
109 codec. int16_t signed type is used for the params array (even though all
110 parameters are actually unsigned) in order to match the guts of ETSI-based EFR
111 codec, and EFR_frame2params() is called internally by EFR_decode_frame().
112
113 extern void EFR_params2frame(const int16_t *params, uint8_t *frame);
114
115 This function takes an array of 57 (EFR_NUM_PARAMS) EFR codec parameter words
116 and packs them into a 31-byte (EFR_RTP_FRAME_LEN) frame in ETSI TS 101 318
117 format. The 0xC signature is generated by this function, and every byte of the
118 output buffer is fully written without regard to any previous content. This
119 function is called internally by EFR_encode_frame().
120
121 extern int EFR_sid_classify(const uint8_t *frame);
122
123 This function analyzes an RTP-encoded EFR frame (the upper nibble of the first
124 byte is NOT checked for 0xC signature) for the SID codeword of GSM 06.62 and
125 classifies the frame as SID=0, SID=1 or SID=2 per the rules of GSM 06.81
126 section 6.1.1.
127
128 extern void EFR_insert_sid_codeword(uint8_t *frame);
129
130 This function inserts the SID codeword of GSM 06.62 into the frame in the
131 pointed-to buffer; specifically, the 95 bits that make up the SID field are all
132 set to 1s, but all other bits remain unchanged. This function is arguably least
133 useful to external users of libgsmefr, but it exists because of how the original
134 code from ETSI generates SID frames produced by the encoder in DTX mode.
135
136 Parameter-based encoder and decoder functions
137 =============================================
138
139 The EFR_encode_frame() and EFR_decode_frame() functions described earlier in
140 this document constitute the most practically useful (intended for actual use)
141 interfaces to our EFR encoder and decoder, but they are actually wrappers around
142 these parameter-based functions:
143
144 extern void EFR_encode_params(struct EFR_encoder_state *st, const int16_t *pcm,
145 int16_t *params, int *sp, int *vad);
146
147 This function is similar to EFR_encode_frame(), but the output is an array of
148 57 (EFR_NUM_PARAMS) codec parameter words rather than a finished frame. The two
149 extra output flags are optional (pointers may be NULL) just like with
150 EFR_encode_frame(), but there is a catch: if the output frame is a SID (which
151 can only happen if DTX is enabled), the bits inside parameter words that would
152 correspond to SID codeword bits are NOT set, instead one MUST call
153 EFR_insert_sid_codeword() after packing the frame with EFR_params2frame(). The
154 wrapper in EFR_encode_frame() does exactly as described, and the overall logic
155 follows the original code structure from ETSI.
156
157 extern void EFR_decode_params(struct EFR_decoder_state *st,
158 const int16_t *params, int bfi, int sid, int taf,
159 int16_t *pcm);
160
161 This function is similar to EFR_decode_frame() with the frame input replaced
162 with params array input, but the SID classification per the rules of GSM 06.81
163 section 6.1.1 needs to be provided by the caller. The wrapper in
164 EFR_decode_frame() calls both EFR_frame2params() and EFR_sid_classify() before
165 passing the work to EFR_decode_params().
166
167 State reset functions
168 =====================
169
170 extern void EFR_encoder_reset(struct EFR_encoder_state *st, int dtx);
171 extern void EFR_decoder_reset(struct EFR_decoder_state *st);
172
173 These functions reset the state of the encoder or the decoder, respectively;
174 the entire state structure is fully initialized to the respective home state
175 defined in GSM 06.60 section 8.5 for the encoder or section 8.6 for the decoder.
176
177 EFR_encoder_reset() is called internally by EFR_encoder_create() and by the
178 encoder itself when it encounters the ETSI-prescribed encoder homing frame;
179 EFR_decoder_reset() is called internally by EFR_decoder_create() and by the
180 decoder itself when it encounters the ETSI-prescribed decoder homing frame.
181 Therefore, there is generally no need for libgsmefr users to call these
182 functions directly - but they are made public for the sake of completeness.