File: rtplib.c

package info (click to toggle)
rtpengine 13.5.1.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,676 kB
  • sloc: ansic: 86,764; perl: 59,422; python: 3,193; sh: 1,030; makefile: 693; asm: 211
file content (214 lines) | stat: -rw-r--r-- 5,850 bytes parent folder | download
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include "rtplib.h"
#include <arpa/inet.h>
#include "str.h"
#include "log.h"
#include "codeclib.h"



struct rtp_extension {
	uint16_t undefined;
	uint16_t length;
} __attribute__ ((packed));




#define RFC_TYPE_FULL(type, name, c_rate, chans, pt)			\
	[type] = {							\
		.payload_type		= type,				\
		.encoding		= STR_CONST(#name),	\
		.encoding_with_params	= STR_CONST(#name "/" #c_rate),	\
		.clock_rate		= c_rate,			\
		.channels		= chans,			\
		.ptime			= pt,				\
	}
#define RFC_TYPE(type, name, c_rate) RFC_TYPE_FULL(type, name, c_rate, 1, 20)

const struct rtp_payload_type rfc_rtp_payload_types[] =
{
	RFC_TYPE(0, PCMU, 8000),
	RFC_TYPE(3, GSM, 8000),
	RFC_TYPE_FULL(4, G723, 8000, 1, 30),
	RFC_TYPE(5, DVI4, 8000),
	RFC_TYPE(6, DVI4, 16000),
	RFC_TYPE(7, LPC, 8000),
	RFC_TYPE(8, PCMA, 8000),
	RFC_TYPE(9, G722, 8000),
	RFC_TYPE(10, L16, 44100),
	RFC_TYPE_FULL(11, L16, 44100, 2, 20),
	RFC_TYPE(12, QCELP, 8000),
	RFC_TYPE(13, CN, 8000),
	RFC_TYPE(14, MPA, 90000),
	RFC_TYPE(15, G728, 8000),
	RFC_TYPE(16, DVI4, 11025),
	RFC_TYPE(17, DVI4, 22050),
	RFC_TYPE(18, G729, 8000),
	RFC_TYPE(25, CelB, 90000),
	RFC_TYPE(26, JPEG, 90000),
	RFC_TYPE(28, nv, 90000),
	RFC_TYPE(31, H261, 90000),
	RFC_TYPE(32, MPV, 90000),
	RFC_TYPE(33, MP2T, 90000),
	RFC_TYPE(34, H263, 90000),
};
const int num_rfc_rtp_payload_types = G_N_ELEMENTS(rfc_rtp_payload_types);






int rtp_payload(struct rtp_header **out, str *p, const str *s) {
	struct rtp_header *rtp;
	struct rtp_extension *ext;
	const char *err;

	err = "short packet (header)";
	if (s->len < sizeof(*rtp))
		goto error;

	rtp = (void *) s->s;
	err = "invalid header version";
	if ((rtp->v_p_x_cc & 0xc0) != 0x80) /* version 2 */
		goto error;

	if (!p)
		goto done;

	*p = *s;
	/* fixed header */
	str_shift(p, sizeof(*rtp));
	/* csrc list */
	err = "short packet (CSRC list)";
	if (str_shift(p, (rtp->v_p_x_cc & 0xf) * 4))
		goto error;

	if ((rtp->v_p_x_cc & 0x10)) {
		/* extension */
		err = "short packet (extension header)";
		if (p->len < sizeof(*ext))
			goto error;
		ext = (void *) p->s;
		err = "short packet (header extensions)";
		if (str_shift(p, sizeof(*ext) + ntohs(ext->length) * 4))
			goto error;
	}

done:
	*out = rtp;

	return 0;

error:
	ilog(LOG_DEBUG | LOG_FLAG_LIMIT, "Error parsing RTP header: %s", err);
	return -1;
}


int rtp_padding(const struct rtp_header *header, str *payload) {
	if (!header || !payload->s)
		return 0;
	if (!(header->v_p_x_cc & 0x20))
		return 0; // no padding
	if (payload->len == 0)
		return -1;
	unsigned int padding = (unsigned char) payload->s[payload->len - 1];
	if (payload->len < padding)
		return -1;
	payload->len -= padding;
	return 0;
}


const struct rtp_payload_type *rtp_get_rfc_payload_type(unsigned int type) {
	const struct rtp_payload_type *rtp_pt;

	if (type >= num_rfc_rtp_payload_types)
		return NULL;
	rtp_pt = &rfc_rtp_payload_types[type];
	if (!rtp_pt->encoding.s)
		return NULL;
	return rtp_pt;
}

// for one-time init only - better use rtp_get_rfc_payload_type(codec_def->rfc_payload_type)
const struct rtp_payload_type *rtp_get_rfc_codec(const str *codec) {
	for (int i = 0; i < num_rfc_rtp_payload_types; i++) {
		if (!rfc_rtp_payload_types[i].encoding.s)
			continue;
		if (str_cmp_str(codec, &rfc_rtp_payload_types[i].encoding))
			continue;
		return &rfc_rtp_payload_types[i];
	}
	return NULL;
}

// helper function: matches only basic params, without matching payload type number
bool rtp_payload_type_fmt_eq_nf(const struct rtp_payload_type *a, const struct rtp_payload_type *b) {
	if (a->clock_rate != b->clock_rate)
		return false;
	if (a->channels != b->channels)
		return false;
	if (str_casecmp_str(&a->encoding, &b->encoding)) {
#ifdef WITH_TRANSCODING
		// last ditch effort: see if it's a botched alias name (AKA G729a)
		if (!a->codec_def || !b->codec_def)
			return false;
		if (a->codec_def->rfc_payload_type == -1 || b->codec_def->rfc_payload_type == -1)
			return false;
		if (a->codec_def->rfc_payload_type != b->codec_def->rfc_payload_type)
			return false;
		if (a->codec_def->codec_type != b->codec_def->codec_type)
			return false;
		if (a->codec_def->avcodec_id != b->codec_def->avcodec_id)
			return false;
		// consider them the same
		return true;
#else
		return false;
#endif
	}
	return true;
}

// matches basic params and format params, but not payload type number
// returns matching val as per format_cmp_f
int rtp_payload_type_fmt_cmp(const struct rtp_payload_type *a, const struct rtp_payload_type *b) {
	if (!rtp_payload_type_fmt_eq_nf(a, b))
		return -1;
	if (a->codec_def && b->codec_def
			&& a->codec_def->format_cmp
			&& a->codec_def->format_cmp == b->codec_def->format_cmp) {
		return a->codec_def->format_cmp(a, b);
	}
	if (!a->codec_def) // ignore format of codecs we don't know
		return 0;
	if (str_cmp_str(&a->format_parameters, &b->format_parameters))
		return -1;
	return 0;
}
bool rtp_payload_type_fmt_eq_exact(const struct rtp_payload_type *a, const struct rtp_payload_type *b) {
	return rtp_payload_type_fmt_cmp(a, b) == 0;
}
bool rtp_payload_type_fmt_eq_compat(const struct rtp_payload_type *a, const struct rtp_payload_type *b) {
	return rtp_payload_type_fmt_cmp(a, b) >= 0;
}

bool rtp_payload_type_eq_exact(const struct rtp_payload_type *a, const struct rtp_payload_type *b) {
	if (a->payload_type != b->payload_type)
		return false;
	return rtp_payload_type_fmt_cmp(a, b) == 0;
}
bool rtp_payload_type_eq_compat(const struct rtp_payload_type *a, const struct rtp_payload_type *b) {
	if (a->payload_type != b->payload_type)
		return false;
	return rtp_payload_type_fmt_cmp(a, b) >= 0;
}

// same as rtp_payload_type_fmt_eq_nf plus matching payload type number
bool rtp_payload_type_eq_nf(const struct rtp_payload_type *a, const struct rtp_payload_type *b) {
	if (a->payload_type != b->payload_type)
		return false;
	return rtp_payload_type_fmt_eq_nf(a, b);
}