mirror of https://gerrit.osmocom.org/libosmocore
166 lines
4.2 KiB
C
166 lines
4.2 KiB
C
/*
|
|
* (C) 2017 by sysmocom - s.f.m.c. GmbH
|
|
* (C) 2017 by Philipp Maier <pmaier@sysmocom.de>
|
|
*
|
|
* All Rights Reserved
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <errno.h>
|
|
|
|
#include <osmocom/core/bitvec.h>
|
|
|
|
#include <osmocom/codec/gsm610_bits.h>
|
|
#include <osmocom/codec/codec.h>
|
|
#include <osmocom/codec/ecu.h>
|
|
|
|
/* See also GSM 06.11, chapter 6 Example solution */
|
|
#define GSM610_XMAXC_REDUCE 4
|
|
#define GSM610_XMAXC_LEN 6
|
|
|
|
/**
|
|
* Reduce the XMAXC field. When the XMAXC field reaches
|
|
* zero the function will return true.
|
|
*/
|
|
static bool reduce_xmaxcr(struct bitvec *frame_bitvec,
|
|
const unsigned int index)
|
|
{
|
|
unsigned int field_index;
|
|
uint64_t field;
|
|
|
|
field_index = index;
|
|
field = bitvec_read_field(frame_bitvec, &field_index, GSM610_XMAXC_LEN);
|
|
if (field > GSM610_XMAXC_REDUCE)
|
|
field -= GSM610_XMAXC_REDUCE;
|
|
else
|
|
field = 0;
|
|
|
|
field_index = index;
|
|
bitvec_write_field(frame_bitvec, &field_index, field, GSM610_XMAXC_LEN);
|
|
|
|
return field == 0;
|
|
}
|
|
|
|
/**
|
|
* Reduce all XMAXC fields in the frame. When all XMAXC fields
|
|
* reach zero, then the function will return true.
|
|
*/
|
|
static bool reduce_xmaxcr_all(struct bitvec *frame_bitvec)
|
|
{
|
|
bool silent = false;
|
|
|
|
if (reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC00))
|
|
silent = true;
|
|
if (reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC10))
|
|
silent = true;
|
|
if (reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC20))
|
|
silent = true;
|
|
if (reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC30))
|
|
silent = true;
|
|
|
|
return silent;
|
|
}
|
|
|
|
/* Use certain modifications to conceal the errors in a full rate frame */
|
|
static int conceal_frame(uint8_t *frame)
|
|
{
|
|
struct bitvec *frame_bitvec;
|
|
unsigned int len;
|
|
bool silent;
|
|
int rc = 0;
|
|
|
|
/* In case we already deal with a silent frame,
|
|
* there is nothing to, we just abort immediately */
|
|
if (osmo_fr_check_sid(frame, GSM_FR_BYTES))
|
|
return 0;
|
|
|
|
/* Attempt to allocate memory for bitvec */
|
|
frame_bitvec = bitvec_alloc(GSM_FR_BYTES, NULL);
|
|
if (!frame_bitvec)
|
|
return -ENOMEM;
|
|
|
|
/* Convert a frame to bitvec */
|
|
len = bitvec_unpack(frame_bitvec, frame);
|
|
if (len != GSM_FR_BYTES) {
|
|
rc = -EIO;
|
|
goto leave;
|
|
}
|
|
|
|
/* Fudge frame parameters */
|
|
silent = reduce_xmaxcr_all(frame_bitvec);
|
|
|
|
/* If we reached silence level, mute the frame
|
|
* completely, this also means that we can
|
|
* save the bitvec_pack operation */
|
|
if (silent) {
|
|
memset(frame, 0x00, GSM_FR_BYTES);
|
|
frame[0] = 0xd0;
|
|
goto leave;
|
|
}
|
|
|
|
/* Convert back to packed byte form */
|
|
len = bitvec_pack(frame_bitvec, frame);
|
|
if (len != GSM_FR_BYTES) {
|
|
rc = -EIO;
|
|
goto leave;
|
|
}
|
|
|
|
leave:
|
|
bitvec_free(frame_bitvec);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* To be called when a good frame is received.
|
|
* This function will then create a backup of the frame
|
|
* and reset the internal state.
|
|
*/
|
|
void osmo_ecu_fr_reset(struct osmo_ecu_fr_state *state, uint8_t *frame)
|
|
{
|
|
state->subsequent_lost_frame = false;
|
|
memcpy(state->frame_backup, frame, GSM_FR_BYTES);
|
|
}
|
|
|
|
/**
|
|
* To be called when a bad frame is received.
|
|
* This function will then generate a replacement frame
|
|
* that can be used to conceal the dropout.
|
|
*/
|
|
int osmo_ecu_fr_conceal(struct osmo_ecu_fr_state *state, uint8_t *frame)
|
|
{
|
|
int rc;
|
|
|
|
/* For subsequent frames we run the error concealment
|
|
* functions on the backed up frame before we restore
|
|
* the backup */
|
|
if (state->subsequent_lost_frame) {
|
|
rc = conceal_frame(state->frame_backup);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
|
|
/* Restore the backed up frame and set flag in case
|
|
* we receive even more bad frames */
|
|
memcpy(frame, state->frame_backup, GSM_FR_BYTES);
|
|
state->subsequent_lost_frame = true;
|
|
|
|
return 0;
|
|
}
|