summaryrefslogtreecommitdiff
path: root/toxav
diff options
context:
space:
mode:
authoriphydf <iphydf@users.noreply.github.com>2018-01-21 22:38:08 +0000
committeriphydf <iphydf@users.noreply.github.com>2018-02-01 23:35:44 +0000
commit83779a21eaf19bbf6aa5d61d8f59681a306e4f65 (patch)
treeb713524d8ce29ca05500fb95f315de94a4d4ae75 /toxav
parentd9413d557696e3aecde9d019e1738e99882d4579 (diff)
Manually serialise RTPHeader struct instead of memcpy.
Diffstat (limited to 'toxav')
-rw-r--r--toxav/BUILD.bazel10
-rw-r--r--toxav/rtp.c183
-rw-r--r--toxav/rtp.h66
-rw-r--r--toxav/rtp_test.cpp19
4 files changed, 193 insertions, 85 deletions
diff --git a/toxav/BUILD.bazel b/toxav/BUILD.bazel
index e9649c36..ff775fdd 100644
--- a/toxav/BUILD.bazel
+++ b/toxav/BUILD.bazel
@@ -35,6 +35,16 @@ cc_library(
35 deps = [":bwcontroller"], 35 deps = [":bwcontroller"],
36) 36)
37 37
38cc_test(
39 name = "rtp_test",
40 srcs = ["rtp_test.cpp"],
41 deps = [
42 ":rtp",
43 "//c-toxcore/toxcore:crypto_core",
44 "@gtest",
45 ],
46)
47
38cc_library( 48cc_library(
39 name = "audio", 49 name = "audio",
40 srcs = ["audio.c"], 50 srcs = ["audio.c"],
diff --git a/toxav/rtp.c b/toxav/rtp.c
index 01d4258a..650fbaf0 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright © 2016-2017 The TokTok team. 2 * Copyright © 2016-2018 The TokTok team.
3 * Copyright © 2013-2015 Tox project. 3 * Copyright © 2013-2015 Tox project.
4 * 4 *
5 * This file is part of Tox, the free peer to peer instant messenger. 5 * This file is part of Tox, the free peer to peer instant messenger.
@@ -34,6 +34,67 @@
34#include <stdlib.h> 34#include <stdlib.h>
35 35
36 36
37size_t rtp_header_pack(uint8_t *const rdata, const struct RTPHeader *header)
38{
39 uint8_t *p = rdata;
40 *p++ = (header->protocol_version & 3) << 6
41 | (header->pe & 1) << 5
42 | (header->xe & 1) << 4
43 | (header->cc & 0xf);
44 *p++ = (header->ma & 1) << 7
45 | (header->pt & 0x7f);
46
47 p += net_pack_u16(p, header->sequnum);
48 p += net_pack_u32(p, header->timestamp);
49 p += net_pack_u32(p, header->ssrc);
50 p += net_pack_u64(p, header->flags);
51 p += net_pack_u32(p, header->offset_full);
52 p += net_pack_u32(p, header->data_length_full);
53 p += net_pack_u32(p, header->received_length_full);
54
55 for (size_t i = 0; i < sizeof header->csrc / sizeof header->csrc[0]; i++) {
56 p += net_pack_u32(p, header->csrc[i]);
57 }
58
59 p += net_pack_u16(p, header->offset_lower);
60 p += net_pack_u16(p, header->data_length_lower);
61 assert(p == rdata + RTP_HEADER_SIZE);
62 return p - rdata;
63}
64
65
66size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header)
67{
68 const uint8_t *p = data;
69 header->protocol_version = (*p >> 6) & 3;
70 header->pe = (*p >> 5) & 1;
71 header->xe = (*p >> 4) & 1;
72 header->cc = *p & 0xf;
73 ++p;
74
75 header->ma = (*p >> 7) & 1;
76 header->pt = *p & 0x7f;
77 ++p;
78
79 p += net_unpack_u16(p, &header->sequnum);
80 p += net_unpack_u32(p, &header->timestamp);
81 p += net_unpack_u32(p, &header->ssrc);
82 p += net_unpack_u64(p, &header->flags);
83 p += net_unpack_u32(p, &header->offset_full);
84 p += net_unpack_u32(p, &header->data_length_full);
85 p += net_unpack_u32(p, &header->received_length_full);
86
87 for (size_t i = 0; i < sizeof header->csrc / sizeof header->csrc[0]; i++) {
88 p += net_unpack_u32(p, &header->csrc[i]);
89 }
90
91 p += net_unpack_u16(p, &header->offset_lower);
92 p += net_unpack_u16(p, &header->data_length_lower);
93 assert(p == data + RTP_HEADER_SIZE);
94 return p - data;
95}
96
97
37int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object); 98int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object);
38 99
39 100
@@ -116,36 +177,37 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Log
116 return -1; 177 return -1;
117 } 178 }
118 179
119 VLA(uint8_t, rdata, length + sizeof(struct RTPHeader) + 1); 180 VLA(uint8_t, rdata, length + RTP_HEADER_SIZE + 1);
120 memset(rdata, 0, SIZEOF_VLA(rdata)); 181 memset(rdata, 0, SIZEOF_VLA(rdata));
121 182
122 rdata[0] = session->payload_type; 183 rdata[0] = session->payload_type;
123 184
124 struct RTPHeader *header = (struct RTPHeader *)(rdata + 1); 185 struct RTPHeader header = {0};
125 186
126 header->protocol_version = 2; 187 header.protocol_version = 2;
127 header->pe = 0; 188 header.pe = 0;
128 header->xe = 0; 189 header.xe = 0;
129 header->cc = 0; 190 header.cc = 0;
130 191
131 header->ma = 0; 192 header.ma = 0;
132 header->pt = session->payload_type % 128; 193 header.pt = session->payload_type % 128;
133 194
134 header->sequnum = net_htons(session->sequnum); 195 header.sequnum = session->sequnum;
135 header->timestamp = net_htonl(current_time_monotonic()); 196 header.timestamp = current_time_monotonic();
136 header->ssrc = net_htonl(session->ssrc); 197 header.ssrc = session->ssrc;
137 198
138 header->offset_lower = 0; 199 header.offset_lower = 0;
139 header->data_length_lower = net_htons(length); 200 header.data_length_lower = length;
140 201
141 if (MAX_CRYPTO_DATA_SIZE > length + sizeof(struct RTPHeader) + 1) { 202 if (MAX_CRYPTO_DATA_SIZE > length + RTP_HEADER_SIZE + 1) {
142 203
143 /** 204 /**
144 * The length is lesser than the maximum allowed length (including header) 205 * The length is lesser than the maximum allowed length (including header)
145 * Send the packet in single piece. 206 * Send the packet in single piece.
146 */ 207 */
147 208
148 memcpy(rdata + 1 + sizeof(struct RTPHeader), data, length); 209 rtp_header_pack(rdata + 1, &header);
210 memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length);
149 211
150 if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, SIZEOF_VLA(rdata))) { 212 if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, SIZEOF_VLA(rdata))) {
151 LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", SIZEOF_VLA(rdata), strerror(errno)); 213 LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", SIZEOF_VLA(rdata), strerror(errno));
@@ -158,31 +220,33 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Log
158 */ 220 */
159 221
160 uint16_t sent = 0; 222 uint16_t sent = 0;
161 uint16_t piece = MAX_CRYPTO_DATA_SIZE - (sizeof(struct RTPHeader) + 1); 223 uint16_t piece = MAX_CRYPTO_DATA_SIZE - (RTP_HEADER_SIZE + 1);
162 224
163 while ((length - sent) + sizeof(struct RTPHeader) + 1 > MAX_CRYPTO_DATA_SIZE) { 225 while ((length - sent) + RTP_HEADER_SIZE + 1 > MAX_CRYPTO_DATA_SIZE) {
164 memcpy(rdata + 1 + sizeof(struct RTPHeader), data + sent, piece); 226 rtp_header_pack(rdata + 1, &header);
227 memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece);
165 228
166 if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, 229 if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number,
167 rdata, piece + sizeof(struct RTPHeader) + 1)) { 230 rdata, piece + RTP_HEADER_SIZE + 1)) {
168 LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", 231 LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s",
169 piece + sizeof(struct RTPHeader) + 1, strerror(errno)); 232 piece + RTP_HEADER_SIZE + 1, strerror(errno));
170 } 233 }
171 234
172 sent += piece; 235 sent += piece;
173 header->offset_lower = net_htons(sent); 236 header.offset_lower = sent;
174 } 237 }
175 238
176 /* Send remaining */ 239 /* Send remaining */
177 piece = length - sent; 240 piece = length - sent;
178 241
179 if (piece) { 242 if (piece) {
180 memcpy(rdata + 1 + sizeof(struct RTPHeader), data + sent, piece); 243 rtp_header_pack(rdata + 1, &header);
244 memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece);
181 245
182 if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, 246 if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata,
183 piece + sizeof(struct RTPHeader) + 1)) { 247 piece + RTP_HEADER_SIZE + 1)) {
184 LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", 248 LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s",
185 piece + sizeof(struct RTPHeader) + 1, strerror(errno)); 249 piece + RTP_HEADER_SIZE + 1, strerror(errno));
186 } 250 }
187 } 251 }
188 } 252 }
@@ -194,10 +258,10 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Log
194 258
195static bool chloss(const RTPSession *session, const struct RTPHeader *header) 259static bool chloss(const RTPSession *session, const struct RTPHeader *header)
196{ 260{
197 if (net_ntohl(header->timestamp) < session->rtimestamp) { 261 if (header->timestamp < session->rtimestamp) {
198 uint16_t hosq, lost = 0; 262 uint16_t hosq, lost = 0;
199 263
200 hosq = net_ntohs(header->sequnum); 264 hosq = header->sequnum;
201 265
202 lost = (hosq > session->rsequnum) ? 266 lost = (hosq > session->rsequnum) ?
203 (session->rsequnum + 65535) - hosq : 267 (session->rsequnum + 65535) - hosq :
@@ -218,21 +282,20 @@ static struct RTPMessage *new_message(size_t allocate_len, const uint8_t *data,
218{ 282{
219 assert(allocate_len >= data_length); 283 assert(allocate_len >= data_length);
220 284
221 struct RTPMessage *msg = (struct RTPMessage *)calloc(sizeof(struct RTPMessage) + (allocate_len - sizeof( 285 struct RTPMessage *msg = (struct RTPMessage *)calloc(sizeof(struct RTPMessage) +
222 struct RTPHeader)), 1); 286 (allocate_len - RTP_HEADER_SIZE), 1);
223
224 msg->len = data_length - sizeof(struct RTPHeader);
225 memcpy(&msg->header, data, data_length);
226 287
227 msg->header.sequnum = net_ntohs(msg->header.sequnum); 288 if (msg == nullptr) {
228 msg->header.timestamp = net_ntohl(msg->header.timestamp); 289 return nullptr;
229 msg->header.ssrc = net_ntohl(msg->header.ssrc); 290 }
230 291
231 msg->header.offset_lower = net_ntohs(msg->header.offset_lower); 292 msg->len = data_length - RTP_HEADER_SIZE;
232 msg->header.data_length_lower = net_ntohs(msg->header.data_length_lower); 293 rtp_header_unpack(data, &msg->header);
294 memcpy(msg->data, data + RTP_HEADER_SIZE, allocate_len - RTP_HEADER_SIZE);
233 295
234 return msg; 296 return msg;
235} 297}
298
236int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object) 299int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object)
237{ 300{
238 (void) m; 301 (void) m;
@@ -243,38 +306,40 @@ int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data,
243 data ++; 306 data ++;
244 length--; 307 length--;
245 308
246 if (!session || length < sizeof(struct RTPHeader)) { 309 if (!session || length < RTP_HEADER_SIZE) {
247 LOGGER_WARNING(m->log, "No session or invalid length of received buffer!"); 310 LOGGER_WARNING(m->log, "No session or invalid length of received buffer!");
248 return -1; 311 return -1;
249 } 312 }
250 313
251 const struct RTPHeader *header = (const struct RTPHeader *) data; 314 struct RTPHeader header;
315
316 rtp_header_unpack(data, &header);
252 317
253 if (header->pt != session->payload_type % 128) { 318 if (header.pt != session->payload_type % 128) {
254 LOGGER_WARNING(m->log, "Invalid payload type with the session"); 319 LOGGER_WARNING(m->log, "Invalid payload type with the session");
255 return -1; 320 return -1;
256 } 321 }
257 322
258 if (net_ntohs(header->offset_lower) >= net_ntohs(header->data_length_lower)) { 323 if (header.offset_lower >= header.data_length_lower) {
259 /* Never allow this case to happen */ 324 /* Never allow this case to happen */
260 return -1; 325 return -1;
261 } 326 }
262 327
263 bwc_feed_avg(session->bwc, length); 328 bwc_feed_avg(session->bwc, length);
264 329
265 if (net_ntohs(header->data_length_lower) == length - sizeof(struct RTPHeader)) { 330 if (header.data_length_lower == length - RTP_HEADER_SIZE) {
266 /* The message is sent in single part */ 331 /* The message is sent in single part */
267 332
268 /* Only allow messages which have arrived in order; 333 /* Only allow messages which have arrived in order;
269 * drop late messages 334 * drop late messages
270 */ 335 */
271 if (chloss(session, header)) { 336 if (chloss(session, &header)) {
272 return 0; 337 return 0;
273 } 338 }
274 339
275 /* Message is not late; pick up the latest parameters */ 340 /* Message is not late; pick up the latest parameters */
276 session->rsequnum = net_ntohs(header->sequnum); 341 session->rsequnum = header.sequnum;
277 session->rtimestamp = net_ntohl(header->timestamp); 342 session->rtimestamp = header.timestamp;
278 343
279 bwc_add_recv(session->bwc, length); 344 bwc_add_recv(session->bwc, length);
280 345
@@ -311,23 +376,23 @@ int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data,
311 * processing message 376 * processing message
312 */ 377 */
313 378
314 if (session->mp->header.sequnum == net_ntohs(header->sequnum) && 379 if (session->mp->header.sequnum == header.sequnum &&
315 session->mp->header.timestamp == net_ntohl(header->timestamp)) { 380 session->mp->header.timestamp == header.timestamp) {
316 /* First case */ 381 /* First case */
317 382
318 /* Make sure we have enough allocated memory */ 383 /* Make sure we have enough allocated memory */
319 if (session->mp->header.data_length_lower - session->mp->len < length - sizeof(struct RTPHeader) || 384 if (session->mp->header.data_length_lower - session->mp->len < length - RTP_HEADER_SIZE ||
320 session->mp->header.data_length_lower <= net_ntohs(header->offset_lower)) { 385 session->mp->header.data_length_lower <= header.offset_lower) {
321 /* There happened to be some corruption on the stream; 386 /* There happened to be some corruption on the stream;
322 * continue wihtout this part 387 * continue wihtout this part
323 */ 388 */
324 return 0; 389 return 0;
325 } 390 }
326 391
327 memcpy(session->mp->data + net_ntohs(header->offset_lower), data + sizeof(struct RTPHeader), 392 memcpy(session->mp->data + header.offset_lower, data + RTP_HEADER_SIZE,
328 length - sizeof(struct RTPHeader)); 393 length - RTP_HEADER_SIZE);
329 394
330 session->mp->len += length - sizeof(struct RTPHeader); 395 session->mp->len += length - RTP_HEADER_SIZE;
331 396
332 bwc_add_recv(session->bwc, length); 397 bwc_add_recv(session->bwc, length);
333 398
@@ -346,7 +411,7 @@ int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data,
346 } else { 411 } else {
347 /* Second case */ 412 /* Second case */
348 413
349 if (session->mp->header.timestamp > net_ntohl(header->timestamp)) { 414 if (session->mp->header.timestamp > header.timestamp) {
350 /* The received message part is from the old message; 415 /* The received message part is from the old message;
351 * discard it. 416 * discard it.
352 */ 417 */
@@ -359,7 +424,7 @@ int handle_rtp_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data,
359 424
360 /* Must account sizes of rtp headers too */ 425 /* Must account sizes of rtp headers too */
361 ((session->mp->header.data_length_lower - session->mp->len) / 426 ((session->mp->header.data_length_lower - session->mp->len) /
362 MAX_CRYPTO_DATA_SIZE) * sizeof(struct RTPHeader)); 427 MAX_CRYPTO_DATA_SIZE) * RTP_HEADER_SIZE);
363 428
364 /* Push the previous message for processing */ 429 /* Push the previous message for processing */
365 if (session->mcb) { 430 if (session->mcb) {
@@ -381,21 +446,21 @@ NEW_MULTIPARTED:
381 /* Only allow messages which have arrived in order; 446 /* Only allow messages which have arrived in order;
382 * drop late messages 447 * drop late messages
383 */ 448 */
384 if (chloss(session, header)) { 449 if (chloss(session, &header)) {
385 return 0; 450 return 0;
386 } 451 }
387 452
388 /* Message is not late; pick up the latest parameters */ 453 /* Message is not late; pick up the latest parameters */
389 session->rsequnum = net_ntohs(header->sequnum); 454 session->rsequnum = header.sequnum;
390 session->rtimestamp = net_ntohl(header->timestamp); 455 session->rtimestamp = header.timestamp;
391 456
392 bwc_add_recv(session->bwc, length); 457 bwc_add_recv(session->bwc, length);
393 458
394 /* Again, only store message if handler is present 459 /* Again, only store message if handler is present
395 */ 460 */
396 if (session->mcb) { 461 if (session->mcb) {
397 session->mp = new_message(net_ntohs(header->data_length_lower) + sizeof(struct RTPHeader), data, length); 462 session->mp = new_message(header.data_length_lower + RTP_HEADER_SIZE, data, length);
398 memmove(session->mp->data + net_ntohs(header->offset_lower), session->mp->data, session->mp->len); 463 memmove(session->mp->data + header.offset_lower, session->mp->data, session->mp->len);
399 } 464 }
400 } 465 }
401 466
diff --git a/toxav/rtp.h b/toxav/rtp.h
index 03e35498..3f684ee5 100644
--- a/toxav/rtp.h
+++ b/toxav/rtp.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright © 2016-2017 The TokTok team. 2 * Copyright © 2016-2018 The TokTok team.
3 * Copyright © 2013-2015 Tox project. 3 * Copyright © 2013-2015 Tox project.
4 * 4 *
5 * This file is part of Tox, the free peer to peer instant messenger. 5 * This file is part of Tox, the free peer to peer instant messenger.
@@ -27,6 +27,15 @@
27 27
28#include <stdbool.h> 28#include <stdbool.h>
29 29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34/**
35 * RTPHeader serialised size in bytes.
36 */
37#define RTP_HEADER_SIZE 80
38
30/** 39/**
31 * Payload type identifier. Also used as rtp callback prefix. 40 * Payload type identifier. Also used as rtp callback prefix.
32 */ 41 */
@@ -53,23 +62,13 @@ enum RTPFlags {
53 62
54struct RTPHeader { 63struct RTPHeader {
55 /* Standard RTP header */ 64 /* Standard RTP header */
56#ifndef WORDS_BIGENDIAN 65 unsigned protocol_version: 2; /* Version has only 2 bits! */
57 uint16_t cc: 4; /* Contributing sources count */ 66 unsigned pe: 1; /* Padding */
58 uint16_t xe: 1; /* Extra header */ 67 unsigned xe: 1; /* Extra header */
59 uint16_t pe: 1; /* Padding */ 68 unsigned cc: 4; /* Contributing sources count */
60 uint16_t protocol_version: 2; /* Version has only 2 bits! */ 69
61 70 unsigned ma: 1; /* Marker */
62 uint16_t pt: 7; /* Payload type */ 71 unsigned pt: 7; /* Payload type */
63 uint16_t ma: 1; /* Marker */
64#else
65 uint16_t protocol_version: 2; /* Version has only 2 bits! */
66 uint16_t pe: 1; /* Padding */
67 uint16_t xe: 1; /* Extra header */
68 uint16_t cc: 4; /* Contributing sources count */
69
70 uint16_t ma: 1; /* Marker */
71 uint16_t pt: 7; /* Payload type */
72#endif
73 72
74 uint16_t sequnum; 73 uint16_t sequnum;
75 uint32_t timestamp; 74 uint32_t timestamp;
@@ -112,20 +111,14 @@ struct RTPHeader {
112 * Total message length (lower bits). 111 * Total message length (lower bits).
113 */ 112 */
114 uint16_t data_length_lower; 113 uint16_t data_length_lower;
115} __attribute__((packed)); 114};
116
117/* Check alignment */
118typedef char __fail_if_misaligned_1 [ sizeof(struct RTPHeader) == 80 ? 1 : -1 ];
119 115
120struct RTPMessage { 116struct RTPMessage {
121 uint16_t len; 117 uint16_t len;
122 118
123 struct RTPHeader header; 119 struct RTPHeader header;
124 uint8_t data[]; 120 uint8_t data[];
125} __attribute__((packed)); 121};
126
127/* Check alignment */
128typedef char __fail_if_misaligned_2 [ sizeof(struct RTPMessage) == 82 ? 1 : -1 ];
129 122
130/** 123/**
131 * RTP control session. 124 * RTP control session.
@@ -147,6 +140,23 @@ typedef struct {
147 int (*mcb)(void *, struct RTPMessage *msg); 140 int (*mcb)(void *, struct RTPMessage *msg);
148} RTPSession; 141} RTPSession;
149 142
143/**
144 * Serialise an RTPHeader to bytes to be sent over the network.
145 *
146 * @param rdata A byte array of length RTP_HEADER_SIZE. Does not need to be
147 * initialised. All RTP_HEADER_SIZE bytes will be initialised after a call
148 * to this function.
149 * @param header The RTPHeader to serialise.
150 */
151size_t rtp_header_pack(uint8_t *rdata, const struct RTPHeader *header);
152
153/**
154 * Deserialise an RTPHeader from bytes received over the network.
155 *
156 * @param data A byte array of length RTP_HEADER_SIZE.
157 * @param header The RTPHeader to write the unpacked values to.
158 */
159size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header);
150 160
151RTPSession *rtp_new(int payload_type, Messenger *m, uint32_t friendnumber, 161RTPSession *rtp_new(int payload_type, Messenger *m, uint32_t friendnumber,
152 BWController *bwc, void *cs, 162 BWController *bwc, void *cs,
@@ -156,4 +166,8 @@ int rtp_allow_receiving(RTPSession *session);
156int rtp_stop_receiving(RTPSession *session); 166int rtp_stop_receiving(RTPSession *session);
157int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Logger *log); 167int rtp_send_data(RTPSession *session, const uint8_t *data, uint16_t length, Logger *log);
158 168
169#ifdef __cplusplus
170} // extern "C"
171#endif
172
159#endif /* RTP_H */ 173#endif /* RTP_H */
diff --git a/toxav/rtp_test.cpp b/toxav/rtp_test.cpp
new file mode 100644
index 00000000..76e369f0
--- /dev/null
+++ b/toxav/rtp_test.cpp
@@ -0,0 +1,19 @@
1#include "rtp.h"
2
3#include "../toxcore/crypto_core.h"
4
5#include <gtest/gtest.h>
6
7TEST(Rtp, Deserialisation) {
8 RTPHeader header;
9 random_bytes((uint8_t *)&header, sizeof header);
10
11 uint8_t rdata[sizeof(RTPHeader)];
12 EXPECT_EQ(rtp_header_pack(rdata, &header), RTP_HEADER_SIZE);
13
14 RTPHeader unpacked;
15 EXPECT_EQ(rtp_header_unpack(rdata, &unpacked), RTP_HEADER_SIZE);
16
17 EXPECT_EQ(std::string((char const *)&header, sizeof header),
18 std::string((char const *)&unpacked, sizeof unpacked));
19}