gstreamer/gst/rtpmanager/rtptimerqueue.h
Havard Graff 63c7a9ae43 rtpjitterbuffer: don't send multiple instant RTX for the same packet
Due to us not properly acknowleding the time when the last RTX was sent
when scheduling a new one, it can easily happen that due to the packet
you are requesting have a PTS that is slightly old (but not too old when
adding the latency of the jitterbuffer), both its calculated second and
third (etc.) timeout could already have passed. This would lead to a burst
of RTX requests, which acts completely against its purpose, potentially
spending a lot more bandwidth than needed.

This has been properly reproduced in the test:
test_rtx_not_bursting_requests

The good news is that slightly re-thinking the logic concerning
re-requesting RTX, made it a lot simpler to understand, and allows us
to remove two members of the RtpTimer which no longer serves any purpose
due to the refactoring. If desirable the whole "delay" concept can actually
be removed completely from the timers, and simply just added to the timeout
by the caller of the API. But that can be a change for a another time.

The only external change (other than the improved behavior around bursting
RTX) is that the "delay" field now stricly represents the delay between
the PTS of the RTX-requested packet and the time it is requested on,
whereas before this calculation was more about the theoretical calculated
delay. This is visible in three other RTX-tests where the delay had
to be adjusted slightly. I am confident however that this change is
correct.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/789>
2020-10-28 01:22:24 +01:00

126 lines
4.9 KiB
C

/* GStreamer RTP Manager
*
* Copyright 2007 Collabora Ltd,
* Copyright 2007 Nokia Corporation
* @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
* Copyright 2007 Wim Taymans <wim.taymans@gmail.com>
* Copyright 2015 Kurento (http://kurento.org/)
* @author: Miguel París <mparisdiaz@gmail.com>
* Copyright 2016 Pexip AS
* @author: Havard Graff <havard@pexip.com>
* @author: Stian Selnes <stian@pexip.com>
* Copyright (C) 2019 Net Insight AB
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <gst/gst.h>
#ifndef __RTP_TIMER_QUEUE_H__
#define __RTP_TIMER_QUEUE_H__
#define RTP_TYPE_TIMER_QUEUE rtp_timer_queue_get_type()
G_DECLARE_FINAL_TYPE (RtpTimerQueue, rtp_timer_queue, RTP_TIMER, QUEUE, GObject);
/**
* RtpTimerType:
* @RTP_TIMER_EXPECTED: This is used to track when to emit retranmission
* requests. They may be converted into %RTP_TIMER_LOST
* timer if the number of retry has been exhausted.
* @RTP_TIMER_LOST: This is used to track when a packet is considered lost.
* @RTP_TIMER_DEADLINE: This is used to track when the jitterbuffer should
* start pushing buffers.
* @RTP_TIMER_EOS: This is used to track when end of stream is reached.
*/
typedef enum
{
RTP_TIMER_EXPECTED,
RTP_TIMER_LOST,
RTP_TIMER_DEADLINE,
RTP_TIMER_EOS
} RtpTimerType;
typedef struct
{
GList list;
gboolean queued;
guint16 seqnum;
RtpTimerType type;
GstClockTime timeout;
GstClockTimeDiff offset;
GstClockTime duration;
GstClockTime rtx_base;
GstClockTime rtx_last;
guint num_rtx_retry;
guint num_rtx_received;
} RtpTimer;
void rtp_timer_free (RtpTimer * timer);
RtpTimer * rtp_timer_dup (const RtpTimer * timer);
static inline RtpTimer * rtp_timer_get_next (RtpTimer * timer)
{
GList *list = (GList *) timer;
return (RtpTimer *) list->next;
}
static inline RtpTimer * rtp_timer_get_prev (RtpTimer * timer)
{
GList *list = (GList *) timer;
return (RtpTimer *) list->prev;
}
RtpTimerQueue * rtp_timer_queue_new (void);
RtpTimer * rtp_timer_queue_find (RtpTimerQueue * queue, guint seqnum);
RtpTimer * rtp_timer_queue_peek_earliest (RtpTimerQueue * queue);
gboolean rtp_timer_queue_insert (RtpTimerQueue * queue, RtpTimer * timer);
gboolean rtp_timer_queue_reschedule (RtpTimerQueue * queue, RtpTimer * timer);
void rtp_timer_queue_unschedule (RtpTimerQueue * queue, RtpTimer * timer);
RtpTimer * rtp_timer_queue_pop_until (RtpTimerQueue * queue, GstClockTime timeout);
void rtp_timer_queue_remove_until (RtpTimerQueue * queue, GstClockTime timeout);
void rtp_timer_queue_remove_all (RtpTimerQueue * queue);
void rtp_timer_queue_set_timer (RtpTimerQueue * queue, RtpTimerType type,
guint16 seqnum, GstClockTime timeout,
GstClockTime delay, GstClockTime duration,
GstClockTimeDiff offset);
void rtp_timer_queue_set_expected (RtpTimerQueue * queue, guint16 seqnum,
GstClockTime timeout, GstClockTime delay,
GstClockTime duration);
void rtp_timer_queue_set_lost (RtpTimerQueue * queue, guint16 seqnum,
GstClockTime timeout,
GstClockTime duration, GstClockTimeDiff offset);
void rtp_timer_queue_set_eos (RtpTimerQueue * queue, GstClockTime timeout,
GstClockTimeDiff offset);
void rtp_timer_queue_set_deadline (RtpTimerQueue * queue, guint16 seqnum,
GstClockTime timeout, GstClockTimeDiff offset);
void rtp_timer_queue_update_timer (RtpTimerQueue * queue, RtpTimer * timer, guint16 seqnum,
GstClockTime timeout, GstClockTime delay,
GstClockTimeDiff offset, gboolean reset);
guint rtp_timer_queue_length (RtpTimerQueue * queue);
#endif