session: handle partial RTCP report blocks
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 26 Jul 2013 15:17:31 +0000 (17:17 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 26 Jul 2013 15:29:10 +0000 (17:29 +0200)
When we have more SSRCs to report than what fit in an RTCP packet, use a
generation counter to make sure all of them end up in a packet eventually.

gst/rtpmanager/rtpsession.c
gst/rtpmanager/rtpsession.h
gst/rtpmanager/rtpsource.h

index 92066c3..5d09478 100644 (file)
@@ -1289,6 +1289,8 @@ add_source (RTPSession * sess, RTPSource * src)
 {
   g_hash_table_insert (sess->ssrcs[sess->mask_idx],
       GINT_TO_POINTER (src->ssrc), src);
+  /* report the new source ASAP */
+  src->generation = sess->generation;
   /* we have one more source now */
   sess->total_sources++;
   if (RTP_SOURCE_IS_ACTIVE (src))
@@ -2744,6 +2746,7 @@ typedef struct
   GstRTCPBuffer rtcpbuf;
   RTPSession *sess;
   RTPSource *source;
+  guint num_to_report;
   GstBuffer *rtcp;
   GstClockTime current_time;
   guint64 ntpnstime;
@@ -2799,15 +2802,23 @@ session_start_rtcp (RTPSession * sess, ReportData * data)
 static void
 session_report_blocks (const gchar * key, RTPSource * source, ReportData * data)
 {
+  RTPSession *sess = data->sess;
   GstRTCPPacket *packet = &data->packet;
   guint8 fractionlost;
   gint32 packetslost;
   guint32 exthighestseq, jitter;
   guint32 lsr, dlsr;
 
+  /* don't report for sources in future generations */
+  if (((gint16) (source->generation - sess->generation)) > 0) {
+    GST_DEBUG ("source %08x generation %u > %u", source->ssrc,
+        source->generation, sess->generation);
+    return;
+  }
+
   /* only report about other sender */
   if (source == data->source)
-    return;
+    goto reported;
 
   if (gst_rtcp_packet_get_rb_count (packet) == GST_RTCP_MAX_RB_COUNT) {
     GST_DEBUG ("max RB count reached");
@@ -2816,7 +2827,7 @@ session_report_blocks (const gchar * key, RTPSource * source, ReportData * data)
 
   if (!RTP_SOURCE_IS_SENDER (source)) {
     GST_DEBUG ("source %08x not sender", source->ssrc);
-    return;
+    goto reported;
   }
 
   GST_DEBUG ("create RB for SSRC %08x", source->ssrc);
@@ -2837,6 +2848,16 @@ session_report_blocks (const gchar * key, RTPSource * source, ReportData * data)
   /* packet is not yet filled, add report block for this source. */
   gst_rtcp_packet_add_rb (packet, source->ssrc, fractionlost, packetslost,
       exthighestseq, jitter, lsr, dlsr);
+
+reported:
+  /* source is reported, move to next generation */
+  source->generation = sess->generation + 1;
+
+  /* if we reported all sources in this generation, move to next */
+  if (--data->num_to_report == 0) {
+    sess->generation++;
+    GST_DEBUG ("all reported, generation now %u", sess->generation);
+  }
 }
 
 /* perform cleanup of sources that timed out */
@@ -2851,6 +2872,8 @@ session_cleanup (const gchar * key, RTPSource * source, ReportData * data)
   GstClockTime interval, binterval;
   GstClockTime btime;
 
+  GST_DEBUG ("look at %08x, generation %u", source->ssrc, source->generation);
+
   /* check for outdated collisions */
   if (source->internal) {
     GST_DEBUG ("Timing out collisions for %x", source->ssrc);
@@ -2963,8 +2986,10 @@ session_cleanup (const gchar * key, RTPSource * source, ReportData * data)
 
       on_sender_timeout (sess, source);
     }
+    /* count how many source to report in this generation */
+    if (((gint16) (source->generation - sess->generation)) <= 0)
+      data->num_to_report++;
   }
-
   source->closing = remove;
 }
 
@@ -3166,7 +3191,7 @@ generate_rtcp (const gchar * key, RTPSource * source, ReportData * data)
     make_source_bye (sess, source, data);
     is_bye = TRUE;
   } else if (!data->is_early) {
-    /* loop over all known sources and add report blocks. If we are ealy, we
+    /* loop over all known sources and add report blocks. If we are early, we
      * just make a minimal RTCP packet and skip this step */
     g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
         (GHFunc) session_report_blocks, data);
@@ -3221,6 +3246,7 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
   data.current_time = current_time;
   data.ntpnstime = ntpnstime;
   data.running_time = running_time;
+  data.num_to_report = 0;
   data.may_suppress = FALSE;
   g_queue_init (&data.output);
 
@@ -3257,6 +3283,9 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
   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);
+
   /* generate RTCP for all internal sources */
   g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
       (GHFunc) generate_rtcp, &data);
index 8ab568e..76ee72d 100644 (file)
@@ -207,6 +207,7 @@ struct _RTPSession {
   GHashTable   *ssrcs[32];
   guint         total_sources;
 
+  guint16       generation;
   GstClockTime  next_rtcp_check_time;
   GstClockTime  last_rtcp_send_time;
   GstClockTime  start_time;
index 34b9d3b..bde29df 100644 (file)
@@ -135,6 +135,7 @@ struct _RTPSource {
   /*< private >*/
   guint32       ssrc;
 
+  guint16       generation;
   guint         probation;
   guint         curr_probation;
   gboolean      validated;