changeset 633:3ab76caba41c

doc/HR-codec-library: document stateless utility functions
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 20 Mar 2026 02:17:55 +0000
parents 7fc57e2a6784
children 4c5a4fcf9236
files doc/HR-codec-library
diffstat 1 files changed, 170 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/doc/HR-codec-library	Thu Mar 19 04:13:45 2026 +0000
+++ b/doc/HR-codec-library	Fri Mar 20 02:17:55 2026 +0000
@@ -248,3 +248,173 @@
 proceeds by applying classic Rx front end processing that only emits speech
 frames, and then replacing output with SID frames under certain conditions if
 DTXd is enabled.
+
+Stateless utility functions
+===========================
+
+All functions in this section are stateless (no encoder, decoder or RxFE state
+structure is needed); they merely manipulate data formats.
+
+void gsmhr_pack_ts101318(const int16_t *param, uint8_t *payload);
+
+This function converts a 112-bit GSM-HR codec frame from an array of speech
+parameters (18 16-bit words) into the packed format of ETSI TS 101 318, which
+is a buffer of 14 octets with every bit used for payload.  Any extraneous bits
+in input 16-bit words (beyond the size of each parameter in bits) are ignored.
+
+void gsmhr_unpack_ts101318(const uint8_t *payload, int16_t *param);
+
+This function converts a 112-bit GSM-HR codec frame from the packed format of
+TS 101 318 into an array of 18 speech parameters.
+
+void gsmhr_encoder_twts002_out(const int16_t *param, uint8_t *payload);
+
+This function converts a cod-style frame (output from gsmhr_encode_frame() or
+gsmhr_tfo_xfrm(), or read from an ETSI *.cod file) into TW-TS-002 format.  The
+output is always 15 octets long (the buffer must have this much room), and is
+valid per both RFC 5993 and TW-TS-002 specs.  The only two possible frame types
+in this context are good speech and good SID, distinguished by SP flag in the
+cod-style input and by FT field in RFC 5993 output.
+
+int gsmhr_decoder_twts002_in(const uint8_t *payload, int16_t *param);
+
+This function reads a super-5993 frame in TW-TS-002 format from a buffer and
+converts it into the required form for input to gsmhr_decode_frame() or
+gsmhr_tfo_xfrm(), which is an extended form of ETSI's *.dec format.  The input
+must be a valid super-5993 in the following sense:
+
+* The first octet in the buffer must be valid ToC per TW-TS-002 section 5.1;
+
+* F bit in this ToC octet must be cleared;
+
+* FT field must equal 0, 1, 2, 6 or 7 per TW-TS-002 section 5.2;
+
+* If FT equals 0, 2 or 6, the ToC octet must be followed by 14 octets of frame
+  payload.
+
+If any of these rules are violated, gsmhr_decoder_twts002_in() returns a
+negative value (-1 if F bit is set or -2 if FT is invalid) and does not write
+anything into the output array.  Otherwise, the function returns 0 (indicating
+success) and the output array is filled as follows:
+
+* For frame types 0, 2 and 6, the 18 speech parameters are filled from the
+  TS-101-318-like payload portion of super-5993 input.
+
+* For frame types 1 and 7, the 18 speech parameters are set to all zeros, with
+  the expectation that gsmhr_decode_frame() or gsmhr_tfo_xfrm() will ignore
+  them.  Please note that "verbose" invalid SID bits that may be present in
+  TW-TS-002 transport are ignored.
+
+* The 4 metadata flags BFI, UFI, SID and TAF are set based on FT and the
+  additional ToC flags defined in TW-TS-002 section 5.3.
+
+* Themyscira extension of BFI=2, described earlier in this document, is used
+  to represent FT=7.
+
+* Invalid SID frames (FT=1) are converted to BFI=1 SID=1.
+
+int gsmhr_rtp_in_preen(const uint8_t *rtp_in, unsigned rtp_in_len,
+			uint8_t *canon_pl);
+
+This function performs initial processing of RTP input that is expected to be
+one of the defined RTP formats for GSM-HR codec.  It accepts all possibilities
+of TW-TS-002, RFC 5993 or TS 101 318 (listed in ThemWi order of preference) and
+writes canonical TW-TS-002 super-5993 format into a buffer.  The output buffer
+must have 15 bytes of space, and the frame written into this buffer will ALWAYS
+be a valid input to gsmhr_decoder_twts002_in() function described above.
+
+The input arguments are RTP payload and its length.  The return value is 0 if
+RTP input was in a recognized format, or -1 if it is invalid.  In the case of
+invalid RTP input, the output is filled with ToC of 0x70 (BFI with no data) -
+the output is always valid.
+
+Zero-length RTP payloads are acceptable; if rtp_in_len is 0, then rtp_in pointer
+may be NULL.  The output in this case is filled with ToC of 0x70 (BFI with no
+data), but the return value is 0, indicating success.  The intent is that truly
+invalid RTP payloads are error events which should be counted, while NULL input
+is a normal occurrence when ThemWi jitter buffer (twjit) does not hold a
+previously received RTP packet that maps to the current tick.  (Actually
+transmitted RTP packets with a zero-length payloads are also possible: they are
+ThemWi preferred alternative to IETF approach of intentional gaps in the RTP
+stream.)
+
+int gsmhr_rtp_in_direct(const uint8_t *rtp_in, unsigned rtp_in_len,
+			int16_t *param);
+
+This function is fully equivalent to calling first gsmhr_rtp_in_preen(), then
+gsmhr_decoder_twts002_in().  It is however slightly more efficient, as it avoids
+the intermediate buffer and some copying.  The return value is the same as
+gsmhr_rtp_in_preen(), and just like with that function, the output is always
+valid.
+
+Reading *.cod and *.dec files
+-----------------------------
+
+The most native representation format for GSM-HR codec frames in libgsmhr1 is
+arrays of broken-down speech parameters.  However, unlike TS 101 318 format in
+which every possible bit pattern is a plausible GSM-HR codec frame, an array of
+broken-down parameters that purports to be a GSM-HR frame can contain garbage.
+The additional metadata flags in the canonical decoder input format can also
+contain garbage - which our speech decoder and TFO transform engines are NOT
+prepared for!  There is no potential for malfunction if these arrays of
+parameters and metadata flags come only from libgsmhr1 functions - but if an
+application needs to read *.cod or *.dec files, or otherwise accept external
+input in any of these formats, then an explicit validation step is required.
+
+int gsmhr_check_common_params(const int16_t *params);
+
+This function examines an array of 18 codec parameters in the int16_t
+representation used in this library, and checks if the unused upper bits of
+each int16_t word are cleared as they should be.  The return value is 0 if the
+frame is valid or -1 if some extraneous high bits are set.
+
+int gsmhr_check_encoder_params(const int16_t *params);
+
+This function examines a frame of 20 int16_t words that corresponds to GSM-HR
+encoder output format, and checks if the unused upper bits of each int16_t word
+are cleared as they should be.  This function should be used when reading from
+ETSI-format *.cod files, to guard against reading garbage or wrong endian.  The
+return value is 0 if the frame is valid or -1 if some extraneous high bits are
+set.
+
+int gsmhr_check_decoder_params(const int16_t *params);
+
+This function examines a frame of 22 int16_t words that corresponds to GSM-HR
+decoder input format, and checks if the unused upper bits of each int16_t word
+are cleared as they should be.  This function should be used when reading from
+ETSI-format *.dec files, to guard against reading garbage or wrong endian.  The
+return value is 0 if the frame is valid or -1 if some extraneous high bits are
+set.  Both BFI and SID words are limited to range [0,2], i.e., Themyscira BFI=2
+extension is accepted.
+
+SID field manipulation
+----------------------
+
+Unlike FR and EFR, GSM-HR codec lacks fixed rules for Rx frame classification
+as valid SID, invalid SID or non-SID speech.  The BTS makes this classification
+decision according to its internal private rules, and the SID flag then needs
+to be carried out of band in Abis, Ater and TFO.  GSM 08.61 and TW-TS-002
+(extended 5993) formats provide the necessary out-of-band SID indication, but
+the bare format of TS 101 318 does not.  Therefore, the only kind of GSM-HR SID
+that can be represented in TS 101 318 format are perfect, 100% error-free SID
+frames in which all 79 bits of the SID field are set to 1.
+
+int gsmhr_ts101318_is_perfect_sid(const uint8_t *payload);
+
+This function checks the given TS 101 318 payload for the possibility of
+perfect SID.  The return value is 2 (GSM 06.41 code for valid SID) if the frame
+is indeed a perfect SID, or 0 (GSM 06.41 code for non-SID speech) otherwise.
+
+void gsmhr_ts101318_set_sid_codeword(uint8_t *payload);
+
+This function sets all 79 bits of the SID field to 1s, forming a perfect SID
+frame in the 14-byte buffer.  The first 33 bits that carry R0 and LPC parameters
+must already be filled correctly.
+
+void gsmhr_set_sid_cw_params(int16_t *params);
+
+This function fills parameters 4 through 17 of generated SID frames, setting
+them to the required SID codeword.  It can also be used to transform a speech
+frame into a SID frame with the same R0 and LPC parameters.  It is logically
+equivalent to gsmhr_ts101318_set_sid_codeword(), but operates on the array of
+parameters form, rather than TS 101 318 packed format.