diff libgsmfr2/pp_bad.c @ 256:a33edf624061

libgsmfr2: start with API definition and port of libgsmfrp code
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 12 Apr 2024 20:49:53 +0000
parents libgsmfrp/bad_frame.c@6ac547f0b903
children 573afa985df6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgsmfr2/pp_bad.c	Fri Apr 12 20:49:53 2024 +0000
@@ -0,0 +1,137 @@
+/*
+ * In this module we implement our handling of BFI frame gaps
+ * and invalid SID frames.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "tw_gsmfr.h"
+#include "pp_internal.h"
+
+static int reduce_xmaxc(uint8_t *frame)
+{
+	int mute_flag = 1;
+	unsigned sub, xmaxc;
+
+	for (sub = 0; sub < 4; sub++) {
+		xmaxc = ((frame[sub*7+6] & 0x1F) << 1) | (frame[sub*7+7] >> 7);
+		if (xmaxc > 4) {
+			xmaxc -= 4;
+			mute_flag = 0;
+		} else
+			xmaxc = 0;
+		frame[sub*7+6] &= 0xE0;
+		frame[sub*7+6] |= xmaxc >> 1;
+		frame[sub*7+7] &= 0x7F;
+		frame[sub*7+7] |= (xmaxc & 1) << 7;
+	}
+	return mute_flag;
+}
+
+static void random_grid_pos(struct gsmfr_preproc_state *st, uint8_t *frame)
+{
+	unsigned sub, Mc;
+
+	for (sub = 0; sub < 4; sub++) {
+		Mc = gsmfr_preproc_prng(st, 2);
+		frame[sub*7+6] &= 0x9F;
+		frame[sub*7+6] |= Mc << 5;
+	}
+}
+
+static int reduce_xmaxc_sid(struct gsmfr_preproc_state *st)
+{
+	if (st->sid_xmaxc > 4) {
+		st->sid_xmaxc -= 4;
+		return 0;
+	} else {
+		st->sid_xmaxc = 0;
+		return 1;
+	}
+}
+
+void gsmfr_preproc_bfi(struct gsmfr_preproc_state *st, int taf, uint8_t *frame)
+{
+	int mute;
+
+	switch (st->rx_state) {
+	case NO_DATA:
+		memcpy(frame, &gsmfr_preproc_silence_frame,
+			GSMFR_RTP_FRAME_LEN);
+		return;
+	case SPEECH:
+		memcpy(frame, &st->speech_frame, GSMFR_RTP_FRAME_LEN);
+		st->rx_state = SPEECH_MUTING;
+		return;
+	case SPEECH_MUTING:
+		mute = reduce_xmaxc(st->speech_frame);
+		memcpy(frame, &st->speech_frame, GSMFR_RTP_FRAME_LEN);
+		random_grid_pos(st, frame);
+		if (mute)
+			st->rx_state = NO_DATA;
+		return;
+	case COMFORT_NOISE:
+		if (taf)
+			st->rx_state = LOST_SID;
+		gsmfr_preproc_gen_cn(st, frame);
+		return;
+	case LOST_SID:
+		if (taf) {
+			st->rx_state = CN_MUTING;
+			reduce_xmaxc_sid(st);
+		}
+		gsmfr_preproc_gen_cn(st, frame);
+		return;
+	case CN_MUTING:
+		if (reduce_xmaxc_sid(st)) {
+			st->rx_state = NO_DATA;
+			memcpy(frame, &gsmfr_preproc_silence_frame,
+				GSMFR_RTP_FRAME_LEN);
+		} else
+			gsmfr_preproc_gen_cn(st, frame);
+		return;
+	}
+}
+
+void gsmfr_preproc_invalid_sid(struct gsmfr_preproc_state *st, uint8_t *frame)
+{
+	int mute;
+
+	switch (st->rx_state) {
+	case NO_DATA:
+		memcpy(frame, &gsmfr_preproc_silence_frame,
+			GSMFR_RTP_FRAME_LEN);
+		return;
+	case SPEECH:
+		/*
+		 * Make CN out of the last good speech frame, following the
+		 * "NOTE" at the end of section 6.1.2 in TS 46.031.
+		 */
+		st->rx_state = COMFORT_NOISE;
+		memcpy(st->sid_prefix, &st->speech_frame, 5);
+		st->sid_xmaxc = gsmfr_preproc_xmaxc_mean(st->speech_frame);
+		gsmfr_preproc_gen_cn(st, frame);
+		return;
+	case SPEECH_MUTING:
+		/* ignore invalid SID in this state and act as if we got BFI */
+		mute = reduce_xmaxc(st->speech_frame);
+		memcpy(frame, &st->speech_frame, GSMFR_RTP_FRAME_LEN);
+		random_grid_pos(st, frame);
+		if (mute)
+			st->rx_state = NO_DATA;
+		return;
+	case COMFORT_NOISE:
+	case LOST_SID:
+		st->rx_state = COMFORT_NOISE;
+		gsmfr_preproc_gen_cn(st, frame);
+		return;
+	case CN_MUTING:
+		if (reduce_xmaxc_sid(st)) {
+			st->rx_state = NO_DATA;
+			memcpy(frame, &gsmfr_preproc_silence_frame,
+				GSMFR_RTP_FRAME_LEN);
+		} else
+			gsmfr_preproc_gen_cn(st, frame);
+		return;
+	}
+}