blob: cfefce148a0576f63948defd3b725b92c01a0f81 [file] [log] [blame]
Mychaela N. Falconia8fa13c62023-05-12 17:04:06 +00001/*
2 * (C) 2017 by sysmocom - s.f.m.c. GmbH
3 * (C) 2017 by Philipp Maier <pmaier@sysmocom.de>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 *
18 * This module implements legacy, deprecated osmo_ecu_fr_reset() and
19 * osmo_ecu_fr_conceal() functions only - see ecu_fr.c for the new
20 * GSM-FR ECU implementation.
21 */
22
23#include <stdbool.h>
24#include <string.h>
25#include <stdint.h>
26#include <errno.h>
27
28#include <osmocom/core/bitvec.h>
29
30#include <osmocom/codec/gsm610_bits.h>
31#include <osmocom/codec/codec.h>
32#include <osmocom/codec/ecu.h>
33
34/* See also GSM 06.11, chapter 6 Example solution */
35#define GSM610_XMAXC_REDUCE 4
36#define GSM610_XMAXC_LEN 6
37
38/**
39 * Reduce the XMAXC field. When the XMAXC field reaches
40 * zero the function will return true.
41 */
42static bool reduce_xmaxcr(struct bitvec *frame_bitvec,
43 const unsigned int index)
44{
45 unsigned int field_index;
46 uint64_t field;
47
48 field_index = index;
49 field = bitvec_read_field(frame_bitvec, &field_index, GSM610_XMAXC_LEN);
50 if (field > GSM610_XMAXC_REDUCE)
51 field -= GSM610_XMAXC_REDUCE;
52 else
53 field = 0;
54
55 field_index = index;
56 bitvec_write_field(frame_bitvec, &field_index, field, GSM610_XMAXC_LEN);
57
58 return field == 0;
59}
60
61/**
62 * Reduce all XMAXC fields in the frame. When all XMAXC fields
63 * reach zero, then the function will return true.
64 */
65static bool reduce_xmaxcr_all(struct bitvec *frame_bitvec)
66{
67 bool silent = true;
68
69 silent &= reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC00);
70 silent &= reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC10);
71 silent &= reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC20);
72 silent &= reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC30);
73
74 return silent;
75}
76
77/* Use certain modifications to conceal the errors in a full rate frame */
78static int conceal_frame(uint8_t *frame)
79{
80 struct bitvec *frame_bitvec;
81 unsigned int len;
82 bool silent;
83 int rc = 0;
84
85 /* In case we already deal with a silent frame,
86 * there is nothing to, we just abort immediately */
87 if (osmo_fr_check_sid(frame, GSM_FR_BYTES))
88 return 0;
89
90 /* Attempt to allocate memory for bitvec */
91 frame_bitvec = bitvec_alloc(GSM_FR_BYTES, NULL);
92 if (!frame_bitvec)
93 return -ENOMEM;
94
95 /* Convert a frame to bitvec */
96 len = bitvec_unpack(frame_bitvec, frame);
97 if (len != GSM_FR_BYTES) {
98 rc = -EIO;
99 goto leave;
100 }
101
102 /* Fudge frame parameters */
103 silent = reduce_xmaxcr_all(frame_bitvec);
104
105 /* If we reached silence level, mute the frame
106 * completely, this also means that we can
107 * save the bitvec_pack operation */
108 if (silent) {
109 memset(frame, 0x00, GSM_FR_BYTES);
110 frame[0] = 0xd0;
111 goto leave;
112 }
113
114 /* Convert back to packed byte form */
115 len = bitvec_pack(frame_bitvec, frame);
116 if (len != GSM_FR_BYTES) {
117 rc = -EIO;
118 goto leave;
119 }
120
121leave:
122 bitvec_free(frame_bitvec);
123 return rc;
124}
125
126/*!
127 * To be called when a good frame is received.
128 * This function will then create a backup of the frame
129 * and reset the internal state.
130 * \param[in] state The state object for the ECU
131 * \param[out] frame The valid frame (GSM_FR_BYTES bytes in RTP payload format)
132 */
133void osmo_ecu_fr_reset(struct osmo_ecu_fr_state *state, const uint8_t *frame)
134{
135 state->subsequent_lost_frame = false;
136 memcpy(state->frame_backup, frame, GSM_FR_BYTES);
137}
138
139/*!
140 * To be called when a bad frame is received.
141 * This function will then generate a replacement frame
142 * that can be used to conceal the dropout.
143 * \param[in] state The state object for the ECU
144 * \param[out] frame The buffer to fill with GSM_FR_BYTES of replacement frame
145 * \returns 0 if the frame was successfully filled
146 */
147int osmo_ecu_fr_conceal(struct osmo_ecu_fr_state *state, uint8_t *frame)
148{
149 int rc;
150
151 /* For subsequent frames we run the error concealment
152 * functions on the backed up frame before we restore
153 * the backup */
154 if (state->subsequent_lost_frame) {
155 rc = conceal_frame(state->frame_backup);
156 if (rc)
157 return rc;
158 }
159
160 /* Restore the backed up frame and set flag in case
161 * we receive even more bad frames */
162 memcpy(frame, state->frame_backup, GSM_FR_BYTES);
163 state->subsequent_lost_frame = true;
164
165 return 0;
166}