blob: 61de25f4fea841e37a333bdcd84ac79df685e25d [file] [log] [blame]
Neels Hofmeyre9920f22017-07-10 15:07:22 +02001#include <stdlib.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <string.h>
5#include <err.h>
6#include <stdint.h>
7#include <errno.h>
8
9#include <osmocom/core/talloc.h>
10#include <osmocom/core/application.h>
11
12#include <osmocom/netif/rtp.h>
13
14#include <osmocom/legacy_mgcp/mgcp.h>
15#include <osmocom/legacy_mgcp/mgcp_internal.h>
16
17#include "bscconfig.h"
18#ifndef BUILD_MGCP_TRANSCODING
19#error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)"
20#endif
21
22#include <osmocom/legacy_mgcp/mgcp_transcode.h>
23
24uint8_t *audio_frame_l16[] = {
25};
26
27struct rtp_packets {
28 float t;
29 int len;
30 char *data;
31};
32
33struct rtp_packets audio_packets_l16[] = {
34 /* RTP: SeqNo=1, TS=160 */
35 {0.020000, 332,
36 "\x80\x0B\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
37 "\x00\x00\x40\x13\x5A\x9E\x40\x13\x00\x00\xBF\xED\xA5\x62\xBF\xED"
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 },
58};
59
60struct rtp_packets audio_packets_gsm[] = {
61 /* RTP: SeqNo=1, TS=160 */
62 {0.020000, 45,
63 "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
64 "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B"
65 "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A"
66 "\xDE"
67 },
68};
69
70struct rtp_packets audio_packets_gsm_invalid_size[] = {
71 /* RTP: SeqNo=1, TS=160 */
72 {0.020000, 41,
73 "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
74 "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B"
75 "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A"
76 "\xDE"
77 },
78};
79
80struct rtp_packets audio_packets_gsm_invalid_data[] = {
81 /* RTP: SeqNo=1, TS=160 */
82 {0.020000, 45,
83 "\x80\x03\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
84 "\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE"
85 "\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE\xEE"
86 "\xEE"
87 },
88};
89
90struct rtp_packets audio_packets_gsm_invalid_ptype[] = {
91 /* RTP: SeqNo=1, TS=160 */
92 {0.020000, 45,
93 "\x80\x08\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
94 "\xD4\x7C\xE3\xE9\x62\x50\x39\xF0\xF8\xB4\x68\xEA\x6C\x0E\x81\x1B"
95 "\x56\x2A\xD5\xBC\x69\x9C\xD1\xF0\x66\x7A\xEC\x49\x7A\x33\x3D\x0A"
96 "\xDE"
97 },
98};
99
100struct rtp_packets audio_packets_g729[] = {
101 /* RTP: SeqNo=1, TS=160 */
102 {0.020000, 32,
103 "\x80\x12\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
104 "\xAF\xC2\x81\x40\x00\xFA\xCE\xA4\x21\x7C\xC5\xC3\x4F\xA5\x98\xF5"
105 "\xB2\x95\xC4\xAD"
106 },
107};
108
109struct rtp_packets audio_packets_pcma[] = {
110 /* RTP: SeqNo=1, TS=160 */
111 {0.020000, 172,
112 "\x80\x08\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
113 "\xD5\xA5\xA3\xA5\xD5\x25\x23\x25\xD5\xA5\xA3\xA5\xD5\x25\x23\x25"
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 },
124 /* RTP: SeqNo=26527, TS=232640 */
125 {0.020000, 92,
126 "\x80\x08\x67\x9f\x00\x03\x8c\xc0\x04\xaa\x67\x9f\xd5\xd5\xd5\xd5"
127 "\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5"
128 "\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\x55\x55\xd5\xd5\x55\x55\xd5\xd5\x55\x55"
131 "\xd5\xd5\xd5\x55\x55\xd5\xd5\xd5\x55\x55\xd5\xd5"
132 },
133 /* RTP: SeqNo=26528, TS=232720 */
134 {0.020000, 92,
135 "\x80\x08\x67\xa0\x00\x03\x8d\x10\x04\xaa\x67\x9f\x55\xd5\xd5\x55"
136 "\xd5\x55\xd5\xd5\xd5\x55\xd5\x55\xd5\xd5\x55\xd5\x55\xd5\x55\xd5"
137 "\x55\x55\xd5\x55\xd5\xd5\x55\x55\x55\x55\x55\xd5\xd5\x55\xd5\xd5"
138 "\xd5\x55\xd5\xd5\xd5\x55\x54\x55\xd5\xd5\x55\xd5\xd5\xd5\xd5\x55"
139 "\x54\x55\xd5\x55\xd5\x55\x55\x55\x55\x55\xd5\xd5\xd5\xd5\xd5\xd4"
140 "\xd5\x54\x55\xd5\xd4\xd5\x54\xd5\x55\xd5\xd5\xd5"
141 },
142};
143
144
145
146static int audio_name_to_type(const char *name)
147{
148 if (!strcasecmp(name, "gsm"))
149 return 3;
150#ifdef HAVE_BCG729
151 else if (!strcasecmp(name, "g729"))
152 return 18;
153#endif
154 else if (!strcasecmp(name, "pcma"))
155 return 8;
156 else if (!strcasecmp(name, "l16"))
157 return 11;
158 return -1;
159}
160
161int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst);
162
163static int given_configured_endpoint(int in_samples, int out_samples,
164 const char *srcfmt, const char *dstfmt,
165 void **out_ctx, struct mgcp_endpoint **out_endp)
166{
167 int rc;
168 struct mgcp_rtp_end *dst_end;
169 struct mgcp_rtp_end *src_end;
170 struct mgcp_config *cfg;
171 struct mgcp_trunk_config *tcfg;
172 struct mgcp_endpoint *endp;
173
174 cfg = mgcp_config_alloc();
175 tcfg = talloc_zero(cfg, struct mgcp_trunk_config);
176 endp = talloc_zero(tcfg, struct mgcp_endpoint);
177
178 cfg->setup_rtp_processing_cb = mgcp_transcoding_setup;
179 cfg->rtp_processing_cb = mgcp_transcoding_process_rtp;
180 cfg->get_net_downlink_format_cb = mgcp_transcoding_net_downlink_format;
181
182 tcfg->endpoints = endp;
183 tcfg->number_endpoints = 1;
184 tcfg->cfg = cfg;
185 endp->tcfg = tcfg;
186 endp->cfg = cfg;
187 mgcp_initialize_endp(endp);
188
189 dst_end = &endp->bts_end;
190 dst_end->codec.payload_type = audio_name_to_type(dstfmt);
191
192 src_end = &endp->net_end;
193 src_end->codec.payload_type = audio_name_to_type(srcfmt);
194
195 if (out_samples) {
196 dst_end->codec.frame_duration_den = dst_end->codec.rate;
197 dst_end->codec.frame_duration_num = out_samples;
198 dst_end->frames_per_packet = 1;
199 dst_end->force_output_ptime = 1;
200 }
201
202 rc = mgcp_transcoding_setup(endp, dst_end, src_end);
203 if (rc < 0) {
204 printf("setup failed: %s", strerror(-rc));
205 abort();
206 }
207
208 *out_ctx = cfg;
209 *out_endp = endp;
210 return 0;
211}
212
213
214static int transcode_test(const char *srcfmt, const char *dstfmt,
215 uint8_t *src_pkts, size_t src_pkt_size)
216{
217 char buf[4096] = {0x80, 0};
218 void *ctx;
219
220 struct mgcp_rtp_end *dst_end;
221 struct mgcp_process_rtp_state *state;
222 struct mgcp_endpoint *endp;
223 int in_size;
224 const int in_samples = 160;
225 int len, cont;
226
227 printf("== Transcoding test ==\n");
228 printf("converting %s -> %s\n", srcfmt, dstfmt);
229
230 given_configured_endpoint(in_samples, 0, srcfmt, dstfmt, &ctx, &endp);
231
232 dst_end = &endp->bts_end;
233 state = dst_end->rtp_process_data;
234 OSMO_ASSERT(state != NULL);
235
236 in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0);
237 OSMO_ASSERT(sizeof(buf) >= in_size + 12);
238
239 memcpy(buf, src_pkts, src_pkt_size);
240
241 len = src_pkt_size;
242
243 cont = mgcp_transcoding_process_rtp(endp, dst_end,
244 buf, &len, sizeof(buf));
245 if (cont < 0) {
246 printf("Nothing encoded due: %s\n", strerror(-cont));
247 talloc_free(ctx);
248 return -1;
249 }
250
251 if (len < 24) {
252 printf("encoded: %s\n", osmo_hexdump((unsigned char *)buf, len));
253 } else {
254 const char *str = osmo_hexdump((unsigned char *)buf, len);
255 int i = 0;
256 const int prefix = 4;
257 const int cutlen = 48;
258 int nchars = 0;
259
260 printf("encoded:\n");
261 do {
262 nchars = printf("%*s%-.*s", prefix, "", cutlen, str + i);
263 i += nchars - prefix;
264 printf("\n");
265 } while (nchars - prefix >= cutlen);
266 }
267 printf("counted: %d\n", cont);
268 talloc_free(ctx);
269 return 0;
270}
271
272static void test_rtp_seq_state(void)
273{
274 char buf[4096];
275 int len;
276 int cont;
277 void *ctx;
278 struct mgcp_endpoint *endp;
279 struct mgcp_process_rtp_state *state;
280 struct rtp_hdr *hdr;
281 uint32_t ts_no;
282 uint16_t seq_no;
283
284 given_configured_endpoint(160, 0, "pcma", "l16", &ctx, &endp);
285 state = endp->bts_end.rtp_process_data;
286 OSMO_ASSERT(!state->is_running);
287 OSMO_ASSERT(state->next_seq == 0);
288 OSMO_ASSERT(state->next_time == 0);
289
290 /* initialize packet */
291 len = audio_packets_pcma[0].len;
292 memcpy(buf, audio_packets_pcma[0].data, len);
293 cont = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, len);
294 OSMO_ASSERT(cont >= 0);
295 OSMO_ASSERT(state->is_running);
296 OSMO_ASSERT(state->next_seq == 2);
297 OSMO_ASSERT(state->next_time == 240);
298
299 /* verify that the right timestamp was written */
300 OSMO_ASSERT(len == audio_packets_pcma[0].len);
301 hdr = (struct rtp_hdr *) &buf[0];
302
303 memcpy(&ts_no, &hdr->timestamp, sizeof(ts_no));
304 OSMO_ASSERT(htonl(ts_no) == 160);
305 memcpy(&seq_no, &hdr->sequence, sizeof(seq_no));
306 OSMO_ASSERT(htons(seq_no) == 1);
307 /* Check the right sequence number is written */
308 state->next_seq = 1234;
309 len = audio_packets_pcma[0].len;
310 memcpy(buf, audio_packets_pcma[0].data, len);
311 cont = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, len);
312 OSMO_ASSERT(cont >= 0);
313 OSMO_ASSERT(len == audio_packets_pcma[0].len);
314 hdr = (struct rtp_hdr *) &buf[0];
315
316 memcpy(&seq_no, &hdr->sequence, sizeof(seq_no));
317 OSMO_ASSERT(htons(seq_no) == 1234);
318
319 talloc_free(ctx);
320}
321
322static void test_transcode_result(void)
323{
324 char buf[4096];
325 int len, res;
326 void *ctx;
327 struct mgcp_endpoint *endp;
328 struct mgcp_process_rtp_state *state;
329
330 {
331 /* from GSM to PCMA and same ptime */
332 given_configured_endpoint(160, 0, "gsm", "pcma", &ctx, &endp);
333 state = endp->bts_end.rtp_process_data;
334
335 /* result */
336 len = audio_packets_gsm[0].len;
337 memcpy(buf, audio_packets_gsm[0].data, len);
338 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
339 OSMO_ASSERT(res == sizeof(struct rtp_hdr));
340 OSMO_ASSERT(state->sample_cnt == 0);
341
342 len = res;
343 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
344 OSMO_ASSERT(res == -ENOMSG);
345
346 talloc_free(ctx);
347 }
348
349 {
350 /* from GSM to PCMA and same ptime */
351 given_configured_endpoint(160, 160, "gsm", "pcma", &ctx, &endp);
352 state = endp->bts_end.rtp_process_data;
353
354 /* result */
355 len = audio_packets_gsm[0].len;
356 memcpy(buf, audio_packets_gsm[0].data, len);
357 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
358 OSMO_ASSERT(res == sizeof(struct rtp_hdr));
359 OSMO_ASSERT(state->sample_cnt == 0);
360
361 len = res;
362 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
363 OSMO_ASSERT(res == -EAGAIN);
364
365 talloc_free(ctx);
366 }
367
368 {
369 /* from PCMA to GSM and wrong different ptime */
370 given_configured_endpoint(80, 160, "pcma", "gsm", &ctx, &endp);
371 state = endp->bts_end.rtp_process_data;
372
373 /* Add the first sample */
374 len = audio_packets_pcma[1].len;
375 memcpy(buf, audio_packets_pcma[1].data, len);
376 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
377 OSMO_ASSERT(state->sample_cnt == 80);
378 OSMO_ASSERT(state->next_time == 232640);
379 OSMO_ASSERT(res < 0);
380
381 /* Add the second sample and it should be consumable */
382 len = audio_packets_pcma[2].len;
383 memcpy(buf, audio_packets_pcma[2].data, len);
384 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
385 OSMO_ASSERT(state->sample_cnt == 0);
386 OSMO_ASSERT(state->next_time == 232640 + 80 + 160);
387 OSMO_ASSERT(res == sizeof(struct rtp_hdr));
388
389 talloc_free(ctx);
390 }
391
392 {
393 /* from PCMA to GSM with a big time jump */
394 struct rtp_hdr *hdr;
395 uint32_t ts;
396
397 given_configured_endpoint(80, 160, "pcma", "gsm", &ctx, &endp);
398 state = endp->bts_end.rtp_process_data;
399
400 /* Add the first sample */
401 len = audio_packets_pcma[1].len;
402 memcpy(buf, audio_packets_pcma[1].data, len);
403 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
404 OSMO_ASSERT(state->sample_cnt == 80);
405 OSMO_ASSERT(state->next_time == 232640);
406 OSMO_ASSERT(state->next_seq == 26527);
407 OSMO_ASSERT(res < 0);
408
409 /* Add a skip to the packet to force a 'resync' */
410 len = audio_packets_pcma[2].len;
411 memcpy(buf, audio_packets_pcma[2].data, len);
412 hdr = (struct rtp_hdr *) &buf[0];
413 /* jump the time and add alignment error */
414 ts = ntohl(hdr->timestamp) + 123 * 80 + 2;
415 hdr->timestamp = htonl(ts);
416 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
417 OSMO_ASSERT(res < 0);
418 OSMO_ASSERT(state->sample_cnt == 80);
419 OSMO_ASSERT(state->next_time == ts);
420 OSMO_ASSERT(state->next_seq == 26527);
421 /* TODO: this can create alignment errors */
422
423
424 /* Now attempt to consume 160 samples */
425 len = audio_packets_pcma[2].len;
426 memcpy(buf, audio_packets_pcma[2].data, len);
427 hdr = (struct rtp_hdr *) &buf[0];
428 ts += 80;
429 hdr->timestamp = htonl(ts);
430 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
431 OSMO_ASSERT(res == 12);
432 OSMO_ASSERT(state->sample_cnt == 0);
433 OSMO_ASSERT(state->next_time == ts + 160);
434 OSMO_ASSERT(state->next_seq == 26528);
435
436 talloc_free(ctx);
437 }
438}
439
440static void test_transcode_change(void)
441{
442 char buf[4096] = {0x80, 0};
443 void *ctx;
444
445 struct mgcp_endpoint *endp;
446 struct mgcp_process_rtp_state *state;
447 struct rtp_hdr *hdr;
448
449 int len, res;
450
451 {
452 /* from GSM to PCMA and same ptime */
453 printf("Testing Initial L16->GSM, PCMA->GSM\n");
454 given_configured_endpoint(160, 0, "l16", "gsm", &ctx, &endp);
455 endp->net_end.alt_codec = endp->net_end.codec;
456 endp->net_end.alt_codec.payload_type = audio_name_to_type("pcma");
457 state = endp->bts_end.rtp_process_data;
458
459 /* initial transcoding work */
460 OSMO_ASSERT(state->src_fmt == AF_L16);
461 OSMO_ASSERT(state->dst_fmt == AF_GSM);
462 OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 8);
463 OSMO_ASSERT(endp->net_end.codec.payload_type == 11);
464
465 /* result */
466 len = audio_packets_pcma[0].len;
467 memcpy(buf, audio_packets_pcma[0].data, len);
468 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
469 state = endp->bts_end.rtp_process_data;
470 OSMO_ASSERT(res == sizeof(struct rtp_hdr));
471 OSMO_ASSERT(state->sample_cnt == 0);
472 OSMO_ASSERT(state->src_fmt == AF_PCMA);
473 OSMO_ASSERT(state->dst_fmt == AF_GSM);
474 OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 11);
475 OSMO_ASSERT(endp->net_end.codec.payload_type == 8);
476
477 len = res;
478 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
479 OSMO_ASSERT(res == -ENOMSG);
480 OSMO_ASSERT(state == endp->bts_end.rtp_process_data);
481
482
483 /* now check that comfort noise doesn't change anything */
484 len = audio_packets_pcma[1].len;
485 memcpy(buf, audio_packets_pcma[1].data, len);
486 hdr = (struct rtp_hdr *) buf;
487 hdr->payload_type = 12;
488 res = mgcp_transcoding_process_rtp(endp, &endp->bts_end, buf, &len, ARRAY_SIZE(buf));
489 OSMO_ASSERT(state == endp->bts_end.rtp_process_data);
490 OSMO_ASSERT(state->sample_cnt == 80);
491 OSMO_ASSERT(state->src_fmt == AF_PCMA);
492 OSMO_ASSERT(state->dst_fmt == AF_GSM);
493 OSMO_ASSERT(endp->net_end.alt_codec.payload_type == 11);
494 OSMO_ASSERT(endp->net_end.codec.payload_type == 8);
495
496 talloc_free(ctx);
497 }
498}
499
500static int test_repacking(int in_samples, int out_samples, int no_transcode)
501{
502 char buf[4096] = {0x80, 0};
503 int cc;
504 struct mgcp_endpoint *endp;
505 void *ctx;
506
507 struct mgcp_process_rtp_state *state;
508 int in_cnt;
509 int out_size;
510 int in_size;
511 uint32_t ts = 0;
512 uint16_t seq = 0;
513 const char *srcfmt = "pcma";
514 const char *dstfmt = no_transcode ? "pcma" : "l16";
515
516 printf("== Transcoding test ==\n");
517 printf("converting %s -> %s\n", srcfmt, dstfmt);
518
519 given_configured_endpoint(in_samples, out_samples, srcfmt, dstfmt, &ctx, &endp);
520
521 state = endp->bts_end.rtp_process_data;
522 OSMO_ASSERT(state != NULL);
523
524 in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0);
525 OSMO_ASSERT(sizeof(buf) >= in_size + 12);
526
527 out_size = mgcp_transcoding_get_frame_size(state, -1, 1);
528 OSMO_ASSERT(sizeof(buf) >= out_size + 12);
529
530 buf[1] = endp->net_end.codec.payload_type;
531 *(uint16_t*)(buf+2) = htons(1);
532 *(uint32_t*)(buf+4) = htonl(0);
533 *(uint32_t*)(buf+8) = htonl(0xaabbccdd);
534
535 for (in_cnt = 0; in_cnt < 16; in_cnt++) {
536 int cont;
537 int len;
538
539 /* fake PCMA data */
540 printf("generating %d %s input samples\n", in_samples, srcfmt);
541 for (cc = 0; cc < in_samples; cc++)
542 buf[12+cc] = cc;
543
544 *(uint16_t*)(buf+2) = htonl(seq);
545 *(uint32_t*)(buf+4) = htonl(ts);
546
547 seq += 1;
548 ts += in_samples;
549
550 cc += 12; /* include RTP header */
551
552 len = cc;
553
554 do {
555 cont = mgcp_transcoding_process_rtp(endp, &endp->bts_end,
556 buf, &len, sizeof(buf));
557 if (cont == -EAGAIN) {
558 fprintf(stderr, "Got EAGAIN\n");
559 break;
560 }
561
562 if (cont < 0) {
563 printf("processing failed: %s", strerror(-cont));
564 abort();
565 }
566
567 len -= 12; /* ignore RTP header */
568
569 printf("got %d %s output frames (%d octets) count=%d\n",
570 len / out_size, dstfmt, len, cont);
571
572 len = cont;
573 } while (len > 0);
574 }
575
576 talloc_free(ctx);
577 return 0;
578}
579
580static const struct log_info_cat log_categories[] = {
581};
582
583const struct log_info log_info = {
584 .cat = log_categories,
585 .num_cat = ARRAY_SIZE(log_categories),
586};
587
588int main(int argc, char **argv)
589{
590 int rc;
591 osmo_init_logging(&log_info);
592
593 printf("=== Transcoding Good Cases ===\n");
594
595 transcode_test("l16", "l16",
596 (uint8_t *)audio_packets_l16[0].data,
597 audio_packets_l16[0].len);
598 transcode_test("l16", "gsm",
599 (uint8_t *)audio_packets_l16[0].data,
600 audio_packets_l16[0].len);
601 transcode_test("l16", "pcma",
602 (uint8_t *)audio_packets_l16[0].data,
603 audio_packets_l16[0].len);
604 transcode_test("gsm", "l16",
605 (uint8_t *)audio_packets_gsm[0].data,
606 audio_packets_gsm[0].len);
607 transcode_test("gsm", "gsm",
608 (uint8_t *)audio_packets_gsm[0].data,
609 audio_packets_gsm[0].len);
610 transcode_test("gsm", "pcma",
611 (uint8_t *)audio_packets_gsm[0].data,
612 audio_packets_gsm[0].len);
613 transcode_test("pcma", "l16",
614 (uint8_t *)audio_packets_pcma[0].data,
615 audio_packets_pcma[0].len);
616 transcode_test("pcma", "gsm",
617 (uint8_t *)audio_packets_pcma[0].data,
618 audio_packets_pcma[0].len);
619 transcode_test("pcma", "pcma",
620 (uint8_t *)audio_packets_pcma[0].data,
621 audio_packets_pcma[0].len);
622
623 printf("=== Transcoding Bad Cases ===\n");
624
625 printf("Invalid size:\n");
626 rc = transcode_test("gsm", "pcma",
627 (uint8_t *)audio_packets_gsm_invalid_size[0].data,
628 audio_packets_gsm_invalid_size[0].len);
629 OSMO_ASSERT(rc < 0);
630
631 printf("Invalid data:\n");
632 rc = transcode_test("gsm", "pcma",
633 (uint8_t *)audio_packets_gsm_invalid_data[0].data,
634 audio_packets_gsm_invalid_data[0].len);
635 OSMO_ASSERT(rc < 0);
636
637 printf("Invalid payload type:\n");
638 rc = transcode_test("gsm", "pcma",
639 (uint8_t *)audio_packets_gsm_invalid_ptype[0].data,
640 audio_packets_gsm_invalid_ptype[0].len);
641 OSMO_ASSERT(rc == 0);
642
643 printf("=== Repacking ===\n");
644
645 test_repacking(160, 160, 0);
646 test_repacking(160, 160, 1);
647 test_repacking(160, 80, 0);
648 test_repacking(160, 80, 1);
649 test_repacking(160, 320, 0);
650 test_repacking(160, 320, 1);
651 test_repacking(160, 240, 0);
652 test_repacking(160, 240, 1);
653 test_repacking(160, 100, 0);
654 test_repacking(160, 100, 1);
655 test_rtp_seq_state();
656 test_transcode_result();
657 test_transcode_change();
658
659 return 0;
660}
661