Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / plugins / codecs / amrnb / amrdecode.c
blob41f199848021f9b71d80255b53f94e1701366b97
1 /* amrdecode.c
2 * AMR codec
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
11 #include "config.h"
13 #include <wireshark.h>
15 #include "wsutil/codecs.h"
16 #include "ws_attributes.h"
18 #include <opencore-amrnb/interf_dec.h>
20 void codec_register_amr(void);
22 static void *
23 codec_amr_init(codec_context_t *ctx _U_)
25 void *state;
26 state = Decoder_Interface_init();
28 return state;
31 static void
32 codec_amr_release(codec_context_t *state)
34 Decoder_Interface_exit(state->priv);
37 static unsigned
38 codec_amr_get_channels(codec_context_t *ctx _U_)
40 return 1;
43 static unsigned
44 codec_amr_get_frequency(codec_context_t *ctx _U_)
46 return 8000;
49 /* RTP doesn't allow the other SID types */
50 static const uint8_t speech_bits[16] = {95,103,118,134,148,159,204,244,39, 0, 0, 0, 0, 0, 0, 0};
51 /* The number of speech bits rounded up to bytes */
52 static const uint8_t block_size[16] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0};
54 static const uint8_t bit_mask8[] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
56 /* Retrieve no_of_bits (<= 8) from in, starting at bit_offset.
57 * Does not do bounds checking.
59 static uint8_t
60 get_bits8(uint8_t *in, unsigned bit_offset, const unsigned no_of_bits)
62 uint8_t ret;
63 unsigned octet_offset = bit_offset >> 3;
64 unsigned bits_in_first_octet = 8 - (bit_offset % 8);
65 if (bits_in_first_octet >= no_of_bits) {
66 ret = in[octet_offset] >> (bits_in_first_octet - no_of_bits) & bit_mask8[no_of_bits];
67 } else {
68 unsigned left_shift = no_of_bits - bits_in_first_octet;
69 ret = (in[octet_offset] << left_shift) & bit_mask8[no_of_bits];
70 ret |= (in[octet_offset + 1] >> (8 - left_shift));
72 return ret;
75 static size_t
76 codec_amr_decode_one(void *state, const void *input, size_t inputSizeBytes,
77 void *output, size_t *outputSizeBytes)
79 uint8_t *in;
80 int mode;
81 unsigned packet_size;
82 packet_size = 2; /* CMR + TOC */
84 /* 160 samples per frame, two byte per frame, 20ms */
85 *outputSizeBytes = 160 * 2;
87 /* If no room for CMR + TOC, insert silence */
88 if (packet_size > inputSizeBytes) {
89 memset(output, 0, 160 * 2);
90 return *outputSizeBytes;
93 in = (uint8_t*)input + 1;
94 mode = (in[0] >> 3) & 0x0F;
95 packet_size += block_size[mode];
97 /* If the size is screwed up, insert silence */
98 if (packet_size > inputSizeBytes) {
99 memset(output, 0, 160 * 2);
100 return *outputSizeBytes;
103 /* XXX: The last parameter is the BFI - we could invert the
104 * Q-bit and pass it in, which might be better?
106 Decoder_Interface_Decode(state, in, (short *)output, 0);
107 return *outputSizeBytes;
110 static size_t
111 codec_amr_decode_many(void *state, const void *input, size_t inputSizeBytes,
112 void *output, size_t *outputSizeBytes, unsigned frames)
114 int mode;
115 unsigned packet_size = 1; /* CMR */
117 *outputSizeBytes = 160 * 2 * frames;
119 uint8_t *toc = (uint8_t *)input + 1;
120 uint8_t *speech = toc + frames;
121 uint8_t in[32];
123 for (unsigned i = 0; i < frames; i++) {
124 mode = (toc[i] >> 3) & 0x0F;
125 packet_size += block_size[mode] + 1; /* include the TOC */
127 /* If the size is screwed up, insert silence */
128 if (packet_size > inputSizeBytes) {
129 memset(output, 0, 160 * 2 * (frames - i));
130 return *outputSizeBytes;
133 /* OpenCORE-AMR ignores the F-bit (which is why we're doing
134 * this memcpy) but might as well clear it.
136 in[0] = toc[i] & 0x7F;
137 memcpy(&in[1], speech, block_size[mode]);
138 /* XXX: The last parameter is the BFI - we could invert the
139 * Q-bit and pass it in, which might be better?
141 Decoder_Interface_Decode(state, in, (short *)output, 0);
142 speech += block_size[mode];
143 output = (uint8_t *)output + 160 * 2;
146 return *outputSizeBytes;
149 static size_t
150 codec_amr_decode_oa(codec_context_t *ctx, const void *input,
151 size_t inputSizeBytes, void *output, size_t *outputSizeBytes)
153 bool f_bit;
154 unsigned frames = 0;
155 void *state = ctx->priv;
157 /* First byte is CMR, second is the Payload TOC */
158 if (inputSizeBytes < 2) {
159 frames = 1;
160 } else {
161 uint8_t *in = (uint8_t *)input;
162 do {
163 f_bit = (in[++frames] >> 7) & 0x01;
164 } while (f_bit && inputSizeBytes > frames + 1);
167 /* 160 samples per frame, two byte per frame, 20ms */
168 if (!output || !outputSizeBytes)
169 return 160 * 2 * frames;
171 if (frames == 1) {
172 return codec_amr_decode_one(state, input, inputSizeBytes, output, outputSizeBytes);
173 } else {
174 return codec_amr_decode_many(state, input, inputSizeBytes, output, outputSizeBytes, frames);
178 static size_t
179 codec_amr_decode(codec_context_t *ctx, const void *input,
180 size_t inputSizeBytes, void *output, size_t *outputSizeBytes)
182 bool f_bit;
183 unsigned frames = 0;
184 void *state = ctx->priv;
186 if (ctx->fmtp_map) {
187 const char* octet_align = (const char *)wmem_map_lookup(ctx->fmtp_map, "octet-align");
188 /* There's a few other lesser used options like "crc", "interleaving",
189 * and "robust-sorting" that can change how it should be decoded.
190 * (All of them imply octet-aligned.) Ideally we'd handle them too.
192 if (g_strcmp0(octet_align, "1") == 0) {
193 return codec_amr_decode_oa(ctx, input, inputSizeBytes, output, outputSizeBytes);
197 unsigned bit_offset = 4;
198 uint8_t *in = (uint8_t *)input;
199 /* Per RFC 4867, if the format parameters don't indicate octet-align,
200 * bandwidth-efficient mode is used. (For Decode As, we'll pass in
201 * the value of the dissector's prefs.)
202 * OpenCORE-AMR's interface only supports octet-aligned mode, so we
203 * have to align the data. (From the source, the decode also supports
204 * IF2, except that there's no way to access that from the interface.)
206 /* First byte is CMR, second is the Payload TOC */
207 if (inputSizeBytes < 2) {
208 frames = 1;
209 } else {
210 do {
211 f_bit = get_bits8(in, bit_offset, 1);
212 bit_offset += 6;
213 frames++;
214 } while (f_bit && inputSizeBytes > (bit_offset / 8));
217 /* 160 samples per frame, two byte per frame, 20ms */
218 if (!output || !outputSizeBytes)
219 return 160 * 2 * frames;
221 *outputSizeBytes = 160 * 2 * frames;
222 /* bit_offset is now where the speech bits begin */
223 unsigned toc_offset = 5; /* Mode start */
224 uint8_t aligned[32];
225 int mode;
226 for (unsigned i = 0; i < frames; ++i) {
227 mode = get_bits8(in, toc_offset, 4);
229 /* If the size is screwed up, insert silence */
230 if ((bit_offset + speech_bits[mode] + 7) / 8 > inputSizeBytes) {
231 memset(output, 0, 160 * 2 * (frames - i));
232 return *outputSizeBytes;
235 memset(aligned, 0, 32);
236 aligned[0] = mode << 3;
237 for (unsigned j = 0; j < speech_bits[mode] / 8U; ++j) {
238 aligned[1 + j] = get_bits8(in, bit_offset, 8);
239 bit_offset += 8;
241 if (speech_bits[mode] % 8) {
242 aligned[1 + block_size[mode]] = get_bits8(in, bit_offset, speech_bits[mode] % 8);
244 /* Padding might be different. */
246 /* XXX: The last parameter is the BFI - we could invert the
247 * Q-bit and pass it in, which might be better?
249 Decoder_Interface_Decode(state, aligned, (short *)output, 0);
250 output = (uint8_t *)output + 160 * 2;
253 return *outputSizeBytes;
256 void
257 codec_register_amr(void)
259 register_codec("AMR", codec_amr_init, codec_amr_release,
260 codec_amr_get_channels, codec_amr_get_frequency, codec_amr_decode);
264 * Editor modelines - http://www.wireshark.org/tools/modelines.html
266 * Local variables:
267 * c-basic-offset: 4
268 * tab-width: 8
269 * indent-tabs-mode: nil
270 * End:
272 * vi: set shiftwidth=4 tabstop=8 expandtab:
273 * :indentSize=4:tabSize=8:noTabs=true: