rtpsession: Send FIR requests in response to key unit requests with all-headers=TRUE
authorOlivier CrĂȘte <olivier.crete@collabora.com>
Thu, 1 Sep 2011 21:47:38 +0000 (17:47 -0400)
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Mon, 14 Nov 2011 11:26:27 +0000 (12:26 +0100)
https://bugzilla.gnome.org/show_bug.cgi?id=658419

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

index fd5944a..881dc4b 100644 (file)
@@ -1386,7 +1386,7 @@ gst_rtp_session_event_recv_rtp_sink (GstPad * pad, GstEvent * event)
 
 static gboolean
 gst_rtp_session_request_remote_key_unit (GstRtpSession * rtpsession,
-    guint32 ssrc, guint payload, gboolean all_headers)
+    guint32 ssrc, guint payload, gboolean all_headers, gint count)
 {
   GstCaps *caps;
 
@@ -1395,14 +1395,16 @@ gst_rtp_session_request_remote_key_unit (GstRtpSession * rtpsession,
   if (caps) {
     const GstStructure *s = gst_caps_get_structure (caps, 0);
     gboolean pli;
+    gboolean fir;
 
     pli = gst_structure_has_field (s, "rtcp-fb-nack-pli");
+    fir = gst_structure_has_field (s, "rtcp-fb-ccm-fir") && all_headers;
 
     gst_caps_unref (caps);
 
-    if (pli)
+    if (pli || fir)
       return rtp_session_request_key_unit (rtpsession->priv->session, ssrc,
-          gst_clock_get_time (rtpsession->priv->sysclock));
+          gst_clock_get_time (rtpsession->priv->sysclock), fir, count);
   }
 
   return FALSE;
@@ -1431,10 +1433,13 @@ gst_rtp_session_event_recv_rtp_src (GstPad * pad, GstEvent * event)
           gst_structure_get_uint (s, "ssrc", &ssrc) &&
           gst_structure_get_uint (s, "payload", &pt)) {
         gboolean all_headers = FALSE;
+        gint count = -1;
 
         gst_structure_get_boolean (s, "all-headers", &all_headers);
+        if (gst_structure_get_int (s, "count", &count) && count < 0)
+          count += G_MAXINT;    /* Make sure count is positive if present */
         if (gst_rtp_session_request_remote_key_unit (rtpsession, ssrc, pt,
-                all_headers))
+                all_headers, count))
           forward = FALSE;
       }
       break;
index 17b1b02..f499106 100644 (file)
@@ -2184,8 +2184,10 @@ rtp_session_request_local_key_unit (RTPSession * sess, RTPSource * src,
       rtp_source_get_ssrc (src), sess->callbacks.process_rtp,
       sess->callbacks.request_key_unit);
 
+  RTP_SESSION_UNLOCK (sess);
   sess->callbacks.request_key_unit (sess, fir,
       sess->request_key_unit_user_data);
+  RTP_SESSION_LOCK (sess);
 
   return TRUE;
 }
@@ -3301,7 +3303,8 @@ dont_send:
 }
 
 gboolean
-rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, GstClockTime now)
+rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, GstClockTime now,
+    gboolean fir, gint count)
 {
   RTPSource *src = g_hash_table_lookup (sess->ssrcs[sess->mask_idx],
       GUINT_TO_POINTER (ssrc));
@@ -3309,7 +3312,16 @@ rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc, GstClockTime now)
   if (!src)
     return FALSE;
 
-  src->send_pli = TRUE;
+  if (fir) {
+    src->send_pli = FALSE;
+    src->send_fir = TRUE;
+
+    if (count == -1 || count != src->last_fir_count)
+      src->current_send_fir_seqnum++;
+    src->last_fir_count = count;
+  } else if (!src->send_fir) {
+    src->send_pli = TRUE;
+  }
 
   rtp_session_request_early_rtcp (sess, now, 200 * GST_MSECOND);
 
@@ -3338,23 +3350,64 @@ rtp_session_on_sending_rtcp (RTPSession * sess, GstBuffer * buffer,
   gboolean ret = FALSE;
   GHashTableIter iter;
   gpointer key, value;
+  gboolean started_fir = FALSE;
+  GstRTCPPacket fir_rtcppacket;
 
   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 (buffer, 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,
+            rtp_source_get_ssrc (sess->source));
+        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 rtcppacket;
+    GstRTCPPacket pli_rtcppacket;
 
     if (media_src->send_pli && !rtp_source_has_retained (media_src,
             has_pli_compare_func, NULL)) {
-      if (gst_rtcp_buffer_add_packet (buffer, GST_RTCP_TYPE_PSFB, &rtcppacket)) {
-        gst_rtcp_packet_fb_set_type (&rtcppacket, GST_RTCP_PSFB_TYPE_PLI);
-        gst_rtcp_packet_fb_set_sender_ssrc (&rtcppacket,
+      if (gst_rtcp_buffer_add_packet (buffer, GST_RTCP_TYPE_PSFB,
+              &pli_rtcppacket)) {
+        gst_rtcp_packet_fb_set_type (&pli_rtcppacket, GST_RTCP_PSFB_TYPE_PLI);
+        gst_rtcp_packet_fb_set_sender_ssrc (&pli_rtcppacket,
             rtp_source_get_ssrc (sess->source));
-        gst_rtcp_packet_fb_set_media_ssrc (&rtcppacket, media_ssrc);
+        gst_rtcp_packet_fb_set_media_ssrc (&pli_rtcppacket, media_ssrc);
         ret = TRUE;
       } else {
         /* Break because the packet is full, will put next request in a
index 741d54b..ecc0b98 100644 (file)
@@ -351,6 +351,8 @@ void            rtp_session_request_early_rtcp     (RTPSession * sess, GstClockT
 /* Notify session of a request for a new key unit */
 gboolean        rtp_session_request_key_unit       (RTPSession * sess,
                                                     guint32 ssrc,
-                                                    GstClockTime now);
+                                                    GstClockTime now,
+                                                    gboolean fir,
+                                                    gint count);
 
 #endif /* __RTP_SESSION_H__ */
index 861ffde..fc204ae 100644 (file)
@@ -174,6 +174,9 @@ struct _RTPSource {
   GQueue        *retained_feedback;
 
   gboolean     send_pli;
+  gboolean     send_fir;
+  guint8       current_send_fir_seqnum;
+  gint         last_fir_count;
 };
 
 struct _RTPSourceClass {