view libgsmfr2/pp_bad.c @ 301:019eed8b1948

doc/FR1-library-history: new article
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 15 Apr 2024 18:36:21 +0000
parents 573afa985df6
children 405a84110997
line wrap: on
line source

/*
 * 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_state.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;
	}
}