changeset 135:22601ae99434

doc/FR1-Rx-DTX article written
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 11 Dec 2022 07:51:10 +0000
parents 170e03b20337
children 8eb0e7a39409
files doc/FR1-Rx-DTX
diffstat 1 files changed, 160 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/FR1-Rx-DTX	Sun Dec 11 07:51:10 2022 +0000
@@ -0,0 +1,160 @@
+At the level of provided functionality and architectural structure, ETSI GSM
+specifications for DTX (discontinuous transmission) are very symmetric between
+FR and EFR: the same DTX functionality is specified for both codecs, with the
+same overall architecture.  However, there is one important difference: in the
+case of EFR the complete implementation of all DTX functions (for both Tx and
+Rx) forms an integral and inseparable part of the reference codec (implemented
+in C) from the beginning, whereas in the case of FR1 the addition of DTX is
+somewhat of an afterthought.  GSM 06.10 defines a "pure" FR codec without any
+DTX functions, and this most basic spec can be and has been implemented in this
+"pure" form - classic Unix libgsm from 1990s is a proper, fully compliant
+implementation of GSM 06.10, but only this spec, without any DTX.  In contrast,
+there has never existed a "pure" implementation of GSM 06.60 EFR codec without
+associated Tx and Rx DTX functions.  Furthermore, there is an important
+distinction between Tx and Rx DTX handlers for FR1:
+
+* Anyone who seeks to implement Tx DTX for FR1 would have to dig into the guts
+  of GSM 06.10 encoder and augment it with VAD and SID encoding functions per
+  GSM 06.32 and 06.12 specs.
+
+* In contrast, the Rx DTX handler for FR1 is modular: the way it is specified
+  in GSM 06.11, 06.12 and 06.31 is a front-end to unmodified GSM 06.10 decoder.
+  On the Rx side, the interface from the radio subsystem to the Rx DTX handler
+  consists of 260 bits of frame plus BFI and TAF flags (the spec also defines a
+  SID flag, but it is determined from frame payload bits), and then the
+  interface from the Rx DTX handler to the GSM 06.10 decoder is another FR frame
+  of 260 bits.
+
+What are the implications of this situation for the GSM published-source
+software community?  Prior to the present libgsmfrp offering, there has always
+been libgsm, but no Rx DTX handler.  If you are working with a GSM uplink RTP
+stream from a BTS or a GSM downlink frame stream read out of TI Calypso DSP or
+some other GSM MS PHY, feeding that stream directly to libgsm (without passing
+through an Rx DTX handler) is NOT acceptable: a "bare" GSM 06.10 decoder won't
+recognize SID frames and won't produce the expected comfort noise output, and
+what are you going to do in those 20 ms windows in which no good traffic frame
+was received?  The situation becomes especially bad (unkind on ears) if you are
+reading received downlink frames out of TI Calypso DSP: the DSP's buffer will
+have *some* bit content in every 20 ms window, but naturally this bit content
+will be garbage during those frame windows when no good frame was received;
+feeding that garbage to libgsm produces noises that are very unkind on ears.
+
+The correct solution is to implement an Rx DTX handler, pass the stream of
+frames and flags from the BTS or the MS PHY to this handler first, and then pass
+the output of this handler to libgsm 06.10 decoder.  Themyscira libgsmfrp is a
+Free Software implementation of Rx DTX handler for GSM FR, implementing SID
+classification, comfort noise generation and error concealment.
+
+Effect of extra preprocessing
+=============================
+
+One key detail deserves extra emphasis before going into library API details:
+if the input to libgsmfrp consists entirely of good speech frames (no SID frames
+and no BFIs), then the preprocessor becomes an identity transform.  Therefore,
+if the output of our libgsmfrp preprocessor were to be fed to an additional
+instance of the same further down the processing chain, no extra transformation
+of any kind will happen.
+
+Using libgsmfrp
+===============
+
+The external public interface to Themyscira libgsmfrp consists of a single
+header file <gsm_fr_preproc.h>; it should be installed in the same system
+include directory as <gsm.h> from libgsm.  Please note that <gsm_fr_preproc.h>
+includes <gsm.h>, as needed for gsm_byte and gsm_frame defined types.
+
+The dialect of C we chose for libgsmfrp is ANSI C (function prototypes), const
+qualifier is used where appropriate; however, unlike libgsmefr, the interface
+to libgsmfrp is defined in terms of gsm_byte type defined in <gsm.h>, included
+from <gsm_fr_preproc.h>.
+
+State allocation and freeing
+============================
+
+The Rx DTX handler is stateful, hence you will need to allocate a preprocessor
+state structure in addition to the usual libgsm state structure for your GSM FR
+Rx session.  The necessary function is:
+
+extern struct gsmfr_preproc_state *gsmfr_preproc_create(void);
+
+struct gsmfr_preproc_state is an opaque structure to library users: you only get
+a pointer which you remember and pass around, but <gsm_fr_preproc.h> does not
+give you a full definition of this struct.  As a library user, you don't even
+get to know the size of this struct, hence the necessary malloc() operation
+happens inside gsmfr_preproc_create().  However, the structure is malloc'ed as
+a single chunk, hence when you are done with it, simply call free() on the
+pointer you got from gsmfr_preproc_create().
+
+gsmfr_preproc_create() can fail if the malloc() call inside fails, in which case
+it returns NULL.
+
+Preprocessing good frames
+=========================
+
+For every good traffic frame (BFI=0) you receive from the radio subsystem, you
+need to call this preprocessor function:
+
+extern void gsmfr_preproc_good_frame(struct gsmfr_preproc_state *state,
+				     gsm_byte *frame);
+
+The second argument is both input and output, i.e., the frame is modified in
+place.  If the received frame is not SID (specifically, if the SID field
+deviates from the SID codeword by 16 or more bits, per GSM 06.31 section 6.1.1),
+then the frame (considered a good speech frame) will be left unmodified (i.e.,
+it is to be passed unchanged to the GSM 06.10 decoder), but preprocessor state
+will be updated.  OTOH, if the received frame is classified as either valid or
+invalid SID per GSM 06.31, then the output frame will contain comfort noise
+generated by the preprocessor using a PRNG, or a silence frame in one particular
+corner case.
+
+GSM-FR RTP (or libgsm) 0xD magic: the upper nibble of the first byte can be
+anything on input to gsmfr_preproc_good_frame(), but the output frame will
+always have the correct magic in it.
+
+Handling BFI conditions
+=======================
+
+If you received a lost/missing frame indication instead of a good traffic frame,
+call this preprocessor function:
+
+extern void gsmfr_preproc_bfi(struct gsmfr_preproc_state *state, int taf,
+			      gsm_byte *frame_out);
+
+TAF is a flag defined in GSM 06.31 section 6.1.1; if you don't have this flag,
+pass 0 - you will lose the function of comfort noise muting in the event of
+prolonged SID loss, but all other Rx DTX functions will still work the same.
+
+With this function the 33-byte frame buffer is only an output, i.e., prior
+buffer content is a don't-care and there is no provision for making any use of
+erroneous frames like in EFR.  The frame generated by the preprocessor may be
+substitution/muting, comfort noise or silence depending on the state.
+
+Other miscellaneous functions
+=============================
+
+extern void gsmfr_preproc_reset(struct gsmfr_preproc_state *state);
+
+This function resets the preprocessor state to what it is right out of
+gsmfr_preproc_create(), which is naturally just a combination of malloc() and
+gsmfr_proproc_reset().  Given that our Rx DTX handler state is much simpler
+than, for example, EFR codec state, there does not seem to be any need for
+explicit resets, but the reset function is made public for the sake of
+completeness.
+
+extern int gsmfr_preproc_sid_classify(const gsm_byte *frame);
+
+This function analyzes an RTP-encoded FR frame (the upper nibble of the first
+byte is NOT checked for 0xD signature) for the SID codeword of GSM 06.12 and
+classifies the frame as SID=0, SID=1 or SID=2 per the rules of GSM 06.31
+section 6.1.1.
+
+Silence frame datum
+===================
+
+extern const gsm_frame gsmfr_preproc_silence_frame;
+
+Many implementors make the mistake of thinking that a GSM FR silence frame is a
+frame of 260 zero bits, but the official specs disagree: the silence frame given
+in GSM 06.11 (3GPP TS 46.011, at the very end of the spec) is quite different.
+Themyscira libgsmfrp implements the correct silence frame per the spec, and that
+datum is also made public.