Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2018 The TokTok team. |
3 | | * Copyright © 2013-2015 Tox project. |
4 | | */ |
5 | | #include "rtp.h" |
6 | | |
7 | | #include <assert.h> |
8 | | #include <errno.h> |
9 | | #include <stdlib.h> |
10 | | #include <string.h> |
11 | | |
12 | | #include "bwcontroller.h" |
13 | | |
14 | | #include "../toxcore/Messenger.h" |
15 | | #include "../toxcore/ccompat.h" |
16 | | #include "../toxcore/logger.h" |
17 | | #include "../toxcore/mono_time.h" |
18 | | #include "../toxcore/util.h" |
19 | | |
20 | | /** |
21 | | * The number of milliseconds we want to keep a keyframe in the buffer for, |
22 | | * even though there are no free slots for incoming frames. |
23 | | */ |
24 | 0 | #define VIDEO_KEEP_KEYFRAME_IN_BUFFER_FOR_MS 15 |
25 | | |
26 | | |
27 | | /** |
28 | | * return -1 on failure, 0 on success |
29 | | * |
30 | | */ |
31 | | static int rtp_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length) |
32 | 329 | { |
33 | 329 | Tox_Err_Friend_Custom_Packet error; |
34 | 329 | tox_friend_send_lossy_packet(tox, friendnumber, data, (size_t)length, &error); |
35 | | |
36 | 329 | if (error == TOX_ERR_FRIEND_CUSTOM_PACKET_OK) { |
37 | 329 | return 0; |
38 | 329 | } |
39 | | |
40 | 0 | return -1; |
41 | 329 | } |
42 | | |
43 | | // allocate_len is NOT including header! |
44 | | static struct RTPMessage *new_message(const struct RTPHeader *header, size_t allocate_len, const uint8_t *data, |
45 | | uint16_t data_length) |
46 | 142 | { |
47 | 142 | assert(allocate_len >= data_length); |
48 | 142 | struct RTPMessage *msg = (struct RTPMessage *)calloc(1, sizeof(struct RTPMessage) + allocate_len); |
49 | | |
50 | 142 | if (msg == nullptr) { |
51 | 0 | return nullptr; |
52 | 0 | } |
53 | | |
54 | 142 | msg->len = data_length; // result without header |
55 | 142 | msg->header = *header; |
56 | 142 | memcpy(msg->data, data, msg->len); |
57 | 142 | return msg; |
58 | 142 | } |
59 | | |
60 | | /** |
61 | | * Instruct the caller to clear slot 0. |
62 | | */ |
63 | 179 | #define GET_SLOT_RESULT_DROP_OLDEST_SLOT (-1) |
64 | | |
65 | | /** |
66 | | * Instruct the caller to drop the incoming packet. |
67 | | */ |
68 | 179 | #define GET_SLOT_RESULT_DROP_INCOMING (-2) |
69 | | |
70 | | /** |
71 | | * Find the next free slot in work_buffer for the incoming data packet. |
72 | | * |
73 | | * - If the data packet belongs to a frame that's already in the work_buffer then |
74 | | * use that slot. |
75 | | * - If there is no free slot return GET_SLOT_RESULT_DROP_OLDEST_SLOT. |
76 | | * - If the data packet is too old return GET_SLOT_RESULT_DROP_INCOMING. |
77 | | * |
78 | | * If there is a keyframe being assembled in slot 0, keep it a bit longer and |
79 | | * do not kick it out right away if all slots are full instead kick out the new |
80 | | * incoming interframe. |
81 | | */ |
82 | | static int8_t get_slot(const Logger *log, struct RTPWorkBufferList *wkbl, bool is_keyframe, |
83 | | const struct RTPHeader *header, bool is_multipart) |
84 | 179 | { |
85 | 179 | if (is_multipart) { |
86 | | // This RTP message is part of a multipart frame, so we try to find an |
87 | | // existing slot with the previous parts of the frame in it. |
88 | 84 | for (uint8_t i = 0; i < wkbl->next_free_entry; ++i) { |
89 | 42 | const struct RTPWorkBuffer *slot = &wkbl->work_buffer[i]; |
90 | | |
91 | 42 | if ((slot->buf->header.sequnum == header->sequnum) && (slot->buf->header.timestamp == header->timestamp)) { |
92 | | // Sequence number and timestamp match, so this slot belongs to |
93 | | // the same frame. |
94 | | // |
95 | | // In reality, these will almost certainly either both match or |
96 | | // both not match. Only if somehow there were 65535 frames |
97 | | // between, the timestamp will matter. |
98 | 42 | return i; |
99 | 42 | } |
100 | 42 | } |
101 | 84 | } |
102 | | |
103 | | // The message may or may not be part of a multipart frame. |
104 | | // |
105 | | // If it is part of a multipart frame, then this is an entirely new frame |
106 | | // for which we did not have a slot *or* the frame is so old that its slot |
107 | | // has been evicted by now. |
108 | | // |
109 | | // |----------- time -----------> |
110 | | // _________________ |
111 | | // slot 0 | | |
112 | | // ----------------- |
113 | | // _________________ |
114 | | // slot 1 | | |
115 | | // ----------------- |
116 | | // ____________ |
117 | | // slot 2 | | -> frame too old, drop |
118 | | // ------------ |
119 | | // |
120 | | // |
121 | | // |
122 | | // |----------- time -----------> |
123 | | // _________________ |
124 | | // slot 0 | | |
125 | | // ----------------- |
126 | | // _________________ |
127 | | // slot 1 | | |
128 | | // ----------------- |
129 | | // ____________ |
130 | | // slot 2 | | -> ok, start filling in a new slot |
131 | | // ------------ |
132 | | |
133 | | // If there is a free slot: |
134 | 137 | if (wkbl->next_free_entry < USED_RTP_WORKBUFFER_COUNT) { |
135 | | // If there is at least one filled slot: |
136 | 137 | if (wkbl->next_free_entry > 0) { |
137 | | // Get the most recently filled slot. |
138 | 0 | const struct RTPWorkBuffer *slot = &wkbl->work_buffer[wkbl->next_free_entry - 1]; |
139 | | |
140 | | // If the incoming packet is older than our newest slot, drop it. |
141 | | // This is the first situation in the above diagram. |
142 | 0 | if (slot->buf->header.timestamp > header->timestamp) { |
143 | 0 | LOGGER_DEBUG(log, "workbuffer:2:timestamp too old"); |
144 | 0 | return GET_SLOT_RESULT_DROP_INCOMING; |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | | // Not all slots are filled, and the packet is newer than our most |
149 | | // recent slot, so it's a new frame we want to start assembling. This is |
150 | | // the second situation in the above diagram. |
151 | 137 | return wkbl->next_free_entry; |
152 | 137 | } |
153 | | |
154 | | // If the incoming frame is a key frame, then stop assembling the oldest |
155 | | // slot, regardless of whether there was a keyframe in that or not. |
156 | 0 | if (is_keyframe) { |
157 | 0 | return GET_SLOT_RESULT_DROP_OLDEST_SLOT; |
158 | 0 | } |
159 | | |
160 | | // The incoming slot is not a key frame, so we look at slot 0 to see what to |
161 | | // do next. |
162 | 0 | const struct RTPWorkBuffer *slot = &wkbl->work_buffer[0]; |
163 | | |
164 | | // The incoming frame is not a key frame, but the existing slot 0 is also |
165 | | // not a keyframe, so we stop assembling the existing frame and make space |
166 | | // for the new one. |
167 | 0 | if (!slot->is_keyframe) { |
168 | 0 | return GET_SLOT_RESULT_DROP_OLDEST_SLOT; |
169 | 0 | } |
170 | | |
171 | | // If this key frame is fully received, we also stop assembling and clear |
172 | | // slot 0. This also means sending the frame to the decoder. |
173 | 0 | if (slot->received_len == slot->buf->header.data_length_full) { |
174 | 0 | return GET_SLOT_RESULT_DROP_OLDEST_SLOT; |
175 | 0 | } |
176 | | |
177 | | // This is a key frame, not fully received yet, but it's already much older |
178 | | // than the incoming frame, so we stop assembling it and send whatever part |
179 | | // we did receive to the decoder. |
180 | 0 | if (slot->buf->header.timestamp + VIDEO_KEEP_KEYFRAME_IN_BUFFER_FOR_MS <= header->timestamp) { |
181 | 0 | return GET_SLOT_RESULT_DROP_OLDEST_SLOT; |
182 | 0 | } |
183 | | |
184 | | // This is a key frame, it's not too old yet, so we keep it in its slot for |
185 | | // a little longer. |
186 | 0 | LOGGER_INFO(log, "keep KEYFRAME in workbuffer"); |
187 | 0 | return GET_SLOT_RESULT_DROP_INCOMING; |
188 | 0 | } |
189 | | |
190 | | /** |
191 | | * Returns an assembled frame (as much data as we currently have for this frame, |
192 | | * some pieces may be missing) |
193 | | * |
194 | | * If there are no frames ready, we return NULL. If this function returns |
195 | | * non-NULL, it transfers ownership of the message to the caller, i.e. the |
196 | | * caller is responsible for storing it elsewhere or calling `free()`. |
197 | | */ |
198 | | static struct RTPMessage *process_frame(const Logger *log, struct RTPWorkBufferList *wkbl, uint8_t slot_id) |
199 | 137 | { |
200 | 137 | assert(wkbl->next_free_entry >= 0); |
201 | | |
202 | 137 | if (wkbl->next_free_entry == 0) { |
203 | | // There are no frames in any slot. |
204 | 0 | return nullptr; |
205 | 0 | } |
206 | | |
207 | | // Slot 0 contains a key frame, slot_id points at an interframe that is |
208 | | // relative to that key frame, so we don't use it yet. |
209 | 137 | if (wkbl->work_buffer[0].is_keyframe && slot_id != 0) { |
210 | 0 | LOGGER_DEBUG(log, "process_frame:KEYFRAME waiting in slot 0"); |
211 | 0 | return nullptr; |
212 | 0 | } |
213 | | |
214 | | // Either slot_id is 0 and slot 0 is a key frame, or there is no key frame |
215 | | // in slot 0 (and slot_id is anything). |
216 | 137 | struct RTPWorkBuffer *const slot = &wkbl->work_buffer[slot_id]; |
217 | | |
218 | | // Move ownership of the frame out of the slot into m_new. |
219 | 137 | struct RTPMessage *const m_new = slot->buf; |
220 | 137 | slot->buf = nullptr; |
221 | | |
222 | 137 | assert(wkbl->next_free_entry >= 1 && wkbl->next_free_entry <= USED_RTP_WORKBUFFER_COUNT); |
223 | | |
224 | 137 | if (slot_id != wkbl->next_free_entry - 1) { |
225 | | // The slot is not the last slot, so we created a gap. We move all the |
226 | | // entries after it one step up. |
227 | 0 | for (uint8_t i = slot_id; i < wkbl->next_free_entry - 1; ++i) { |
228 | | // Move entry (i+1) into entry (i). |
229 | 0 | wkbl->work_buffer[i] = wkbl->work_buffer[i + 1]; |
230 | 0 | } |
231 | 0 | } |
232 | | |
233 | | // We now have a free entry at the end of the array. |
234 | 137 | --wkbl->next_free_entry; |
235 | | |
236 | | // Clear the newly freed entry. |
237 | 137 | const struct RTPWorkBuffer empty = {0}; |
238 | 137 | wkbl->work_buffer[wkbl->next_free_entry] = empty; |
239 | | |
240 | | // Move ownership of the frame to the caller. |
241 | 137 | return m_new; |
242 | 137 | } |
243 | | |
244 | | /** |
245 | | * @param log A logger. |
246 | | * @param wkbl The list of in-progress frames, i.e. all the slots. |
247 | | * @param slot_id The slot we want to fill the data into. |
248 | | * @param is_keyframe Whether the data is part of a key frame. |
249 | | * @param header The RTP header from the incoming packet. |
250 | | * @param incoming_data The pure payload without header. |
251 | | * @param incoming_data_length The length in bytes of the incoming data payload. |
252 | | */ |
253 | | static bool fill_data_into_slot(const Logger *log, struct RTPWorkBufferList *wkbl, const uint8_t slot_id, |
254 | | bool is_keyframe, const struct RTPHeader *header, |
255 | | const uint8_t *incoming_data, uint16_t incoming_data_length) |
256 | 179 | { |
257 | | // We're either filling the data into an existing slot, or in a new one that |
258 | | // is the next free entry. |
259 | 179 | assert(slot_id <= wkbl->next_free_entry); |
260 | 179 | struct RTPWorkBuffer *const slot = &wkbl->work_buffer[slot_id]; |
261 | | |
262 | 179 | assert(header != nullptr); |
263 | 179 | assert(is_keyframe == (bool)((header->flags & RTP_KEY_FRAME) != 0)); |
264 | | |
265 | 179 | if (slot->received_len == 0) { |
266 | 137 | assert(slot->buf == nullptr); |
267 | | |
268 | | // No data for this slot has been received, yet, so we create a new |
269 | | // message for it with enough memory for the entire frame. |
270 | 137 | struct RTPMessage *msg = (struct RTPMessage *)calloc(1, sizeof(struct RTPMessage) + header->data_length_full); |
271 | | |
272 | 137 | if (msg == nullptr) { |
273 | 0 | LOGGER_ERROR(log, "Out of memory while trying to allocate for frame of size %u", |
274 | 0 | (unsigned)header->data_length_full); |
275 | | // Out of memory: throw away the incoming data. |
276 | 0 | return false; |
277 | 0 | } |
278 | | |
279 | | // Unused in the new video receiving code, as it's 16 bit and can't hold |
280 | | // the full length of large frames. Instead, we use slot->received_len. |
281 | 137 | msg->len = 0; |
282 | 137 | msg->header = *header; |
283 | | |
284 | 137 | slot->buf = msg; |
285 | 137 | slot->is_keyframe = is_keyframe; |
286 | 137 | slot->received_len = 0; |
287 | | |
288 | 137 | assert(wkbl->next_free_entry < USED_RTP_WORKBUFFER_COUNT); |
289 | 137 | ++wkbl->next_free_entry; |
290 | 137 | } |
291 | | |
292 | | // We already checked this when we received the packet, but we rely on it |
293 | | // here, so assert again. |
294 | 179 | assert(header->offset_full < header->data_length_full); |
295 | | |
296 | | // Copy the incoming chunk of data into the correct position in the full |
297 | | // frame data array. |
298 | 179 | memcpy( |
299 | 179 | slot->buf->data + header->offset_full, |
300 | 179 | incoming_data, |
301 | 179 | incoming_data_length |
302 | 179 | ); |
303 | | |
304 | | // Update the total received length of this slot. |
305 | 179 | slot->received_len += incoming_data_length; |
306 | | |
307 | | // Update received length also in the header of the message, for later use. |
308 | 179 | slot->buf->header.received_length_full = slot->received_len; |
309 | | |
310 | 179 | return slot->received_len == header->data_length_full; |
311 | 179 | } |
312 | | |
313 | | static void update_bwc_values(const Logger *log, RTPSession *session, const struct RTPMessage *msg) |
314 | 137 | { |
315 | 137 | if (session->first_packets_counter < DISMISS_FIRST_LOST_VIDEO_PACKET_COUNT) { |
316 | 54 | ++session->first_packets_counter; |
317 | 83 | } else { |
318 | 83 | const uint32_t data_length_full = msg->header.data_length_full; // without header |
319 | 83 | const uint32_t received_length_full = msg->header.received_length_full; // without header |
320 | 83 | bwc_add_recv(session->bwc, data_length_full); |
321 | | |
322 | 83 | if (received_length_full < data_length_full) { |
323 | 0 | LOGGER_DEBUG(log, "BWC: full length=%u received length=%d", data_length_full, received_length_full); |
324 | 0 | bwc_add_lost(session->bwc, data_length_full - received_length_full); |
325 | 0 | } |
326 | 83 | } |
327 | 137 | } |
328 | | |
329 | | /** |
330 | | * Handle a single RTP video packet. |
331 | | * |
332 | | * The packet may or may not be part of a multipart frame. This function will |
333 | | * find out and handle it appropriately. |
334 | | * |
335 | | * @param session The current RTP session with: |
336 | | * <code> |
337 | | * session->mcb == vc_queue_message() // this function is called from here |
338 | | * session->mp == struct RTPMessage * |
339 | | * session->cs == call->video.second // == VCSession created by vc_new() call |
340 | | * </code> |
341 | | * @param header The RTP header deserialised from the packet. |
342 | | * @param incoming_data The packet data *not* header, i.e. this is the actual |
343 | | * payload. |
344 | | * @param incoming_data_length The packet length *not* including header, i.e. |
345 | | * this is the actual payload length. |
346 | | * @param log A logger. |
347 | | * |
348 | | * @retval -1 on error. |
349 | | * @retval 0 on success. |
350 | | */ |
351 | | static int handle_video_packet(RTPSession *session, const struct RTPHeader *header, |
352 | | const uint8_t *incoming_data, uint16_t incoming_data_length, const Logger *log) |
353 | 179 | { |
354 | | // Full frame length in bytes. The frame may be split into multiple packets, |
355 | | // but this value is the complete assembled frame size. |
356 | 179 | const uint32_t full_frame_length = header->data_length_full; |
357 | | |
358 | | // Current offset in the frame. If this is the first packet of a multipart |
359 | | // frame or it's not a multipart frame, then this value is 0. |
360 | 179 | const uint32_t offset = header->offset_full; // without header |
361 | | |
362 | | // The sender tells us whether this is a key frame. |
363 | 179 | const bool is_keyframe = (header->flags & RTP_KEY_FRAME) != 0; |
364 | | |
365 | 179 | LOGGER_DEBUG(log, "-- handle_video_packet -- full lens=%u len=%u offset=%u is_keyframe=%s", |
366 | 179 | (unsigned)incoming_data_length, (unsigned)full_frame_length, (unsigned)offset, is_keyframe ? "K" : "."); |
367 | 179 | LOGGER_DEBUG(log, "wkbl->next_free_entry:003=%d", session->work_buffer_list->next_free_entry); |
368 | | |
369 | 179 | const bool is_multipart = full_frame_length != incoming_data_length; |
370 | | |
371 | | /* The message was sent in single part */ |
372 | 179 | int8_t slot_id = get_slot(log, session->work_buffer_list, is_keyframe, header, is_multipart); |
373 | 179 | LOGGER_DEBUG(log, "slot num=%d", slot_id); |
374 | | |
375 | | // get_slot told us to drop the packet, so we ignore it. |
376 | 179 | if (slot_id == GET_SLOT_RESULT_DROP_INCOMING) { |
377 | 0 | return -1; |
378 | 0 | } |
379 | | |
380 | | // get_slot said there is no free slot. |
381 | 179 | if (slot_id == GET_SLOT_RESULT_DROP_OLDEST_SLOT) { |
382 | 0 | LOGGER_DEBUG(log, "there was no free slot, so we process the oldest frame"); |
383 | | // We now own the frame. |
384 | 0 | struct RTPMessage *m_new = process_frame(log, session->work_buffer_list, 0); |
385 | | |
386 | | // The process_frame function returns NULL if there is no slot 0, i.e. |
387 | | // the work buffer list is completely empty. It can't be empty, because |
388 | | // get_slot just told us it's full, so process_frame must return non-null. |
389 | 0 | assert(m_new != nullptr); |
390 | | |
391 | 0 | LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-001a b0=%d b1=%d", (int)m_new->data[0], (int)m_new->data[1]); |
392 | 0 | update_bwc_values(log, session, m_new); |
393 | | // Pass ownership of m_new to the callback. |
394 | 0 | session->mcb(session->m->mono_time, session->cs, m_new); |
395 | | // Now we no longer own m_new. |
396 | 0 | m_new = nullptr; |
397 | | |
398 | | // Now we must have a free slot, so we either get that slot, i.e. >= 0, |
399 | | // or get told to drop the incoming packet if it's too old. |
400 | 0 | slot_id = get_slot(log, session->work_buffer_list, is_keyframe, header, /* is_multipart */false); |
401 | |
|
402 | 0 | if (slot_id == GET_SLOT_RESULT_DROP_INCOMING) { |
403 | | // The incoming frame is too old, so we drop it. |
404 | 0 | return -1; |
405 | 0 | } |
406 | 0 | } |
407 | | |
408 | | // We must have a valid slot here. |
409 | 179 | assert(slot_id >= 0); |
410 | | |
411 | 179 | LOGGER_DEBUG(log, "fill_data_into_slot.1"); |
412 | | |
413 | | // fill in this part into the slot buffer at the correct offset |
414 | 179 | if (!fill_data_into_slot( |
415 | 179 | log, |
416 | 179 | session->work_buffer_list, |
417 | 179 | slot_id, |
418 | 179 | is_keyframe, |
419 | 179 | header, |
420 | 179 | incoming_data, |
421 | 179 | incoming_data_length)) { |
422 | | // Memory allocation failed. Return error. |
423 | 42 | return -1; |
424 | 42 | } |
425 | | |
426 | 137 | struct RTPMessage *m_new = process_frame(log, session->work_buffer_list, slot_id); |
427 | | |
428 | 137 | if (m_new != nullptr) { |
429 | 137 | LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-003a b0=%d b1=%d", (int)m_new->data[0], (int)m_new->data[1]); |
430 | 137 | update_bwc_values(log, session, m_new); |
431 | 137 | session->mcb(session->m->mono_time, session->cs, m_new); |
432 | | |
433 | 137 | m_new = nullptr; |
434 | 137 | } |
435 | | |
436 | 137 | return 0; |
437 | 179 | } |
438 | | |
439 | | /** |
440 | | * @retval -1 on error. |
441 | | * @retval 0 on success. |
442 | | */ |
443 | | static int handle_rtp_packet(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object) |
444 | 321 | { |
445 | 321 | RTPSession *session = (RTPSession *)object; |
446 | | |
447 | 321 | if (session == nullptr || length < RTP_HEADER_SIZE + 1) { |
448 | 0 | LOGGER_WARNING(m->log, "No session or invalid length of received buffer!"); |
449 | 0 | return -1; |
450 | 0 | } |
451 | | |
452 | | // Get the packet type. |
453 | 321 | const uint8_t packet_type = data[0]; |
454 | 321 | ++data; |
455 | 321 | --length; |
456 | | |
457 | | // Unpack the header. |
458 | 321 | struct RTPHeader header; |
459 | 321 | rtp_header_unpack(data, &header); |
460 | | |
461 | 321 | if (header.pt != packet_type % 128) { |
462 | 0 | LOGGER_WARNING(m->log, "RTPHeader packet type and Tox protocol packet type did not agree: %d != %d", |
463 | 0 | header.pt, packet_type % 128); |
464 | 0 | return -1; |
465 | 0 | } |
466 | | |
467 | 321 | if (header.pt != session->payload_type % 128) { |
468 | 0 | LOGGER_WARNING(m->log, "RTPHeader packet type does not match this session's payload type: %d != %d", |
469 | 0 | header.pt, session->payload_type % 128); |
470 | 0 | return -1; |
471 | 0 | } |
472 | | |
473 | 321 | if ((header.flags & RTP_LARGE_FRAME) != 0 && header.offset_full >= header.data_length_full) { |
474 | 0 | LOGGER_ERROR(m->log, "Invalid video packet: frame offset (%u) >= full frame length (%u)", |
475 | 0 | (unsigned)header.offset_full, (unsigned)header.data_length_full); |
476 | 0 | return -1; |
477 | 0 | } |
478 | | |
479 | 321 | if (header.offset_lower >= header.data_length_lower) { |
480 | 0 | LOGGER_ERROR(m->log, "Invalid old protocol video packet: frame offset (%u) >= full frame length (%u)", |
481 | 0 | (unsigned)header.offset_lower, (unsigned)header.data_length_lower); |
482 | 0 | return -1; |
483 | 0 | } |
484 | | |
485 | 321 | LOGGER_DEBUG(m->log, "header.pt %d, video %d", (uint8_t)header.pt, RTP_TYPE_VIDEO % 128); |
486 | | |
487 | | // The sender uses the new large-frame capable protocol and is sending a |
488 | | // video packet. |
489 | 321 | if ((header.flags & RTP_LARGE_FRAME) != 0 && header.pt == (RTP_TYPE_VIDEO % 128)) { |
490 | 179 | return handle_video_packet(session, &header, data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE, m->log); |
491 | 179 | } |
492 | | |
493 | | // everything below here is for the old 16 bit protocol ------------------ |
494 | | |
495 | 142 | if (header.data_length_lower == length - RTP_HEADER_SIZE) { |
496 | | /* The message is sent in single part */ |
497 | | |
498 | | /* Message is not late; pick up the latest parameters */ |
499 | 142 | session->rsequnum = header.sequnum; |
500 | 142 | session->rtimestamp = header.timestamp; |
501 | 142 | bwc_add_recv(session->bwc, length); |
502 | | |
503 | | /* Invoke processing of active multiparted message */ |
504 | 142 | if (session->mp != nullptr) { |
505 | 0 | session->mcb(session->m->mono_time, session->cs, session->mp); |
506 | 0 | session->mp = nullptr; |
507 | 0 | } |
508 | | |
509 | | /* The message came in the allowed time; |
510 | | */ |
511 | | |
512 | 142 | return session->mcb(session->m->mono_time, session->cs, new_message(&header, length - RTP_HEADER_SIZE, |
513 | 142 | data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE)); |
514 | 142 | } |
515 | | |
516 | | /* The message is sent in multiple parts */ |
517 | | |
518 | 0 | if (session->mp != nullptr) { |
519 | | /* There are 2 possible situations in this case: |
520 | | * 1) being that we got the part of already processing message. |
521 | | * 2) being that we got the part of a new/old message. |
522 | | * |
523 | | * We handle them differently as we only allow a single multiparted |
524 | | * processing message |
525 | | */ |
526 | 0 | if (session->mp->header.sequnum == header.sequnum && |
527 | 0 | session->mp->header.timestamp == header.timestamp) { |
528 | | /* First case */ |
529 | | |
530 | | /* Make sure we have enough allocated memory */ |
531 | 0 | if (session->mp->header.data_length_lower - session->mp->len < length - RTP_HEADER_SIZE || |
532 | 0 | session->mp->header.data_length_lower <= header.offset_lower) { |
533 | | /* There happened to be some corruption on the stream; |
534 | | * continue wihtout this part |
535 | | */ |
536 | 0 | return 0; |
537 | 0 | } |
538 | | |
539 | 0 | memcpy(session->mp->data + header.offset_lower, data + RTP_HEADER_SIZE, |
540 | 0 | length - RTP_HEADER_SIZE); |
541 | 0 | session->mp->len += length - RTP_HEADER_SIZE; |
542 | 0 | bwc_add_recv(session->bwc, length); |
543 | |
|
544 | 0 | if (session->mp->len == session->mp->header.data_length_lower) { |
545 | | /* Received a full message; now push it for the further |
546 | | * processing. |
547 | | */ |
548 | 0 | session->mcb(session->m->mono_time, session->cs, session->mp); |
549 | 0 | session->mp = nullptr; |
550 | 0 | } |
551 | 0 | } else { |
552 | | /* Second case */ |
553 | 0 | if (session->mp->header.timestamp > header.timestamp) { |
554 | | /* The received message part is from the old message; |
555 | | * discard it. |
556 | | */ |
557 | 0 | return 0; |
558 | 0 | } |
559 | | |
560 | | /* Push the previous message for processing */ |
561 | 0 | session->mcb(session->m->mono_time, session->cs, session->mp); |
562 | |
|
563 | 0 | session->mp = nullptr; |
564 | 0 | goto NEW_MULTIPARTED; |
565 | 0 | } |
566 | 0 | } else { |
567 | | /* In this case threat the message as if it was received in order |
568 | | */ |
569 | | /* This is also a point for new multiparted messages */ |
570 | 0 | NEW_MULTIPARTED: |
571 | | |
572 | | /* Message is not late; pick up the latest parameters */ |
573 | 0 | session->rsequnum = header.sequnum; |
574 | 0 | session->rtimestamp = header.timestamp; |
575 | 0 | bwc_add_recv(session->bwc, length); |
576 | | |
577 | | /* Store message. |
578 | | */ |
579 | 0 | session->mp = new_message(&header, header.data_length_lower, data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE); |
580 | |
|
581 | 0 | if (session->mp != nullptr) { |
582 | 0 | memmove(session->mp->data + header.offset_lower, session->mp->data, session->mp->len); |
583 | 0 | } else { |
584 | 0 | LOGGER_WARNING(m->log, "new_message() returned a null pointer"); |
585 | 0 | return -1; |
586 | 0 | } |
587 | 0 | } |
588 | | |
589 | 0 | return 0; |
590 | 0 | } |
591 | | |
592 | | size_t rtp_header_pack(uint8_t *const rdata, const struct RTPHeader *header) |
593 | 331 | { |
594 | 331 | uint8_t *p = rdata; |
595 | 331 | *p = (header->ve & 3) << 6 |
596 | 331 | | (header->pe & 1) << 5 |
597 | 331 | | (header->xe & 1) << 4 |
598 | 331 | | (header->cc & 0xf); |
599 | 331 | ++p; |
600 | 331 | *p = (header->ma & 1) << 7 |
601 | 331 | | (header->pt & 0x7f); |
602 | 331 | ++p; |
603 | | |
604 | 331 | p += net_pack_u16(p, header->sequnum); |
605 | 331 | p += net_pack_u32(p, header->timestamp); |
606 | 331 | p += net_pack_u32(p, header->ssrc); |
607 | 331 | p += net_pack_u64(p, header->flags); |
608 | 331 | p += net_pack_u32(p, header->offset_full); |
609 | 331 | p += net_pack_u32(p, header->data_length_full); |
610 | 331 | p += net_pack_u32(p, header->received_length_full); |
611 | | |
612 | 3.97k | for (size_t i = 0; i < RTP_PADDING_FIELDS; ++i) { |
613 | 3.64k | p += net_pack_u32(p, 0); |
614 | 3.64k | } |
615 | | |
616 | 331 | p += net_pack_u16(p, header->offset_lower); |
617 | 331 | p += net_pack_u16(p, header->data_length_lower); |
618 | 331 | assert(p == rdata + RTP_HEADER_SIZE); |
619 | 331 | return p - rdata; |
620 | 331 | } |
621 | | |
622 | | size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header) |
623 | 322 | { |
624 | 322 | const uint8_t *p = data; |
625 | 322 | header->ve = (*p >> 6) & 3; |
626 | 322 | header->pe = (*p >> 5) & 1; |
627 | 322 | header->xe = (*p >> 4) & 1; |
628 | 322 | header->cc = *p & 0xf; |
629 | 322 | ++p; |
630 | | |
631 | 322 | header->ma = (*p >> 7) & 1; |
632 | 322 | header->pt = *p & 0x7f; |
633 | 322 | ++p; |
634 | | |
635 | 322 | p += net_unpack_u16(p, &header->sequnum); |
636 | 322 | p += net_unpack_u32(p, &header->timestamp); |
637 | 322 | p += net_unpack_u32(p, &header->ssrc); |
638 | 322 | p += net_unpack_u64(p, &header->flags); |
639 | 322 | p += net_unpack_u32(p, &header->offset_full); |
640 | 322 | p += net_unpack_u32(p, &header->data_length_full); |
641 | 322 | p += net_unpack_u32(p, &header->received_length_full); |
642 | | |
643 | 322 | p += sizeof(uint32_t) * RTP_PADDING_FIELDS; |
644 | | |
645 | 322 | p += net_unpack_u16(p, &header->offset_lower); |
646 | 322 | p += net_unpack_u16(p, &header->data_length_lower); |
647 | 322 | assert(p == data + RTP_HEADER_SIZE); |
648 | 322 | return p - data; |
649 | 322 | } |
650 | | |
651 | | RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnumber, |
652 | | BWController *bwc, void *cs, rtp_m_cb *mcb) |
653 | 36 | { |
654 | 36 | assert(mcb != nullptr); |
655 | 36 | assert(cs != nullptr); |
656 | 36 | assert(m != nullptr); |
657 | | |
658 | 36 | RTPSession *session = (RTPSession *)calloc(1, sizeof(RTPSession)); |
659 | | |
660 | 36 | if (session == nullptr) { |
661 | 0 | LOGGER_WARNING(m->log, "Alloc failed! Program might misbehave!"); |
662 | 0 | return nullptr; |
663 | 0 | } |
664 | | |
665 | 36 | session->work_buffer_list = (struct RTPWorkBufferList *)calloc(1, sizeof(struct RTPWorkBufferList)); |
666 | | |
667 | 36 | if (session->work_buffer_list == nullptr) { |
668 | 0 | LOGGER_ERROR(m->log, "out of memory while allocating work buffer list"); |
669 | 0 | free(session); |
670 | 0 | return nullptr; |
671 | 0 | } |
672 | | |
673 | | // First entry is free. |
674 | 36 | session->work_buffer_list->next_free_entry = 0; |
675 | | |
676 | 36 | session->ssrc = payload_type == RTP_TYPE_VIDEO ? 0 : random_u32(m->rng); |
677 | 36 | session->payload_type = payload_type; |
678 | 36 | session->m = m; |
679 | 36 | session->tox = tox; |
680 | 36 | session->friend_number = friendnumber; |
681 | | |
682 | | // set NULL just in case |
683 | 36 | session->mp = nullptr; |
684 | 36 | session->first_packets_counter = 1; |
685 | | |
686 | | /* Also set payload type as prefix */ |
687 | 36 | session->bwc = bwc; |
688 | 36 | session->cs = cs; |
689 | 36 | session->mcb = mcb; |
690 | | |
691 | 36 | if (-1 == rtp_allow_receiving(session)) { |
692 | 0 | LOGGER_WARNING(m->log, "Failed to start rtp receiving mode"); |
693 | 0 | free(session->work_buffer_list); |
694 | 0 | free(session); |
695 | 0 | return nullptr; |
696 | 0 | } |
697 | | |
698 | 36 | return session; |
699 | 36 | } |
700 | | |
701 | | void rtp_kill(RTPSession *session) |
702 | 36 | { |
703 | 36 | if (session == nullptr) { |
704 | 0 | return; |
705 | 0 | } |
706 | | |
707 | 36 | LOGGER_DEBUG(session->m->log, "Terminated RTP session: %p", (void *)session); |
708 | 36 | rtp_stop_receiving(session); |
709 | | |
710 | 36 | LOGGER_DEBUG(session->m->log, "Terminated RTP session V3 work_buffer_list->next_free_entry: %d", |
711 | 36 | (int)session->work_buffer_list->next_free_entry); |
712 | | |
713 | 36 | for (int8_t i = 0; i < session->work_buffer_list->next_free_entry; ++i) { |
714 | 0 | free(session->work_buffer_list->work_buffer[i].buf); |
715 | 0 | } |
716 | 36 | free(session->work_buffer_list); |
717 | 36 | free(session); |
718 | 36 | } |
719 | | |
720 | | int rtp_allow_receiving(RTPSession *session) |
721 | 61 | { |
722 | 61 | if (session == nullptr) { |
723 | 0 | return -1; |
724 | 0 | } |
725 | | |
726 | 61 | if (m_callback_rtp_packet(session->m, session->friend_number, session->payload_type, |
727 | 61 | handle_rtp_packet, session) == -1) { |
728 | 0 | LOGGER_WARNING(session->m->log, "Failed to register rtp receive handler"); |
729 | 0 | return -1; |
730 | 0 | } |
731 | | |
732 | 61 | LOGGER_DEBUG(session->m->log, "Started receiving on session: %p", (void *)session); |
733 | 61 | return 0; |
734 | 61 | } |
735 | | |
736 | | int rtp_stop_receiving(RTPSession *session) |
737 | 51 | { |
738 | 51 | if (session == nullptr) { |
739 | 0 | return -1; |
740 | 0 | } |
741 | | |
742 | 51 | m_callback_rtp_packet(session->m, session->friend_number, session->payload_type, nullptr, nullptr); |
743 | | |
744 | 51 | LOGGER_DEBUG(session->m->log, "Stopped receiving on session: %p", (void *)session); |
745 | 51 | return 0; |
746 | 51 | } |
747 | | |
748 | | /** |
749 | | * Send a frame of audio or video data, chunked in @ref RTPMessage instances. |
750 | | * |
751 | | * @param session The A/V session to send the data for. |
752 | | * @param data A byte array of length @p length. |
753 | | * @param length The number of bytes to send from @p data. |
754 | | * @param is_keyframe Whether this video frame is a key frame. If it is an |
755 | | * audio frame, this parameter is ignored. |
756 | | */ |
757 | | int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length, |
758 | | bool is_keyframe, const Logger *log) |
759 | 287 | { |
760 | 287 | if (session == nullptr) { |
761 | 0 | LOGGER_ERROR(log, "No session!"); |
762 | 0 | return -1; |
763 | 0 | } |
764 | | |
765 | 287 | struct RTPHeader header = {0}; |
766 | | |
767 | 287 | header.ve = 2; // this is unused in toxav |
768 | | |
769 | 287 | header.pe = 0; |
770 | | |
771 | 287 | header.xe = 0; |
772 | | |
773 | 287 | header.cc = 0; |
774 | | |
775 | 287 | header.ma = 0; |
776 | | |
777 | 287 | header.pt = session->payload_type % 128; |
778 | | |
779 | 287 | header.sequnum = session->sequnum; |
780 | | |
781 | 287 | header.timestamp = current_time_monotonic(session->m->mono_time); |
782 | | |
783 | 287 | header.ssrc = session->ssrc; |
784 | | |
785 | 287 | header.offset_lower = 0; |
786 | | |
787 | | // here the highest bits gets stripped anyway, no need to do keyframe bit magic here! |
788 | 287 | header.data_length_lower = length; |
789 | | |
790 | 287 | if (session->payload_type == RTP_TYPE_VIDEO) { |
791 | 142 | header.flags = RTP_LARGE_FRAME; |
792 | 142 | } |
793 | | |
794 | 287 | uint16_t length_safe = (uint16_t)length; |
795 | | |
796 | 287 | if (length > UINT16_MAX) { |
797 | 0 | length_safe = UINT16_MAX; |
798 | 0 | } |
799 | | |
800 | 287 | header.data_length_lower = length_safe; |
801 | 287 | header.data_length_full = length; // without header |
802 | 287 | header.offset_lower = 0; |
803 | 287 | header.offset_full = 0; |
804 | | |
805 | 287 | if (is_keyframe) { |
806 | 42 | header.flags |= RTP_KEY_FRAME; |
807 | 42 | } |
808 | | |
809 | 287 | const uint16_t rdata_size = length + RTP_HEADER_SIZE + 1; |
810 | 287 | VLA(uint8_t, rdata, rdata_size); |
811 | 287 | memset(rdata, 0, rdata_size); |
812 | 287 | rdata[0] = session->payload_type; // packet id == payload_type |
813 | | |
814 | 287 | if (MAX_CRYPTO_DATA_SIZE > (length + RTP_HEADER_SIZE + 1)) { |
815 | | /* |
816 | | * The length is lesser than the maximum allowed length (including header) |
817 | | * Send the packet in single piece. |
818 | | */ |
819 | 245 | rtp_header_pack(rdata + 1, &header); |
820 | 245 | memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length); |
821 | | |
822 | 245 | if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, rdata, rdata_size)) { |
823 | 0 | char *netstrerror = net_new_strerror(net_error()); |
824 | 0 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %u)! net error: %s", |
825 | 0 | rdata_size, netstrerror); |
826 | 0 | net_kill_strerror(netstrerror); |
827 | 0 | } |
828 | 245 | } else { |
829 | | /* |
830 | | * The length is greater than the maximum allowed length (including header) |
831 | | * Send the packet in multiple pieces. |
832 | | */ |
833 | 42 | uint32_t sent = 0; |
834 | 42 | uint16_t piece = MAX_CRYPTO_DATA_SIZE - (RTP_HEADER_SIZE + 1); |
835 | | |
836 | 84 | while ((length - sent) + RTP_HEADER_SIZE + 1 > MAX_CRYPTO_DATA_SIZE) { |
837 | 42 | rtp_header_pack(rdata + 1, &header); |
838 | 42 | memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece); |
839 | | |
840 | 42 | if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, |
841 | 42 | rdata, piece + RTP_HEADER_SIZE + 1)) { |
842 | 0 | char *netstrerror = net_new_strerror(net_error()); |
843 | 0 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! net error: %s", |
844 | 0 | piece + RTP_HEADER_SIZE + 1, netstrerror); |
845 | 0 | net_kill_strerror(netstrerror); |
846 | 0 | } |
847 | | |
848 | 42 | sent += piece; |
849 | 42 | header.offset_lower = sent; |
850 | 42 | header.offset_full = sent; // raw data offset, without any header |
851 | 42 | } |
852 | | |
853 | | /* Send remaining */ |
854 | 42 | piece = length - sent; |
855 | | |
856 | 42 | if (piece != 0) { |
857 | 42 | rtp_header_pack(rdata + 1, &header); |
858 | 42 | memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece); |
859 | | |
860 | 42 | if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, rdata, |
861 | 42 | piece + RTP_HEADER_SIZE + 1)) { |
862 | 0 | char *netstrerror = net_new_strerror(net_error()); |
863 | 0 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! net error: %s", |
864 | 0 | piece + RTP_HEADER_SIZE + 1, netstrerror); |
865 | 0 | net_kill_strerror(netstrerror); |
866 | 0 | } |
867 | 42 | } |
868 | 42 | } |
869 | | |
870 | 287 | ++session->sequnum; |
871 | 287 | return 0; |
872 | 287 | } |