blob: d4ea741b2584b53310ffaa85cdf0bad29222fbae [file] [log] [blame]
Philipp Maier40def492017-12-16 03:42:15 +07001/*
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 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
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 = false;
68
69 if (reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC00))
70 silent = true;
71 if (reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC10))
72 silent = true;
73 if (reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC20))
74 silent = true;
75 if (reduce_xmaxcr(frame_bitvec, GSM610_RTP_XMAXC30))
76 silent = true;
77
78 return silent;
79}
80
81/* Use certain modifications to conceal the errors in a full rate frame */
82static int conceal_frame(uint8_t *frame)
83{
84 struct bitvec *frame_bitvec;
85 unsigned int len;
86 bool silent;
87 int rc = 0;
88
89 /* In case we already deal with a silent frame,
90 * there is nothing to, we just abort immediately */
91 if (osmo_fr_check_sid(frame, GSM_FR_BYTES))
92 return 0;
93
94 /* Attempt to allocate memory for bitvec */
95 frame_bitvec = bitvec_alloc(GSM_FR_BYTES, NULL);
96 if (!frame_bitvec)
97 return -ENOMEM;
98
99 /* Convert a frame to bitvec */
100 len = bitvec_unpack(frame_bitvec, frame);
101 if (len != GSM_FR_BYTES) {
102 rc = -EIO;
103 goto leave;
104 }
105
106 /* Fudge frame parameters */
107 silent = reduce_xmaxcr_all(frame_bitvec);
108
109 /* If we reached silence level, mute the frame
110 * completely, this also means that we can
111 * save the bitvec_pack operation */
112 if (silent) {
113 memset(frame, 0x00, GSM_FR_BYTES);
114 frame[0] = 0xd0;
115 goto leave;
116 }
117
118 /* Convert back to packed byte form */
119 len = bitvec_pack(frame_bitvec, frame);
120 if (len != GSM_FR_BYTES) {
121 rc = -EIO;
122 goto leave;
123 }
124
125leave:
126 bitvec_free(frame_bitvec);
127 return rc;
128}
129
130/**
131 * To be called when a good frame is received.
132 * This function will then create a backup of the frame
133 * and reset the internal state.
134 */
135void osmo_ecu_fr_reset(struct osmo_ecu_fr_state *state, uint8_t *frame)
136{
137 state->subsequent_lost_frame = false;
138 memcpy(state->frame_backup, frame, GSM_FR_BYTES);
139}
140
141/**
142 * To be called when a bad frame is received.
143 * This function will then generate a replacement frame
144 * that can be used to conceal the dropout.
145 */
146int osmo_ecu_fr_conceal(struct osmo_ecu_fr_state *state, uint8_t *frame)
147{
148 int rc;
149
150 /* For subsequent frames we run the error concealment
151 * functions on the backed up frame before we restore
152 * the backup */
153 if (state->subsequent_lost_frame) {
154 rc = conceal_frame(state->frame_backup);
155 if (rc)
156 return rc;
157 }
158
159 /* Restore the backed up frame and set flag in case
160 * we receive even more bad frames */
161 memcpy(frame, state->frame_backup, GSM_FR_BYTES);
162 state->subsequent_lost_frame = true;
163
164 return 0;
165}