Merge "res_rtp_asterisk: Improve video performance in certain networks." into 16

16.9
Kevin Harwell 6 years ago committed by Gerrit Code Review
commit 47658a0a2b

@ -103,8 +103,13 @@
#define TURN_STATE_WAIT_TIME 2000
#define DEFAULT_RTP_SEND_BUFFER_SIZE 250
#define DEFAULT_RTP_RECV_BUFFER_SIZE 20
#define DEFAULT_RTP_SEND_BUFFER_SIZE 250 /*!< The initial size of the RTP send buffer */
#define MAXIMUM_RTP_SEND_BUFFER_SIZE (DEFAULT_RTP_SEND_BUFFER_SIZE + 200) /*!< Maximum RTP send buffer size */
#define DEFAULT_RTP_RECV_BUFFER_SIZE 20 /*!< The initial size of the RTP receiver buffer */
#define MAXIMUM_RTP_RECV_BUFFER_SIZE (DEFAULT_RTP_RECV_BUFFER_SIZE + 20) /*!< Maximum RTP receive buffer size */
#define OLD_PACKET_COUNT 1000 /*!< The number of previous packets that are considered old */
#define MISSING_SEQNOS_ADDED_TRIGGER 2 /*!< The number of immediate missing packets that will trigger an immediate NACK */
#define SEQNO_CYCLE_OVER 65536 /*!< The number after the maximum allowed sequence number */
/*! Full INTRA-frame Request / Fast Update Request (From RFC2032) */
#define RTCP_PT_FUR 192
@ -4587,10 +4592,10 @@ static int ast_rtcp_generate_nack(struct ast_rtp_instance *instance, unsigned ch
{
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
int packet_len;
int blp_index;
int blp_index = -1;
int current_seqno;
int seqno;
unsigned int fci;
unsigned int fci = 0;
size_t remaining_missing_seqno;
if (!rtp || !rtp->rtcp) {
return 0;
@ -4601,32 +4606,50 @@ static int ast_rtcp_generate_nack(struct ast_rtp_instance *instance, unsigned ch
}
current_seqno = rtp->expectedrxseqno;
seqno = rtp->lastrxseqno;
remaining_missing_seqno = AST_VECTOR_SIZE(&rtp->missing_seqno);
packet_len = 12; /* The header length is 12 (version line, packet source SSRC, media source SSRC) */
/* Get the missing sequence numbers for the FCI section of the NACK request */
for (blp_index = 0, fci = 0; current_seqno < seqno; current_seqno++, blp_index++) {
/* If there are no missing sequence numbers then don't bother sending a NACK needlessly */
if (!remaining_missing_seqno) {
return 0;
}
/* This iterates through the possible forward sequence numbers seeing which ones we
* have no packet for, adding it to the NACK until we are out of missing packets.
*/
while (remaining_missing_seqno) {
int *missing_seqno;
/* On the first entry to this loop blp_index will be -1, so this will become 0
* and the sequence number will be placed into the packet as the PID.
*/
blp_index++;
missing_seqno = AST_VECTOR_GET_CMP(&rtp->missing_seqno, current_seqno,
find_by_value);
if (missing_seqno) {
/* We hit the max blp size, reset */
if (blp_index >= 17) {
put_unaligned_uint32(rtcpheader + packet_len, htonl(fci));
fci = 0;
blp_index = 0;
packet_len += 4;
}
if (!missing_seqno) {
continue;
}
if (blp_index == 0) {
fci |= (current_seqno << 16);
} else {
fci |= (1 << (blp_index - 1));
}
/* We hit the max blp size, reset */
if (blp_index >= 17) {
put_unaligned_uint32(rtcpheader + packet_len, htonl(fci));
fci = 0;
blp_index = 0;
packet_len += 4;
/* Since we've used a missing sequence number, we're down one */
remaining_missing_seqno--;
}
if (blp_index == 0) {
fci |= (current_seqno << 16);
} else {
fci |= (1 << (blp_index - 1));
/* Handle cycling of the sequence number */
current_seqno++;
if (current_seqno == SEQNO_CYCLE_OVER) {
current_seqno = 0;
}
}
@ -5793,6 +5816,7 @@ static int ast_rtp_rtcp_handle_nack(struct ast_rtp_instance *instance, unsigned
int abs_send_time_id;
unsigned int now_msw = 0;
unsigned int now_lsw = 0;
unsigned int packets_not_found = 0;
if (!rtp->send_buffer) {
ast_debug(1, "Tried to handle NACK request, but we don't have a RTP packet storage!\n");
@ -5825,6 +5849,7 @@ static int ast_rtp_rtcp_handle_nack(struct ast_rtp_instance *instance, unsigned
res += rtp_sendto(instance, payload->buf, payload->size, 0, &remote_address, &ice);
} else {
ast_debug(1, "Received NACK request for RTP packet with seqno %d, but we don't have it\n", pid);
packets_not_found++;
}
/*
* The bitmask. Denoting the least significant bit as 1 and its most significant bit
@ -5846,6 +5871,7 @@ static int ast_rtp_rtcp_handle_nack(struct ast_rtp_instance *instance, unsigned
res += rtp_sendto(instance, payload->buf, payload->size, 0, &remote_address, &ice);
} else {
ast_debug(1, "Remote end also requested RTP packet with seqno %d, but we don't have it\n", seqno);
packets_not_found++;
}
}
blp >>= 1;
@ -5853,6 +5879,15 @@ static int ast_rtp_rtcp_handle_nack(struct ast_rtp_instance *instance, unsigned
}
}
if (packets_not_found) {
/* Grow the send buffer based on how many packets were not found in the buffer, but
* enforce a maximum.
*/
ast_data_buffer_resize(rtp->send_buffer, MIN(MAXIMUM_RTP_SEND_BUFFER_SIZE,
ast_data_buffer_max(rtp->send_buffer) + packets_not_found));
ast_debug(2, "Send buffer on RTP instance '%p' is now at maximum of %zu\n", instance, ast_data_buffer_max(rtp->send_buffer));
}
return res;
}
@ -7625,6 +7660,11 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
} else if (rtp->expectedrxseqno == -1 || seqno == rtp->expectedrxseqno) {
rtp->expectedrxseqno = seqno + 1;
/* We've cycled over, so go back to 0 */
if (rtp->expectedrxseqno == SEQNO_CYCLE_OVER) {
rtp->expectedrxseqno = 0;
}
/* If there are no buffered packets that will be placed after this frame then we can
* return it directly without duplicating it.
*/
@ -7643,7 +7683,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
/* If we don't have the next packet after this we can directly return the frame, as there is no
* chance it will be overwritten.
*/
if (!ast_data_buffer_get(rtp->recv_buffer, seqno + 1)) {
if (!ast_data_buffer_get(rtp->recv_buffer, rtp->expectedrxseqno)) {
frame = ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno);
AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
return AST_LIST_FIRST(&frames);
@ -7654,9 +7694,10 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
* to the head of the frames list and avoid having to duplicate it but this would result in out
* of order packet processing by libsrtp which we are trying to avoid.
*/
frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, read_area, res, seqno - 1));
frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno));
if (frame) {
AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
prev_seqno = seqno;
}
/* Add any additional packets that we have buffered and that are available */
@ -7668,7 +7709,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
break;
}
frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, payload->buf, payload->size, rtp->expectedrxseqno - 1));
frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, payload->buf, payload->size, prev_seqno));
ast_free(payload);
if (!frame) {
@ -7681,11 +7722,15 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
ast_debug(2, "Pulled buffered packet with sequence number '%d' to additionally return on RTP instance '%p'\n",
frame->seqno, instance);
AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
prev_seqno = rtp->expectedrxseqno;
rtp->expectedrxseqno++;
if (rtp->expectedrxseqno == SEQNO_CYCLE_OVER) {
rtp->expectedrxseqno = 0;
}
}
return AST_LIST_FIRST(&frames);
} else if ((abs(seqno - rtp->expectedrxseqno) > 100) ||
} else if (((abs(seqno - rtp->expectedrxseqno) > 100) && timestamp > rtp->lastividtimestamp) ||
ast_data_buffer_count(rtp->recv_buffer) == ast_data_buffer_max(rtp->recv_buffer)) {
int inserted = 0;
@ -7701,43 +7746,46 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
rtp_write_rtcp_fir(instance, rtp, &remote_address);
}
/* This works by going through the progression of the sequence number retrieving buffered packets
* or inserting the current received packet until we've run out of packets. This ensures that the
* packets are in the correct sequence number order.
*/
while (ast_data_buffer_count(rtp->recv_buffer)) {
struct ast_rtp_rtcp_nack_payload *payload;
payload = (struct ast_rtp_rtcp_nack_payload *)ast_data_buffer_remove_head(rtp->recv_buffer);
if (!payload) {
/* If the packet we received is the one we are expecting at this point then add it in */
if (rtp->expectedrxseqno == seqno) {
frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno));
if (frame) {
AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
prev_seqno = seqno;
ast_debug(2, "Inserted just received packet with sequence number '%d' in correct order on RTP instance '%p'\n",
seqno, instance);
}
rtp->expectedrxseqno++;
if (rtp->expectedrxseqno == SEQNO_CYCLE_OVER) {
rtp->expectedrxseqno = 0;
}
inserted = 1;
continue;
}
/* Even when dumping the receive buffer we do our best to order things, so we ensure that the
* packet we just received is processed in the correct order, so see if we need to insert it now.
*/
if (!inserted) {
int buffer_seqno;
buffer_seqno = ntohl(payload->buf[0]) & 0xffff;
if (seqno < buffer_seqno) {
frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno));
if (frame) {
AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
rtp->expectedrxseqno = seqno + 1;
prev_seqno = seqno;
ast_debug(2, "Inserted just received packet with sequence number '%d' in correct order on RTP instance '%p'\n",
seqno, instance);
}
inserted = 1;
payload = (struct ast_rtp_rtcp_nack_payload *)ast_data_buffer_remove(rtp->recv_buffer, rtp->expectedrxseqno);
if (payload) {
frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, payload->buf, payload->size, prev_seqno));
if (frame) {
AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
prev_seqno = rtp->expectedrxseqno;
ast_debug(2, "Emptying queue and returning packet with sequence number '%d' from RTP instance '%p'\n",
frame->seqno, instance);
}
ast_free(payload);
}
frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, payload->buf, payload->size, prev_seqno));
if (frame) {
AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
prev_seqno = frame->seqno;
ast_debug(2, "Emptying queue and returning packet with sequence number '%d' from RTP instance '%p'\n",
frame->seqno, instance);
rtp->expectedrxseqno++;
if (rtp->expectedrxseqno == SEQNO_CYCLE_OVER) {
rtp->expectedrxseqno = 0;
}
ast_free(payload);
}
if (!inserted) {
@ -7749,11 +7797,21 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
frame = ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno);
AST_LIST_INSERT_TAIL(&frames, frame, frame_list);
rtp->expectedrxseqno = seqno + 1;
if (rtp->expectedrxseqno == SEQNO_CYCLE_OVER) {
rtp->expectedrxseqno = 0;
}
ast_debug(2, "Adding just received packet with sequence number '%d' to end of dumped queue on RTP instance '%p'\n",
seqno, instance);
}
/* When we flush increase our chance for next time by growing the receive buffer when possible
* by how many packets we missed, to give ourselves a bit more breathing room.
*/
ast_data_buffer_resize(rtp->recv_buffer, MIN(MAXIMUM_RTP_RECV_BUFFER_SIZE,
ast_data_buffer_max(rtp->recv_buffer) + AST_VECTOR_SIZE(&rtp->missing_seqno)));
ast_debug(2, "Receive buffer on RTP instance '%p' is now at maximum of %zu\n", instance, ast_data_buffer_max(rtp->recv_buffer));
/* As there is such a large gap we don't want to flood the order side with missing packets, so we
* give up and start anew.
*/
@ -7765,7 +7823,18 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
/* We're finished with the frames list */
ast_frame_free(AST_LIST_FIRST(&frames), 0);
if (seqno < rtp->expectedrxseqno) {
/* Determine if the received packet is from the last OLD_PACKET_COUNT (1000 by default) packets or not.
* For the case where the received sequence number exceeds that of the expected sequence number we calculate
* the past sequence number that would be 1000 sequence numbers ago. If the received sequence number
* exceeds or meets that then it is within OLD_PACKET_COUNT packets ago. For example if the expected
* sequence number is 100 and we receive 65530, then it would be considered old. This is because
* 65535 - 1000 + 100 = 64635 which gives us the sequence number at which we would consider the packets
* old. Since 65530 is above that, it would be considered old.
* For the case where the received sequence number is less than the expected sequence number we can do
* a simple subtraction to see if it is 1000 packets ago or not.
*/
if ((seqno < rtp->expectedrxseqno && ((rtp->expectedrxseqno - seqno) <= OLD_PACKET_COUNT)) ||
(seqno > rtp->expectedrxseqno && (seqno >= (65535 - OLD_PACKET_COUNT + rtp->expectedrxseqno)))) {
/* If this is a packet from the past then we have received a duplicate packet, so just drop it */
ast_debug(2, "Received an old packet with sequence number '%d' on RTP instance '%p', dropping it\n",
seqno, instance);
@ -7778,10 +7847,12 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
} else {
/* This is an out of order packet from the future */
struct ast_rtp_rtcp_nack_payload *payload;
int difference;
int missing_seqno;
int remove_failed;
unsigned int missing_seqnos_added = 0;
ast_debug(2, "Received an out of order packet with sequence number '%d' from the future on RTP instance '%p'\n",
seqno, instance);
ast_debug(2, "Received an out of order packet with sequence number '%d' while expecting '%d' from the future on RTP instance '%p'\n",
seqno, rtp->expectedrxseqno, instance);
payload = ast_malloc(sizeof(*payload) + res);
if (!payload) {
@ -7797,11 +7868,38 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
payload->size = res;
memcpy(payload->buf, rtpheader, res);
ast_data_buffer_put(rtp->recv_buffer, seqno, payload);
AST_VECTOR_REMOVE_CMP_ORDERED(&rtp->missing_seqno, seqno, find_by_value,
/* If this sequence number is removed that means we had a gap and this packet has filled it in
* some. Since it was part of the gap we will have already added any other missing sequence numbers
* before it (and possibly after it) to the vector so we don't need to do that again. Note that
* remove_failed will be set to -1 if the sequence number isn't removed, and 0 if it is.
*/
remove_failed = AST_VECTOR_REMOVE_CMP_ORDERED(&rtp->missing_seqno, seqno, find_by_value,
AST_VECTOR_ELEM_CLEANUP_NOOP);
if (!remove_failed) {
ast_debug(2, "Packet with sequence number '%d' on RTP instance '%p' is no longer missing\n",
seqno, instance);
}
/* The missing sequence number code works by taking the sequence number of the
* packet we've just received and going backwards until we hit the sequence number
* of the last packet we've received. While doing so we check to make sure that the
* sequence number is not already missing and that it is not already buffered.
*/
missing_seqno = seqno;
while (remove_failed) {
missing_seqno -= 1;
/* If we've cycled backwards then start back at the top */
if (missing_seqno < 0) {
missing_seqno = 65535;
}
/* We've gone backwards enough such that we've hit the previous sequence number */
if (missing_seqno == prev_seqno) {
break;
}
difference = seqno - (prev_seqno + 1);
while (difference > 0) {
/* We don't want missing sequence number duplicates. If, for some reason,
* packets are really out of order, we could end up in this scenario:
*
@ -7814,24 +7912,34 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
*
* This will prevent the duplicate from being added.
*/
if (AST_VECTOR_GET_CMP(&rtp->missing_seqno, seqno - difference,
if (AST_VECTOR_GET_CMP(&rtp->missing_seqno, missing_seqno,
find_by_value)) {
difference--;
continue;
}
/* If this packet has been buffered already then don't count it amongst the
* missing.
*/
if (ast_data_buffer_get(rtp->recv_buffer, missing_seqno)) {
continue;
}
ast_debug(2, "Added missing sequence number '%d' to RTP instance '%p'\n",
seqno - difference, instance);
AST_VECTOR_ADD_SORTED(&rtp->missing_seqno, seqno - difference,
missing_seqno, instance);
AST_VECTOR_ADD_SORTED(&rtp->missing_seqno, missing_seqno,
compare_by_value);
difference--;
missing_seqnos_added++;
}
/* When our data buffer is half full we assume that the packets aren't just out of order but
* have actually been lost. To get them back we construct and send a NACK causing the sender to
* retransmit them.
/* When we add a large number of missing sequence numbers we assume there was a substantial
* gap in reception so we trigger an immediate NACK. When our data buffer is 1/4 full we
* assume that the packets aren't just out of order but have actually been lost. At 1/2
* full we get more aggressive and ask for retransmission when we get a new packet.
* To get them back we construct and send a NACK causing the sender to retransmit them.
*/
if (ast_data_buffer_count(rtp->recv_buffer) == ast_data_buffer_max(rtp->recv_buffer) / 2) {
if (missing_seqnos_added >= MISSING_SEQNOS_ADDED_TRIGGER ||
ast_data_buffer_count(rtp->recv_buffer) == ast_data_buffer_max(rtp->recv_buffer) / 4 ||
ast_data_buffer_count(rtp->recv_buffer) >= ast_data_buffer_max(rtp->recv_buffer) / 2) {
int packet_len = 0;
int res = 0;
int ice;

Loading…
Cancel
Save