aboutsummaryrefslogtreecommitdiff
path: root/gst/rtpmanager/rtpsession.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/rtpmanager/rtpsession.c')
-rw-r--r--gst/rtpmanager/rtpsession.c502
1 files changed, 320 insertions, 182 deletions
diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c
index 1ab81859..7794efd9 100644
--- a/gst/rtpmanager/rtpsession.c
+++ b/gst/rtpmanager/rtpsession.c
@@ -28,7 +28,6 @@
#include <gst/glib-compat-private.h>
-#include "gstrtpbin-marshal.h"
#include "rtpsession.h"
GST_DEBUG_CATEGORY_STATIC (rtp_session_debug);
@@ -112,11 +111,7 @@ static void rtp_session_set_property (GObject * object, guint prop_id,
static void rtp_session_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-static gboolean rtp_session_on_sending_rtcp (RTPSession * sess,
- GstBuffer * buffer, gboolean early);
-static void rtp_session_send_rtcp (RTPSession * sess,
- GstClockTimeDiff max_delay);
-
+static void rtp_session_send_rtcp (RTPSession * sess, GstClockTime max_delay);
static guint rtp_session_signals[LAST_SIGNAL] = { 0 };
@@ -163,7 +158,7 @@ rtp_session_class_init (RTPSessionClass * klass)
rtp_session_signals[SIGNAL_GET_SOURCE_BY_SSRC] =
g_signal_new ("get-source-by-ssrc", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (RTPSessionClass,
- get_source_by_ssrc), NULL, NULL, gst_rtp_bin_marshal_OBJECT__UINT,
+ get_source_by_ssrc), NULL, NULL, g_cclosure_marshal_generic,
RTP_TYPE_SOURCE, 1, G_TYPE_UINT);
/**
@@ -290,9 +285,8 @@ rtp_session_class_init (RTPSessionClass * klass)
rtp_session_signals[SIGNAL_ON_SENDING_RTCP] =
g_signal_new ("on-sending-rtcp", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_sending_rtcp),
- accumulate_trues, NULL, gst_rtp_bin_marshal_BOOLEAN__BOXED_BOOLEAN,
- G_TYPE_BOOLEAN, 2, GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE,
- G_TYPE_BOOLEAN);
+ accumulate_trues, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 2,
+ GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, G_TYPE_BOOLEAN);
/**
* RTPSession::on-feedback-rtcp:
@@ -310,9 +304,8 @@ rtp_session_class_init (RTPSessionClass * klass)
rtp_session_signals[SIGNAL_ON_FEEDBACK_RTCP] =
g_signal_new ("on-feedback-rtcp", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_feedback_rtcp),
- NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT_UINT_UINT_BOXED,
- G_TYPE_NONE, 5, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT,
- GST_TYPE_BUFFER);
+ NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 5, G_TYPE_UINT,
+ G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, GST_TYPE_BUFFER);
/**
* RTPSession::send-rtcp:
@@ -327,7 +320,7 @@ rtp_session_class_init (RTPSessionClass * klass)
g_signal_new ("send-rtcp", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (RTPSessionClass, send_rtcp), NULL, NULL,
- gst_rtp_bin_marshal_VOID__UINT64, G_TYPE_NONE, 1, G_TYPE_UINT64);
+ g_cclosure_marshal_generic, G_TYPE_NONE, 1, G_TYPE_UINT64);
g_object_class_install_property (gobject_class, PROP_INTERNAL_SSRC,
g_param_spec_uint ("internal-ssrc", "Internal SSRC",
@@ -451,7 +444,6 @@ rtp_session_class_init (RTPSessionClass * klass)
klass->get_source_by_ssrc =
GST_DEBUG_FUNCPTR (rtp_session_get_source_by_ssrc);
- klass->on_sending_rtcp = GST_DEBUG_FUNCPTR (rtp_session_on_sending_rtcp);
klass->send_rtcp = GST_DEBUG_FUNCPTR (rtp_session_send_rtcp);
GST_DEBUG_CATEGORY_INIT (rtp_session_debug, "rtpsession", 0, "RTP Session");
@@ -855,6 +847,10 @@ rtp_session_set_callbacks (RTPSession * sess, RTPSessionCallbacks * callbacks,
sess->callbacks.request_time = callbacks->request_time;
sess->request_time_user_data = user_data;
}
+ if (callbacks->notify_nack) {
+ sess->callbacks.notify_nack = callbacks->notify_nack;
+ sess->notify_nack_user_data = user_data;
+ }
}
/**
@@ -2083,8 +2079,7 @@ rtp_session_request_local_key_unit (RTPSession * sess, RTPSource * src,
GstClockTime round_trip_in_ns = gst_util_uint64_scale (round_trip,
GST_SECOND, 65536);
- if (sess->last_keyframe_request != GST_CLOCK_TIME_NONE &&
- current_time - sess->last_keyframe_request < 2 * round_trip_in_ns) {
+ if (current_time - sess->last_keyframe_request < 2 * round_trip_in_ns) {
GST_DEBUG ("Ignoring %s request because one was send without one "
"RTT (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
fir ? "FIR" : "PLI",
@@ -2178,6 +2173,32 @@ rtp_session_process_fir (RTPSession * sess, guint32 sender_ssrc,
}
static void
+rtp_session_process_nack (RTPSession * sess, guint32 sender_ssrc,
+ guint32 media_ssrc, guint8 * fci_data, guint fci_length,
+ GstClockTime current_time)
+{
+ if (!sess->callbacks.notify_nack)
+ return;
+
+ while (fci_length > 0) {
+ guint16 seqnum, blp;
+
+ seqnum = GST_READ_UINT16_BE (fci_data);
+ blp = GST_READ_UINT16_BE (fci_data + 2);
+
+ GST_DEBUG ("NACK #%u, blp %04x", seqnum, blp);
+
+ RTP_SESSION_UNLOCK (sess);
+ sess->callbacks.notify_nack (sess, seqnum, blp,
+ sess->notify_nack_user_data);
+ RTP_SESSION_LOCK (sess);
+
+ fci_data += 4;
+ fci_length -= 4;
+ }
+}
+
+static void
rtp_session_process_feedback (RTPSession * sess, GstRTCPPacket * packet,
RTPArrivalStats * arrival, GstClockTime current_time)
{
@@ -2239,6 +2260,14 @@ rtp_session_process_feedback (RTPSession * sess, GstRTCPPacket * packet,
}
break;
case GST_RTCP_TYPE_RTPFB:
+ switch (fbtype) {
+ case GST_RTCP_RTPFB_TYPE_NACK:
+ rtp_session_process_nack (sess, sender_ssrc, media_ssrc,
+ fci_data, fci_length, current_time);
+ break;
+ default:
+ break;
+ }
default:
break;
}
@@ -2646,6 +2675,7 @@ rtp_session_next_timeout (RTPSession * sess, GstClockTime current_time)
RTP_SESSION_LOCK (sess);
if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time)) {
+ GST_DEBUG ("have early rtcp time");
result = sess->next_early_rtcp_time;
goto early_exit;
}
@@ -2711,6 +2741,9 @@ typedef struct
RTPSession *sess;
RTPSource *source;
guint num_to_report;
+ gboolean have_fir;
+ gboolean have_pli;
+ gboolean have_nack;
GstBuffer *rtcp;
GstClockTime current_time;
guint64 ntpnstime;
@@ -2824,6 +2857,138 @@ reported:
}
}
+/* construct FIR */
+static void
+session_add_fir (const gchar * key, RTPSource * source, ReportData * data)
+{
+ GstRTCPPacket *packet = &data->packet;
+ guint16 len;
+ guint8 *fci_data;
+
+ if (!source->send_fir)
+ return;
+
+ len = gst_rtcp_packet_fb_get_fci_length (packet);
+ if (!gst_rtcp_packet_fb_set_fci_length (packet, len + 2))
+ /* exit because the packet is full, will put next request in a
+ * further packet */
+ return;
+
+ fci_data = gst_rtcp_packet_fb_get_fci (packet) + (len * 4);
+
+ GST_WRITE_UINT32_BE (fci_data, source->ssrc);
+ fci_data += 4;
+ fci_data[0] = source->current_send_fir_seqnum;
+ fci_data[1] = fci_data[2] = fci_data[3] = 0;
+
+ source->send_fir = FALSE;
+}
+
+static void
+session_fir (RTPSession * sess, ReportData * data)
+{
+ GstRTCPBuffer *rtcp = &data->rtcpbuf;
+ GstRTCPPacket *packet = &data->packet;
+
+ if (!gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_PSFB, packet))
+ return;
+
+ gst_rtcp_packet_fb_set_type (packet, GST_RTCP_PSFB_TYPE_FIR);
+ gst_rtcp_packet_fb_set_sender_ssrc (packet, data->source->ssrc);
+ gst_rtcp_packet_fb_set_media_ssrc (packet, 0);
+
+ g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+ (GHFunc) session_add_fir, data);
+
+ if (gst_rtcp_packet_fb_get_fci_length (packet) == 0)
+ gst_rtcp_packet_remove (packet);
+ else
+ data->may_suppress = FALSE;
+}
+
+static gboolean
+has_pli_compare_func (gconstpointer a, gconstpointer ignored)
+{
+ GstRTCPPacket packet;
+ GstRTCPBuffer rtcp = { NULL, };
+ gboolean ret = FALSE;
+
+ gst_rtcp_buffer_map ((GstBuffer *) a, GST_MAP_READ, &rtcp);
+
+ if (gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
+ if (gst_rtcp_packet_get_type (&packet) == GST_RTCP_TYPE_PSFB &&
+ gst_rtcp_packet_fb_get_type (&packet) == GST_RTCP_PSFB_TYPE_PLI)
+ ret = TRUE;
+ }
+
+ gst_rtcp_buffer_unmap (&rtcp);
+
+ return ret;
+}
+
+/* construct PLI */
+static void
+session_pli (const gchar * key, RTPSource * source, ReportData * data)
+{
+ GstRTCPBuffer *rtcp = &data->rtcpbuf;
+ GstRTCPPacket *packet = &data->packet;
+
+ if (!source->send_pli)
+ return;
+
+ if (rtp_source_has_retained (source, has_pli_compare_func, NULL))
+ return;
+
+ if (!gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_PSFB, packet))
+ /* exit because the packet is full, will put next request in a
+ * further packet */
+ return;
+
+ gst_rtcp_packet_fb_set_type (packet, GST_RTCP_PSFB_TYPE_PLI);
+ gst_rtcp_packet_fb_set_sender_ssrc (packet, data->source->ssrc);
+ gst_rtcp_packet_fb_set_media_ssrc (packet, source->ssrc);
+
+ source->send_pli = FALSE;
+ data->may_suppress = FALSE;
+}
+
+/* construct NACK */
+static void
+session_nack (const gchar * key, RTPSource * source, ReportData * data)
+{
+ GstRTCPBuffer *rtcp = &data->rtcpbuf;
+ GstRTCPPacket *packet = &data->packet;
+ guint32 *nacks;
+ guint n_nacks, i;
+ guint8 *fci_data;
+
+ if (!source->send_nack)
+ return;
+
+ if (!gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_RTPFB, packet))
+ /* exit because the packet is full, will put next request in a
+ * further packet */
+ return;
+
+ gst_rtcp_packet_fb_set_type (packet, GST_RTCP_RTPFB_TYPE_NACK);
+ gst_rtcp_packet_fb_set_sender_ssrc (packet, data->source->ssrc);
+ gst_rtcp_packet_fb_set_media_ssrc (packet, source->ssrc);
+
+ nacks = rtp_source_get_nacks (source, &n_nacks);
+ GST_DEBUG ("%u NACKs", n_nacks);
+ if (!gst_rtcp_packet_fb_set_fci_length (packet, n_nacks))
+ return;
+
+ fci_data = gst_rtcp_packet_fb_get_fci (packet);
+ for (i = 0; i < n_nacks; i++) {
+ GST_WRITE_UINT32_BE (fci_data, nacks[i]);
+ fci_data += 4;
+ }
+
+ rtp_source_clear_nacks (source);
+ data->may_suppress = FALSE;
+}
+
/* perform cleanup of sources that timed out */
static void
session_cleanup (const gchar * key, RTPSource * source, ReportData * data)
@@ -3045,14 +3210,19 @@ static gboolean
is_rtcp_time (RTPSession * sess, GstClockTime current_time, ReportData * data)
{
GstClockTime new_send_time, elapsed;
+ GstClockTime interval;
if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time))
data->is_early = TRUE;
else
data->is_early = FALSE;
- if (data->is_early && sess->next_early_rtcp_time < current_time)
+ if (data->is_early && sess->next_early_rtcp_time < current_time) {
+ GST_DEBUG ("early feedback %" GST_TIME_FORMAT " < now %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (sess->next_early_rtcp_time),
+ GST_TIME_ARGS (current_time));
goto early;
+ }
/* no need to check yet */
if (sess->next_rtcp_check_time == GST_CLOCK_TIME_NONE ||
@@ -3063,62 +3233,58 @@ is_rtcp_time (RTPSession * sess, GstClockTime current_time, ReportData * data)
return FALSE;
}
+early:
/* get elapsed time since we last reported */
elapsed = current_time - sess->last_rtcp_send_time;
- new_send_time = data->interval;
- /* perform forward reconsideration */
- if (new_send_time != GST_CLOCK_TIME_NONE) {
- new_send_time = rtp_stats_add_rtcp_jitter (&sess->stats, new_send_time);
+ /* take interval and add jitter */
+ interval = data->interval;
+ if (interval != GST_CLOCK_TIME_NONE)
+ interval = rtp_stats_add_rtcp_jitter (&sess->stats, interval);
+ /* perform forward reconsideration */
+ if (interval != GST_CLOCK_TIME_NONE) {
GST_DEBUG ("forward reconsideration %" GST_TIME_FORMAT ", elapsed %"
- GST_TIME_FORMAT, GST_TIME_ARGS (new_send_time),
- GST_TIME_ARGS (elapsed));
-
- new_send_time += sess->last_rtcp_send_time;
- }
-
- /* check if reconsideration */
- if (new_send_time == GST_CLOCK_TIME_NONE || current_time < new_send_time) {
- GST_DEBUG ("reconsider RTCP for %" GST_TIME_FORMAT,
- GST_TIME_ARGS (new_send_time));
- /* store new check time */
- sess->next_rtcp_check_time = new_send_time;
- return FALSE;
+ GST_TIME_FORMAT, GST_TIME_ARGS (interval), GST_TIME_ARGS (elapsed));
+ new_send_time = interval + sess->last_rtcp_send_time;
+ } else {
+ new_send_time = sess->last_rtcp_send_time;
}
-early:
-
- new_send_time = calculate_rtcp_interval (sess, FALSE, FALSE);
-
- GST_DEBUG ("can send RTCP now, next interval %" GST_TIME_FORMAT,
- GST_TIME_ARGS (new_send_time));
-
- sess->next_rtcp_check_time = new_send_time;
- if (new_send_time != GST_CLOCK_TIME_NONE) {
- sess->next_rtcp_check_time += current_time;
-
+ if (!data->is_early) {
+ /* check if reconsideration */
+ if (new_send_time == GST_CLOCK_TIME_NONE || current_time < new_send_time) {
+ GST_DEBUG ("reconsider RTCP for %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (new_send_time));
+ /* store new check time */
+ sess->next_rtcp_check_time = new_send_time;
+ return FALSE;
+ }
+ sess->next_rtcp_check_time = current_time + interval;
+ } else if (interval != GST_CLOCK_TIME_NONE) {
/* Apply the rules from RFC 4585 section 3.5.3 */
if (sess->stats.min_interval != 0 && !sess->first_rtcp) {
- GstClockTimeDiff T_rr_current_interval =
+ GstClockTime T_rr_current_interval =
g_random_double_range (0.5, 1.5) * sess->stats.min_interval;
/* This will caused the RTCP to be suppressed if no FB packets are added */
- if (sess->last_rtcp_send_time + T_rr_current_interval >
- sess->next_rtcp_check_time) {
+ if (sess->last_rtcp_send_time + T_rr_current_interval > new_send_time) {
GST_DEBUG ("RTCP packet could be suppressed min: %" GST_TIME_FORMAT
" last: %" GST_TIME_FORMAT
" + T_rr_current_interval: %" GST_TIME_FORMAT
- " > sess->next_rtcp_check_time: %" GST_TIME_FORMAT,
+ " > new_send_time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (sess->stats.min_interval),
GST_TIME_ARGS (sess->last_rtcp_send_time),
GST_TIME_ARGS (T_rr_current_interval),
- GST_TIME_ARGS (sess->next_rtcp_check_time));
+ GST_TIME_ARGS (new_send_time));
data->may_suppress = TRUE;
}
}
}
+ GST_DEBUG ("can send RTCP now, next interval %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (new_send_time));
+
return TRUE;
}
@@ -3129,9 +3295,20 @@ clone_ssrcs_hashtable (gchar * key, RTPSource * source, GHashTable * hash_table)
}
static gboolean
-remove_closing_sources (const gchar * key, RTPSource * source, gpointer * data)
+remove_closing_sources (const gchar * key, RTPSource * source,
+ ReportData * data)
{
- return source->closing;
+ if (source->closing)
+ return TRUE;
+
+ if (source->send_fir)
+ data->have_fir = TRUE;
+ if (source->send_pli)
+ data->have_pli = TRUE;
+ if (source->send_nack)
+ data->have_nack = TRUE;
+
+ return FALSE;
}
static void
@@ -3163,6 +3340,17 @@ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
if (!data->has_sdes)
session_sdes (sess, data);
+ if (data->have_fir)
+ session_fir (sess, data);
+
+ if (data->have_pli)
+ g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+ (GHFunc) session_pli, data);
+
+ if (data->have_nack)
+ g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+ (GHFunc) session_nack, data);
+
gst_rtcp_buffer_unmap (&data->rtcpbuf);
output = g_slice_new (ReportOutput);
@@ -3218,6 +3406,8 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
/* get a new interval, we need this for various cleanups etc */
data.interval = calculate_rtcp_interval (sess, TRUE, sess->first_rtcp);
+ GST_DEBUG ("interval %" GST_TIME_FORMAT, GST_TIME_ARGS (data.interval));
+
/* we need an internal source now */
if (sess->stats.internal_sources == 0) {
RTPSource *source;
@@ -3241,14 +3431,14 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
/* Now remove the marked sources */
g_hash_table_foreach_remove (sess->ssrcs[sess->mask_idx],
- (GHRFunc) remove_closing_sources, NULL);
+ (GHRFunc) remove_closing_sources, &data);
/* see if we need to generate SR or RR packets */
if (!is_rtcp_time (sess, current_time, &data))
goto done;
- GST_DEBUG ("doing RTCP generation %u for %u sources", sess->generation,
- data.num_to_report);
+ GST_DEBUG ("doing RTCP generation %u for %u sources, early %d",
+ sess->generation, data.num_to_report, data.is_early);
/* generate RTCP for all internal sources */
g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
@@ -3307,7 +3497,7 @@ done:
*/
void
rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
- GstClockTimeDiff max_delay)
+ GstClockTime max_delay)
{
GstClockTime T_dither_max;
@@ -3317,15 +3507,24 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
/* Check if already requested */
/* RFC 4585 section 3.5.2 step 2 */
- if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time))
+ if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time)) {
+ GST_LOG_OBJECT (sess, "already have next early rtcp time");
goto dont_send;
+ }
- if (!GST_CLOCK_TIME_IS_VALID (sess->next_rtcp_check_time))
+ if (!GST_CLOCK_TIME_IS_VALID (sess->next_rtcp_check_time)) {
+ GST_LOG_OBJECT (sess, "no next RTCP check time");
goto dont_send;
+ }
/* Ignore the request a scheduled packet will be in time anyway */
- if (current_time + max_delay > sess->next_rtcp_check_time)
+ if (current_time + max_delay > sess->next_rtcp_check_time) {
+ GST_LOG_OBJECT (sess, "next scheduled time is soon %" GST_TIME_FORMAT " + %"
+ GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (current_time),
+ GST_TIME_ARGS (max_delay), GST_TIME_ARGS (sess->next_rtcp_check_time));
goto dont_send;
+ }
/* RFC 4585 section 3.5.2 step 2b */
/* If the total sources is <=2, then there is only us and one peer */
@@ -3338,8 +3537,10 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
}
/* RFC 4585 section 3.5.2 step 3 */
- if (current_time + T_dither_max > sess->next_rtcp_check_time)
+ if (current_time + T_dither_max > sess->next_rtcp_check_time) {
+ GST_LOG_OBJECT (sess, "don't send because of dither");
goto dont_send;
+ }
/* RFC 4585 section 3.5.2 step 4
* Don't send if allow_early is FALSE, but not if we are in
@@ -3347,8 +3548,10 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
* application-specific threshold.
*/
if (sess->total_sources > sess->rtcp_immediate_feedback_threshold &&
- sess->allow_early == FALSE)
+ sess->allow_early == FALSE) {
+ GST_LOG_OBJECT (sess, "can't allow early feedback");
goto dont_send;
+ }
if (T_dither_max) {
/* Schedule an early transmission later */
@@ -3359,6 +3562,8 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
sess->next_early_rtcp_time = current_time;
}
+ GST_LOG_OBJECT (sess, "next early RTCP time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (sess->next_early_rtcp_time));
RTP_SESSION_UNLOCK (sess);
/* notify app of need to send packet early
@@ -3373,14 +3578,29 @@ dont_send:
RTP_SESSION_UNLOCK (sess);
}
+static void
+rtp_session_send_rtcp (RTPSession * sess, GstClockTime max_delay)
+{
+ GstClockTime now;
+
+ if (!sess->callbacks.send_rtcp)
+ return;
+
+ now = sess->callbacks.request_time (sess, sess->request_time_user_data);
+
+ rtp_session_request_early_rtcp (sess, now, max_delay);
+}
+
gboolean
-rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, GstClockTime now,
+rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc,
gboolean fir, gint count)
{
- RTPSource *src = find_source (sess, ssrc);
+ RTPSource *src;
+ RTP_SESSION_LOCK (sess);
+ src = find_source (sess, ssrc);
if (!src)
- return FALSE;
+ goto no_source;
if (fir) {
src->send_pli = FALSE;
@@ -3392,136 +3612,54 @@ rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, GstClockTime now,
} else if (!src->send_fir) {
src->send_pli = TRUE;
}
+ RTP_SESSION_UNLOCK (sess);
- rtp_session_request_early_rtcp (sess, now, 200 * GST_MSECOND);
+ rtp_session_send_rtcp (sess, 200 * GST_MSECOND);
return TRUE;
-}
-
-static gboolean
-has_pli_compare_func (gconstpointer a, gconstpointer ignored)
-{
- GstRTCPPacket packet;
- GstRTCPBuffer rtcp = { NULL, };
- gboolean ret = FALSE;
-
- gst_rtcp_buffer_map ((GstBuffer *) a, GST_MAP_READ, &rtcp);
- if (gst_rtcp_buffer_get_first_packet (&rtcp, &packet)) {
- if (gst_rtcp_packet_get_type (&packet) == GST_RTCP_TYPE_PSFB &&
- gst_rtcp_packet_fb_get_type (&packet) == GST_RTCP_PSFB_TYPE_PLI)
- ret = TRUE;
+ /* ERRORS */
+no_source:
+ {
+ RTP_SESSION_UNLOCK (sess);
+ return FALSE;
}
-
- gst_rtcp_buffer_unmap (&rtcp);
-
- return ret;
}
-static gboolean
-rtp_session_on_sending_rtcp (RTPSession * sess, GstBuffer * buffer,
- gboolean early)
+/**
+ * rtp_session_request_nack:
+ * @sess: a #RTPSession
+ * @ssrc: the SSRC
+ * @seqnum: the missing seqnum
+ * @max_delay: max delay to request NACK
+ *
+ * Request scheduling of a NACK feedback packet for @seqnum in @ssrc.
+ *
+ * Returns: %TRUE if the NACK feedback could be scheduled
+ */
+gboolean
+rtp_session_request_nack (RTPSession * sess, guint32 ssrc, guint16 seqnum,
+ GstClockTime max_delay)
{
- gboolean ret = FALSE;
- GHashTableIter iter;
- gpointer key, value;
- gboolean started_fir = FALSE;
- GstRTCPPacket fir_rtcppacket;
- GstRTCPPacket packet;
- GstRTCPBuffer rtcp = { NULL, };
- guint32 ssrc;
-
- gst_rtcp_buffer_map (buffer, GST_MAP_READWRITE, &rtcp);
-
- gst_rtcp_buffer_get_first_packet (&rtcp, &packet);
- switch (gst_rtcp_packet_get_type (&packet)) {
- case GST_RTCP_TYPE_SR:
- gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc,
- NULL, NULL, NULL, NULL);
- break;
- case GST_RTCP_TYPE_RR:
- ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
- break;
- default:
- goto done;
- }
+ RTPSource *source;
RTP_SESSION_LOCK (sess);
- g_hash_table_iter_init (&iter, sess->ssrcs[sess->mask_idx]);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- guint media_ssrc = GPOINTER_TO_UINT (key);
- RTPSource *media_src = value;
- guint8 *fci_data;
-
- if (media_src->send_fir) {
- if (!started_fir) {
- if (!gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_PSFB,
- &fir_rtcppacket))
- break;
- gst_rtcp_packet_fb_set_type (&fir_rtcppacket, GST_RTCP_PSFB_TYPE_FIR);
- gst_rtcp_packet_fb_set_sender_ssrc (&fir_rtcppacket, ssrc);
- gst_rtcp_packet_fb_set_media_ssrc (&fir_rtcppacket, 0);
-
- if (!gst_rtcp_packet_fb_set_fci_length (&fir_rtcppacket, 2)) {
- gst_rtcp_packet_remove (&fir_rtcppacket);
- break;
- }
- ret = TRUE;
- started_fir = TRUE;
- } else {
- if (!gst_rtcp_packet_fb_set_fci_length (&fir_rtcppacket,
- !gst_rtcp_packet_fb_get_fci_length (&fir_rtcppacket) + 2))
- break;
- }
-
- fci_data = gst_rtcp_packet_fb_get_fci (&fir_rtcppacket) -
- ((gst_rtcp_packet_fb_get_fci_length (&fir_rtcppacket) - 2) * 4);
-
- GST_WRITE_UINT32_BE (fci_data, media_ssrc);
- fci_data += 4;
- fci_data[0] = media_src->current_send_fir_seqnum;
- fci_data[1] = fci_data[2] = fci_data[3] = 0;
- media_src->send_fir = FALSE;
- }
- }
-
- g_hash_table_iter_init (&iter, sess->ssrcs[sess->mask_idx]);
- while (g_hash_table_iter_next (&iter, &key, &value)) {
- guint media_ssrc = GPOINTER_TO_UINT (key);
- RTPSource *media_src = value;
- GstRTCPPacket pli_rtcppacket;
+ source = find_source (sess, ssrc);
+ if (source == NULL)
+ goto no_source;
- if (media_src->send_pli && !rtp_source_has_retained (media_src,
- has_pli_compare_func, NULL)) {
- if (!gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_PSFB,
- &pli_rtcppacket))
- /* Break because the packet is full, will put next request in a
- * further packet */
- break;
- gst_rtcp_packet_fb_set_type (&pli_rtcppacket, GST_RTCP_PSFB_TYPE_PLI);
- gst_rtcp_packet_fb_set_sender_ssrc (&pli_rtcppacket, ssrc);
- gst_rtcp_packet_fb_set_media_ssrc (&pli_rtcppacket, media_ssrc);
- ret = TRUE;
- }
- media_src->send_pli = FALSE;
- }
+ GST_DEBUG ("request NACK for %08x, #%u", ssrc, seqnum);
+ rtp_source_register_nack (source, seqnum);
RTP_SESSION_UNLOCK (sess);
-done:
- gst_rtcp_buffer_unmap (&rtcp);
-
- return ret;
-}
-
-static void
-rtp_session_send_rtcp (RTPSession * sess, GstClockTimeDiff max_delay)
-{
- GstClockTime now;
+ rtp_session_send_rtcp (sess, max_delay);
- if (!sess->callbacks.send_rtcp)
- return;
-
- now = sess->callbacks.request_time (sess, sess->request_time_user_data);
+ return TRUE;
- rtp_session_request_early_rtcp (sess, now, max_delay);
+ /* ERRORS */
+no_source:
+ {
+ RTP_SESSION_UNLOCK (sess);
+ return FALSE;
+ }
}