blob: c5c0a0bab0d62f479d691e76f32bed383d85e19e [file] [log] [blame]
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +02001#include <stdlib.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <string.h>
5#include <err.h>
Holger Hans Peter Freyther7ce72c12015-03-22 14:43:19 +01006#include <stdint.h>
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +02007
8#include <osmocom/core/talloc.h>
9#include <osmocom/core/application.h>
10
Holger Hans Peter Freyther7ce72c12015-03-22 14:43:19 +010011#include <osmocom/netif/rtp.h>
12
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +020013#include <openbsc/debug.h>
14#include <openbsc/gsm_data.h>
15#include <openbsc/mgcp.h>
16#include <openbsc/mgcp_internal.h>
17
18#include "bscconfig.h"
19#ifndef BUILD_MGCP_TRANSCODING
20#error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)"
21#endif
22
Jacob Erlbeck909fac62014-05-08 14:08:37 +020023#include "openbsc/mgcp_transcode.h"
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +020024
25uint8_t *audio_frame_l16[] = {
26};
27
28struct rtp_packets {
29 float t;
30 int len;
31 char *data;
32};
33
34struct rtp_packets audio_packets_l16[] = {
35 /* RTP: SeqNo=1, TS=160 */
36 {0.020000, 332,
37 "\x80\x0B\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
38 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
39 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
40 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
41 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
42 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
43 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
44 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
45 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
46 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
47 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
48 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
49 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
50 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
51 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
52 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
53 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
54 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
55 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
56 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
57 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
58 },
59};
60
61struct rtp_packets audio_packets_gsm[] = {
62 /* RTP: SeqNo=1, TS=160 */
63 {0.020000, 45,
64 "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
65 "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B"
66 "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A"
67 "\xDE"
68 },
69};
70
71struct rtp_packets audio_packets_gsm_invalid_size[] = {
72 /* RTP: SeqNo=1, TS=160 */
73 {0.020000, 41,
74 "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
75 "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B"
76 "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A"
77 "\xDE"
78 },
79};
80
81struct rtp_packets audio_packets_gsm_invalid_data[] = {
82 /* RTP: SeqNo=1, TS=160 */
83 {0.020000, 45,
84 "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
85 "\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE"
86 "\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE"
87 "\xEE"
88 },
89};
90
91struct rtp_packets audio_packets_gsm_invalid_ptype[] = {
92 /* RTP: SeqNo=1, TS=160 */
93 {0.020000, 45,
94 "\x80\x08\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
95 "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B"
96 "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A"
97 "\xDE"
98 },
99};
100
101struct rtp_packets audio_packets_g729[] = {
102 /* RTP: SeqNo=1, TS=160 */
103 {0.020000, 32,
104 "\x80\x12\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
105 "\xAF\xC2\x81\x40\x00\xFA\xCE\xA4\x21\x7C\xC5\xC3\x4F\xA5\x98\xF5"
106 "\xB2\x95\xC4\xAD"
107 },
108};
109
110struct rtp_packets audio_packets_pcma[] = {
111 /* RTP: SeqNo=1, TS=160 */
112 {0.020000, 172,
113 "\x80\x08\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
114 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
115 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
116 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
117 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
118 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
119 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
120 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
121 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
122 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
123 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
124 },
Holger Hans Peter Freytherc8b29082014-07-02 22:02:15 +0200125 /* RTP: SeqNo=26527, TS=232640 */
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200126 {0.020000, 92,
Holger Hans Peter Freytherc8b29082014-07-02 22:02:15 +0200127 "\x80\x08\x67\x9f\x00\x03\x8c\xc0\x04\xaa\x67\x9f\xd5\xd5\xd5\xd5"
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200128 "\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5"
129 "\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5"
130 "\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5"
131 "\xd5\xd5\xd5\xd5\xd5\xd5\x55\x55\xd5\xd5\x55\x55\xd5\xd5\x55\x55"
132 "\xd5\xd5\xd5\x55\x55\xd5\xd5\xd5\x55\x55\xd5\xd5"
133 },
Holger Hans Peter Freytherc8b29082014-07-02 22:02:15 +0200134 /* RTP: SeqNo=26528, TS=232720 */
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200135 {0.020000, 92,
Holger Hans Peter Freytherc8b29082014-07-02 22:02:15 +0200136 "\x80\x08\x67\xa0\x00\x03\x8d\x10\x04\xaa\x67\x9f\x55\xd5\xd5\x55"
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200137 "\xd5\x55\xd5\xd5\xd5\x55\xd5\x55\xd5\xd5\x55\xd5\x55\xd5\x55\xd5"
138 "\x55\x55\xd5\x55\xd5\xd5\x55\x55\x55\x55\x55\xd5\xd5\x55\xd5\xd5"
139 "\xd5\x55\xd5\xd5\xd5\x55\x54\x55\xd5\xd5\x55\xd5\xd5\xd5\xd5\x55"
140 "\x54\x55\xd5\x55\xd5\x55\x55\x55\x55\x55\xd5\xd5\xd5\xd5\xd5\xd4"
141 "\xd5\x54\x55\xd5\xd4\xd5\x54\xd5\x55\xd5\xd5\xd5"
142 },
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200143};
144
145
146
147static int audio_name_to_type(const char *name)
148{
149 if (!strcasecmp(name, "gsm"))
150 return 3;
151#ifdef HAVE_BCG729
152 else if (!strcasecmp(name, "g729"))
153 return 18;
154#endif
155 else if (!strcasecmp(name, "pcma"))
156 return 8;
157 else if (!strcasecmp(name, "l16"))
158 return 11;
159 return -1;
160}
161
162int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst);
163
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200164static int given_configured_endpoint(int in_samples, int out_samples,
165 const char *srcfmt, const char *dstfmt,
166 void **out_ctx, struct mgcp_endpoint **out_endp)
167{
168 int rc;
169 struct mgcp_rtp_end *dst_end;
170 struct mgcp_rtp_end *src_end;
171 struct mgcp_config *cfg;
172 struct mgcp_trunk_config *tcfg;
173 struct mgcp_endpoint *endp;
174
175 cfg = mgcp_config_alloc();
176 tcfg = talloc_zero(cfg, struct mgcp_trunk_config);
177 endp = talloc_zero(tcfg, struct mgcp_endpoint);
178
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200179 cfg->setup_rtp_processing_cb = mgcp_transcoding_setup;
180 cfg->rtp_processing_cb = mgcp_transcoding_process_rtp;
181 cfg->get_net_downlink_format_cb = mgcp_transcoding_net_downlink_format;
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200182
183 tcfg->endpoints = endp;
184 tcfg->number_endpoints = 1;
185 tcfg->cfg = cfg;
186 endp->tcfg = tcfg;
187 endp->cfg = cfg;
Holger Hans Peter Freythercb6ad702014-07-22 15:00:52 +0200188 mgcp_initialize_endp(endp);
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200189
190 dst_end = &endp->bts_end;
Holger Hans Peter Freythercac24382014-09-01 10:35:55 +0200191 dst_end->codec.payload_type = audio_name_to_type(dstfmt);
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200192
193 src_end = &endp->net_end;
Holger Hans Peter Freythercac24382014-09-01 10:35:55 +0200194 src_end->codec.payload_type = audio_name_to_type(srcfmt);
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200195
196 if (out_samples) {
Holger Hans Peter Freythercac24382014-09-01 10:35:55 +0200197 dst_end->codec.frame_duration_den = dst_end->codec.rate;
198 dst_end->codec.frame_duration_num = out_samples;
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200199 dst_end->frames_per_packet = 1;
200 dst_end->force_output_ptime = 1;
201 }
202
203 rc = mgcp_transcoding_setup(endp, dst_end, src_end);
Holger Hans Peter Freyther6041c8d2014-06-28 13:24:36 +0200204 if (rc < 0) {
205 printf("setup failed: %s", strerror(-rc));
206 abort();
207 }
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200208
209 *out_ctx = cfg;
210 *out_endp = endp;
211 return 0;
212}
213
214
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200215static int transcode_test(const char *srcfmt, const char *dstfmt,
216 uint8_t *src_pkts, size_t src_pkt_size)
217{
218 char buf[4096] = {0x80, 0};
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200219 void *ctx;
220
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200221 struct mgcp_rtp_end *dst_end;
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200222 struct mgcp_process_rtp_state *state;
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200223 struct mgcp_endpoint *endp;
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200224 int in_size;
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200225 const int in_samples = 160;
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200226 int len, cont;
227
228 printf("== Transcoding test ==\n");
229 printf("converting %s -> %s\n", srcfmt, dstfmt);
230
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200231 given_configured_endpoint(in_samples, 0, srcfmt, dstfmt, &ctx, &endp);
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200232
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200233 dst_end = &endp->bts_end;
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200234 state = dst_end->rtp_process_data;
235 OSMO_ASSERT(state != NULL);
236
237 in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0);
238 OSMO_ASSERT(sizeof(buf) >= in_size + 12);
239
240 memcpy(buf, src_pkts, src_pkt_size);
241
242 len = src_pkt_size;
243
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200244 cont = mgcp_transcoding_process_rtp(endp, dst_end,
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200245 buf, &len, sizeof(buf));
Holger Hans Peter Freyther6041c8d2014-06-28 13:24:36 +0200246 if (cont < 0) {
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200247 printf("Nothing encoded due: %s\n", strerror(-cont));
248 talloc_free(ctx);
249 return -1;
Holger Hans Peter Freyther6041c8d2014-06-28 13:24:36 +0200250 }
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200251
252 if (len < 24) {
253 printf("encoded: %s\n", osmo_hexdump((unsigned char *)buf, len));
254 } else {
255 const char *str = osmo_hexdump((unsigned char *)buf, len);
256 int i = 0;
257 const int prefix = 4;
258 const int cutlen = 48;
259 int nchars = 0;
260
261 printf("encoded:\n");
262 do {
263 nchars = printf("%*s%-.*s", prefix, "", cutlen, str + i);
264 i += nchars - prefix;
265 printf("\n");
266 } while (nchars - prefix >= cutlen);
267 }
Holger Hans Peter Freyther4fb7e642014-06-28 00:10:10 +0200268 printf("counted: %d\n", cont);
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200269 talloc_free(ctx);
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200270 return 0;
271}
272
Holger Hans Peter Freyther91eeeae2014-07-04 20:55:20 +0200273static void test_rtp_seq_state(void)
274{
275 char buf[4096];
276 int len;
277 int cont;
278 void *ctx;
279 struct mgcp_endpoint *endp;
280 struct mgcp_process_rtp_state *state;
281 struct rtp_hdr *hdr;
282 uint32_t ts_no;
283 uint16_t seq_no;
284
285 given_configured_endpoint(160, 0, "pcma", "l16", &ctx, &endp);
286 state = endp->bts_end.rtp_process_data;
287 OSMO_ASSERT(!state->is_running);
288 OSMO_ASSERT(state->next_seq == 0);
289 OSMO_ASSERT(state->next_time == 0);
290
291 /* initialize packet */
292 len = audio_packets_pcma[0].len;
293 memcpy(buf, audio_packets_pcma[0].data, len);
294 cont = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, len);
295 OSMO_ASSERT(cont >= 0);
296 OSMO_ASSERT(state->is_running);
297 OSMO_ASSERT(state->next_seq == 2);
Jacob Erlbeckddc0e052015-04-27 09:13:48 +0200298 OSMO_ASSERT(state->next_time == 240);
Holger Hans Peter Freyther91eeeae2014-07-04 20:55:20 +0200299
300 /* verify that the right timestamp was written */
301 OSMO_ASSERT(len == audio_packets_pcma[0].len);
302 hdr = (struct rtp_hdr *) &buf[0];
303
304 memcpy(&ts_no, &hdr->timestamp, sizeof(ts_no));
305 OSMO_ASSERT(htonl(ts_no) == 160);
306 memcpy(&seq_no, &hdr->sequence, sizeof(seq_no));
307 OSMO_ASSERT(htons(seq_no) == 1);
308 /* Check the right sequence number is written */
309 state->next_seq = 1234;
310 len = audio_packets_pcma[0].len;
311 memcpy(buf, audio_packets_pcma[0].data, len);
312 cont = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, len);
313 OSMO_ASSERT(cont >= 0);
314 OSMO_ASSERT(len == audio_packets_pcma[0].len);
315 hdr = (struct rtp_hdr *) &buf[0];
316
317 memcpy(&seq_no, &hdr->sequence, sizeof(seq_no));
318 OSMO_ASSERT(htons(seq_no) == 1234);
319
320 talloc_free(ctx);
321}
322
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200323static void test_transcode_result(void)
324{
325 char buf[4096];
326 int len, res;
327 void *ctx;
328 struct mgcp_endpoint *endp;
329 struct mgcp_process_rtp_state *state;
330
331 {
332 /* from GSM to PCMA and same ptime */
333 given_configured_endpoint(160, 0, "gsm", "pcma", &ctx, &endp);
334 state = endp->bts_end.rtp_process_data;
335
336 /* result */
337 len = audio_packets_gsm[0].len;
338 memcpy(buf, audio_packets_gsm[0].data, len);
339 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
340 OSMO_ASSERT(res == sizeof(struct rtp_hdr));
341 OSMO_ASSERT(state->sample_cnt == 0);
342
343 len = res;
344 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
345 OSMO_ASSERT(res == -ENOMSG);
346
347 talloc_free(ctx);
348 }
349
350 {
Holger Hans Peter Freyther4c18d792014-07-04 08:13:53 +0200351 /* from GSM to PCMA and same ptime */
352 given_configured_endpoint(160, 160, "gsm", "pcma", &ctx, &endp);
353 state = endp->bts_end.rtp_process_data;
354
355 /* result */
356 len = audio_packets_gsm[0].len;
357 memcpy(buf, audio_packets_gsm[0].data, len);
358 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
359 OSMO_ASSERT(res == sizeof(struct rtp_hdr));
360 OSMO_ASSERT(state->sample_cnt == 0);
361
362 len = res;
363 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
364 OSMO_ASSERT(res == -EAGAIN);
365
366 talloc_free(ctx);
367 }
368
369 {
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200370 /* from PCMA to GSM and wrong different ptime */
371 given_configured_endpoint(80, 160, "pcma", "gsm", &ctx, &endp);
372 state = endp->bts_end.rtp_process_data;
373
374 /* Add the first sample */
375 len = audio_packets_pcma[1].len;
376 memcpy(buf, audio_packets_pcma[1].data, len);
377 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
378 OSMO_ASSERT(state->sample_cnt == 80);
Holger Hans Peter Freytherc8b29082014-07-02 22:02:15 +0200379 OSMO_ASSERT(state->next_time == 232640);
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200380 OSMO_ASSERT(res < 0);
381
382 /* Add the second sample and it should be consumable */
383 len = audio_packets_pcma[2].len;
384 memcpy(buf, audio_packets_pcma[2].data, len);
385 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
386 OSMO_ASSERT(state->sample_cnt == 0);
Holger Hans Peter Freytherc8b29082014-07-02 22:02:15 +0200387 OSMO_ASSERT(state->next_time == 232640 + 80 + 160);
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200388 OSMO_ASSERT(res == sizeof(struct rtp_hdr));
389
390 talloc_free(ctx);
391 }
Holger Hans Peter Freytherb9362782014-07-04 20:55:20 +0200392
393 {
394 /* from PCMA to GSM with a big time jump */
395 struct rtp_hdr *hdr;
396 uint32_t ts;
397
398 given_configured_endpoint(80, 160, "pcma", "gsm", &ctx, &endp);
399 state = endp->bts_end.rtp_process_data;
400
401 /* Add the first sample */
402 len = audio_packets_pcma[1].len;
403 memcpy(buf, audio_packets_pcma[1].data, len);
404 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
405 OSMO_ASSERT(state->sample_cnt == 80);
406 OSMO_ASSERT(state->next_time == 232640);
407 OSMO_ASSERT(state->next_seq == 26527);
408 OSMO_ASSERT(res < 0);
409
410 /* Add a skip to the packet to force a 'resync' */
411 len = audio_packets_pcma[2].len;
412 memcpy(buf, audio_packets_pcma[2].data, len);
413 hdr = (struct rtp_hdr *) &buf[0];
414 /* jump the time and add alignment error */
415 ts = ntohl(hdr->timestamp) + 123 * 80 + 2;
416 hdr->timestamp = htonl(ts);
417 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
418 OSMO_ASSERT(res < 0);
419 OSMO_ASSERT(state->sample_cnt == 80);
420 OSMO_ASSERT(state->next_time == ts);
421 OSMO_ASSERT(state->next_seq == 26527);
422 /* TODO: this can create alignment errors */
423
424
425 /* Now attempt to consume 160 samples */
426 len = audio_packets_pcma[2].len;
427 memcpy(buf, audio_packets_pcma[2].data, len);
428 hdr = (struct rtp_hdr *) &buf[0];
429 ts += 80;
430 hdr->timestamp = htonl(ts);
431 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
432 OSMO_ASSERT(res == 12);
433 OSMO_ASSERT(state->sample_cnt == 0);
434 OSMO_ASSERT(state->next_time == ts + 160);
435 OSMO_ASSERT(state->next_seq == 26528);
436
437 talloc_free(ctx);
438 }
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200439}
440
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200441static void test_transcode_change(void)
442{
443 char buf[4096] = {0x80, 0};
444 void *ctx;
445
446 struct mgcp_endpoint *endp;
447 struct mgcp_process_rtp_state *state;
448 struct rtp_hdr *hdr;
449
450 int len, res;
451
452 {
453 /* from GSM to PCMA and same ptime */
Holger Hans Peter Freyther0454e322014-09-02 12:15:37 +0200454 printf("Testing Initial L16->GSM, PCMA->GSM\n");
455 given_configured_endpoint(160, 0, "l16", "gsm", &ctx, &endp);
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200456 endp->net_end.alt_codec = endp->net_end.codec;
457 endp->net_end.alt_codec.payload_type = audio_name_to_type("pcma");
458 state = endp->bts_end.rtp_process_data;
459
460 /* initial transcoding work */
Holger Hans Peter Freyther0454e322014-09-02 12:15:37 +0200461 OSMO_ASSERT(state->src_fmt == AF_L16);
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200462 OSMO_ASSERT(state->dst_fmt == AF_GSM);
463 OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 8);
Holger Hans Peter Freyther0454e322014-09-02 12:15:37 +0200464 OSMO_ASSERT(endp->net_end.codec.payload_type == 11);
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200465
466 /* result */
467 len = audio_packets_pcma[0].len;
468 memcpy(buf, audio_packets_pcma[0].data, len);
469 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
Holger Hans Peter Freyther01699712014-09-05 12:23:36 +0200470 state = endp->bts_end.rtp_process_data;
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200471 OSMO_ASSERT(res == sizeof(struct rtp_hdr));
472 OSMO_ASSERT(state->sample_cnt == 0);
473 OSMO_ASSERT(state->src_fmt == AF_PCMA);
474 OSMO_ASSERT(state->dst_fmt == AF_GSM);
Holger Hans Peter Freyther0454e322014-09-02 12:15:37 +0200475 OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 11);
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200476 OSMO_ASSERT(endp->net_end.codec.payload_type == 8);
477
478 len = res;
479 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
480 OSMO_ASSERT(res == -ENOMSG);
Holger Hans Peter Freyther01699712014-09-05 12:23:36 +0200481 OSMO_ASSERT(state == endp->bts_end.rtp_process_data);
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200482
483
484 /* now check that comfort noise doesn't change anything */
485 len = audio_packets_pcma[1].len;
486 memcpy(buf, audio_packets_pcma[1].data, len);
487 hdr = (struct rtp_hdr *) buf;
Holger Hans Peter Freyther0454e322014-09-02 12:15:37 +0200488 hdr->payload_type = 12;
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200489 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
Holger Hans Peter Freyther01699712014-09-05 12:23:36 +0200490 OSMO_ASSERT(state == endp->bts_end.rtp_process_data);
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200491 OSMO_ASSERT(state->sample_cnt == 80);
492 OSMO_ASSERT(state->src_fmt == AF_PCMA);
493 OSMO_ASSERT(state->dst_fmt == AF_GSM);
Holger Hans Peter Freyther0454e322014-09-02 12:15:37 +0200494 OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 11);
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200495 OSMO_ASSERT(endp->net_end.codec.payload_type == 8);
496
497 talloc_free(ctx);
498 }
499}
500
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200501static int test_repacking(int in_samples, int out_samples, int no_transcode)
502{
503 char buf[4096] = {0x80, 0};
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200504 int cc;
505 struct mgcp_endpoint *endp;
506 void *ctx;
507
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200508 struct mgcp_process_rtp_state *state;
509 int in_cnt;
510 int out_size;
511 int in_size;
512 uint32_t ts = 0;
513 uint16_t seq = 0;
514 const char *srcfmt = "pcma";
515 const char *dstfmt = no_transcode ? "pcma" : "l16";
516
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200517 printf("== Transcoding test ==\n");
518 printf("converting %s -> %s\n", srcfmt, dstfmt);
519
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200520 given_configured_endpoint(in_samples, out_samples, srcfmt, dstfmt, &ctx, &endp);
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200521
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200522 state = endp->bts_end.rtp_process_data;
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200523 OSMO_ASSERT(state != NULL);
524
525 in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0);
526 OSMO_ASSERT(sizeof(buf) >= in_size + 12);
527
528 out_size = mgcp_transcoding_get_frame_size(state, -1, 1);
529 OSMO_ASSERT(sizeof(buf) >= out_size + 12);
530
Holger Hans Peter Freythercac24382014-09-01 10:35:55 +0200531 buf[1] = endp->net_end.codec.payload_type;
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200532 *(uint16_t*)(buf+2) = htons(1);
533 *(uint32_t*)(buf+4) = htonl(0);
534 *(uint32_t*)(buf+8) = htonl(0xaabbccdd);
535
536 for (in_cnt = 0; in_cnt < 16; in_cnt++) {
537 int cont;
538 int len;
539
540 /* fake PCMA data */
541 printf("generating %d %s input samples\n", in_samples, srcfmt);
542 for (cc = 0; cc < in_samples; cc++)
543 buf[12+cc] = cc;
544
545 *(uint16_t*)(buf+2) = htonl(seq);
546 *(uint32_t*)(buf+4) = htonl(ts);
547
548 seq += 1;
549 ts += in_samples;
550
551 cc += 12; /* include RTP header */
552
553 len = cc;
554
555 do {
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200556 cont = mgcp_transcoding_process_rtp(endp, &endp->bts_end,
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200557 buf, &len, sizeof(buf));
558 if (cont == -EAGAIN) {
559 fprintf(stderr, "Got EAGAIN\n");
560 break;
561 }
562
Holger Hans Peter Freyther6041c8d2014-06-28 13:24:36 +0200563 if (cont < 0) {
564 printf("processing failed: %s", strerror(-cont));
565 abort();
566 }
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200567
568 len -= 12; /* ignore RTP header */
569
Holger Hans Peter Freyther4fb7e642014-06-28 00:10:10 +0200570 printf("got %d %s output frames (%d octets) count=%d\n",
571 len / out_size, dstfmt, len, cont);
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200572
573 len = cont;
574 } while (len > 0);
575 }
Holger Hans Peter Freyther83cbac22014-06-22 21:55:50 +0200576
577 talloc_free(ctx);
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200578 return 0;
579}
580
581int main(int argc, char **argv)
582{
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200583 int rc;
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200584 osmo_init_logging(&log_info);
585
586 printf("=== Transcoding Good Cases ===\n");
587
588 transcode_test("l16", "l16",
589 (uint8_t *)audio_packets_l16[0].data,
590 audio_packets_l16[0].len);
591 transcode_test("l16", "gsm",
592 (uint8_t *)audio_packets_l16[0].data,
593 audio_packets_l16[0].len);
594 transcode_test("l16", "pcma",
595 (uint8_t *)audio_packets_l16[0].data,
596 audio_packets_l16[0].len);
597 transcode_test("gsm", "l16",
598 (uint8_t *)audio_packets_gsm[0].data,
599 audio_packets_gsm[0].len);
600 transcode_test("gsm", "gsm",
601 (uint8_t *)audio_packets_gsm[0].data,
602 audio_packets_gsm[0].len);
603 transcode_test("gsm", "pcma",
604 (uint8_t *)audio_packets_gsm[0].data,
605 audio_packets_gsm[0].len);
606 transcode_test("pcma", "l16",
607 (uint8_t *)audio_packets_pcma[0].data,
608 audio_packets_pcma[0].len);
609 transcode_test("pcma", "gsm",
610 (uint8_t *)audio_packets_pcma[0].data,
611 audio_packets_pcma[0].len);
612 transcode_test("pcma", "pcma",
613 (uint8_t *)audio_packets_pcma[0].data,
614 audio_packets_pcma[0].len);
615
616 printf("=== Transcoding Bad Cases ===\n");
617
618 printf("Invalid size:\n");
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200619 rc = transcode_test("gsm", "pcma",
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200620 (uint8_t *)audio_packets_gsm_invalid_size[0].data,
621 audio_packets_gsm_invalid_size[0].len);
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200622 OSMO_ASSERT(rc < 0);
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200623
624 printf("Invalid data:\n");
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200625 rc = transcode_test("gsm", "pcma",
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200626 (uint8_t *)audio_packets_gsm_invalid_data[0].data,
627 audio_packets_gsm_invalid_data[0].len);
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200628 OSMO_ASSERT(rc < 0);
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200629
630 printf("Invalid payload type:\n");
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200631 rc = transcode_test("gsm", "pcma",
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200632 (uint8_t *)audio_packets_gsm_invalid_ptype[0].data,
633 audio_packets_gsm_invalid_ptype[0].len);
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200634 OSMO_ASSERT(rc == 0);
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200635
636 printf("=== Repacking ===\n");
637
638 test_repacking(160, 160, 0);
639 test_repacking(160, 160, 1);
640 test_repacking(160, 80, 0);
641 test_repacking(160, 80, 1);
642 test_repacking(160, 320, 0);
643 test_repacking(160, 320, 1);
644 test_repacking(160, 240, 0);
645 test_repacking(160, 240, 1);
646 test_repacking(160, 100, 0);
647 test_repacking(160, 100, 1);
Holger Hans Peter Freyther91eeeae2014-07-04 20:55:20 +0200648 test_rtp_seq_state();
Holger Hans Peter Freytherbd4109b2014-06-27 19:27:38 +0200649 test_transcode_result();
Holger Hans Peter Freyther46801212014-09-01 22:20:57 +0200650 test_transcode_change();
Jacob Erlbeck84a45cb2014-04-08 16:10:04 +0200651
652 return 0;
653}
654