aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/contrib/testconv/testconv_main.c
blob: 773be26a36d4d7c05c0fab469e5819c646c69337 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <err.h>

#include <osmocom/core/talloc.h>
#include <osmocom/core/application.h>

#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/mgcp.h>
#include <openbsc/mgcp_internal.h>

#include "bscconfig.h"
#ifndef BUILD_MGCP_TRANSCODING
#error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)"
#endif

#include "openbsc/mgcp_transcode.h"

static int audio_name_to_type(const char *name)
{
	if (!strcasecmp(name, "gsm"))
		return 3;
#ifdef HAVE_BCG729
	else if (!strcasecmp(name, "g729"))
		return 18;
#endif
	else if (!strcasecmp(name, "pcma"))
		return 8;
	else if (!strcasecmp(name, "l16"))
		return 11;
	return -1;
}

int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst);

int main(int argc, char **argv)
{
	char buf[4096] = {0x80, 0};
	int cc, rc;
	struct mgcp_rtp_end *dst_end;
	struct mgcp_rtp_end *src_end;
	struct mgcp_trunk_config tcfg = {{0}};
	struct mgcp_endpoint endp = {0};
	struct mgcp_process_rtp_state *state;
	int in_size;
	int in_samples = 160;
	int out_samples = 0;
	uint32_t ts = 0;
	uint16_t seq = 0;

	osmo_init_logging(&log_info);

	tcfg.endpoints = &endp;
	tcfg.number_endpoints = 1;
	endp.tcfg = &tcfg;
	mgcp_initialize_endp(&endp);

	dst_end = &endp.bts_end;
	src_end = &endp.net_end;

	if (argc <= 2)
		errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16} [SPP]");

	if ((src_end->payload_type = audio_name_to_type(argv[1])) == -1)
		errx(1, "invalid input format '%s'", argv[1]);
	if ((dst_end->payload_type = audio_name_to_type(argv[2])) == -1)
		errx(1, "invalid output format '%s'", argv[2]);
	if (argc > 3)
		out_samples = atoi(argv[3]);

	if (out_samples) {
		dst_end->frame_duration_den = dst_end->rate;
		dst_end->frame_duration_num = out_samples;
		dst_end->frames_per_packet = 1;
	}

	rc = mgcp_transcoding_setup(&endp, dst_end, src_end);
	if (rc < 0)
		errx(1, "setup failed: %s", strerror(-rc));

	state = dst_end->rtp_process_data;
	OSMO_ASSERT(state != NULL);

	in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0);
	OSMO_ASSERT(sizeof(buf) >= in_size + 12);

	buf[1] = src_end->payload_type;
	*(uint16_t*)(buf+2) = htons(1);
	*(uint32_t*)(buf+4) = htonl(0);
	*(uint32_t*)(buf+8) = htonl(0xaabbccdd);

	while ((cc = read(0, buf + 12, in_size))) {
		int cont;
		int len;

		if (cc != in_size)
			err(1, "read");

		*(uint16_t*)(buf+2) = htonl(seq);
		*(uint32_t*)(buf+4) = htonl(ts);

		seq += 1;
		ts += in_samples;

		cc += 12; /* include RTP header */

		len = cc;

		do {
			cont = mgcp_transcoding_process_rtp(&endp, dst_end,
							    buf, &len, sizeof(buf));
			if (cont == -EAGAIN) {
				fprintf(stderr, "Got EAGAIN\n");
				break;
			}

			if (cont < 0)
				errx(1, "processing failed: %s", strerror(-cont));

			len -= 12; /* ignore RTP header */

			if (write(1, buf + 12, len) != len)
				err(1, "write");

			len = cont;
		} while (len > 0);
	}
	return 0;
}