commit 0c89a43aa83b6bdd0491d8b043a0a1c0f59d3441
Author: Torrie Fischer <torrie.fischer@collabora.co.uk>
Date:   Mon Nov 11 13:10:25 2013 -0500

    gstrtpsession: Implement a number of feedback packet statistics

diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c
index 7a497b4..7ec7b3c 100644
--- a/gst/rtpmanager/gstrtpsession.c
+++ b/gst/rtpmanager/gstrtpsession.c
@@ -218,6 +218,10 @@ enum
   PROP_USE_PIPELINE_CLOCK,
   PROP_RTCP_MIN_INTERVAL,
   PROP_PROBATION,
+  PROP_RTX_COUNT,
+  PROP_RTX_DROP_COUNT,
+  PROP_SENT_NACK_COUNT,
+  PROP_RECV_NACK_COUNT,
   PROP_LAST
 };
 
@@ -251,6 +255,8 @@ struct _GstRtpSessionPrivate
   GstClockTime send_latency;
 
   gboolean use_pipeline_clock;
+
+  guint rtx_count;
 };
 
 /* callbacks to handle actions from the session manager */
@@ -613,6 +619,26 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass)
           0, G_MAXUINT, DEFAULT_PROBATION,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_RTX_COUNT,
+      g_param_spec_uint ("rtx-count", "Number of retransmissions recieved",
+          "Number of retransmissions recieved",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RTX_DROP_COUNT,
+      g_param_spec_uint ("rtx-drop-count", "Number of retransmissions recieved",
+          "Number of retransmissions recieved",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SENT_NACK_COUNT,
+      g_param_spec_uint ("sent-nack-count", "Number of NACKs sent",
+          "Number of NACKs sent",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RECV_NACK_COUNT,
+      g_param_spec_uint ("recv-nack-count", "Number of NACKs recieved",
+          "Number of NACKs recieved",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_rtp_session_change_state);
   gstelement_class->request_new_pad =
@@ -686,6 +712,8 @@ gst_rtp_session_init (GstRtpSession * rtpsession)
   gst_segment_init (&rtpsession->send_rtp_seg, GST_FORMAT_UNDEFINED);
 
   rtpsession->priv->thread_stopped = TRUE;
+
+  rtpsession->priv->rtx_count = 0;
 }
 
 static void
@@ -796,6 +824,18 @@ gst_rtp_session_get_property (GObject * object, guint prop_id,
     case PROP_PROBATION:
       g_object_get_property (G_OBJECT (priv->session), "probation", value);
       break;
+    case PROP_RTX_COUNT:
+      g_value_set_uint (value, priv->rtx_count);
+      break;
+    case PROP_RTX_DROP_COUNT:
+      g_object_get_property (G_OBJECT (priv->session), "nacks-dropped", value);
+      break;
+    case PROP_SENT_NACK_COUNT:
+      g_object_get_property (G_OBJECT (priv->session), "nacks-sent", value);
+      break;
+    case PROP_RECV_NACK_COUNT:
+      g_object_get_property (G_OBJECT (priv->session), "nacks-recieved", value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1519,6 +1559,10 @@ gst_rtp_session_event_recv_rtp_src (GstPad * pad, GstObject * parent,
         GstClockTime running_time;
         guint seqnum, delay, deadline, max_delay;
 
+        GST_RTP_SESSION_LOCK (rtpsession);
+        rtpsession->priv->rtx_count++;
+        GST_RTP_SESSION_UNLOCK (rtpsession);
+
         if (!gst_structure_get_clock_time (s, "running-time", &running_time))
           running_time = -1;
         if (!gst_structure_get_uint (s, "ssrc", &ssrc))
diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c
index c374815..09b73b8 100644
--- a/gst/rtpmanager/rtpsession.c
+++ b/gst/rtpmanager/rtpsession.c
@@ -86,6 +86,9 @@ enum
   PROP_RTCP_FEEDBACK_RETENTION_WINDOW,
   PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
   PROP_PROBATION,
+  PROP_NACKS_DROPPED,
+  PROP_NACKS_SENT,
+  PROP_NACKS_RECEIVED,
   PROP_LAST
 };
 
@@ -442,6 +445,21 @@ rtp_session_class_init (RTPSessionClass * klass)
           0, G_MAXUINT, DEFAULT_PROBATION,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_NACKS_DROPPED,
+      g_param_spec_uint ("nacks-dropped", "Number of NACKs dropped",
+          "Number of NACKs that were requested but not sent",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NACKS_SENT,
+      g_param_spec_uint ("nacks-sent", "Number of NACKs sent",
+          "Number of NACKs that were requested and sent",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_NACKS_RECEIVED,
+      g_param_spec_uint ("nacks-received", "Number of NACKs received",
+          "Number of NACKs that were received",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
   klass->get_source_by_ssrc =
       GST_DEBUG_FUNCPTR (rtp_session_get_source_by_ssrc);
   klass->send_rtcp = GST_DEBUG_FUNCPTR (rtp_session_send_rtcp);
@@ -684,6 +702,15 @@ rtp_session_get_property (GObject * object, guint prop_id,
     case PROP_PROBATION:
       g_value_set_uint (value, sess->probation);
       break;
+    case PROP_NACKS_DROPPED:
+      g_value_set_uint (value, sess->stats.nacks_dropped);
+      break;
+    case PROP_NACKS_SENT:
+      g_value_set_uint (value, sess->stats.nacks_sent);
+      break;
+    case PROP_NACKS_RECEIVED:
+      g_value_set_uint (value, sess->stats.nacks_received);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -2223,6 +2250,8 @@ rtp_session_process_nack (RTPSession * sess, guint32 sender_ssrc,
 
     GST_DEBUG ("NACK #%u, blp %04x", seqnum, blp);
 
+    sess->stats.nacks_received++;
+
     RTP_SESSION_UNLOCK (sess);
     sess->callbacks.notify_nack (sess, media_ssrc, seqnum, blp,
         sess->notify_nack_user_data);
@@ -2770,6 +2799,7 @@ typedef struct
   gboolean is_early;
   gboolean may_suppress;
   GQueue output;
+  guint nacked_seqnums;
 } ReportData;
 
 static void
@@ -2999,6 +3029,7 @@ session_nack (const gchar * key, RTPSource * source, ReportData * data)
   for (i = 0; i < n_nacks; i++) {
     GST_WRITE_UINT32_BE (fci_data, nacks[i]);
     fci_data += 4;
+    data->nacked_seqnums++;
   }
 
   rtp_source_clear_nacks (source);
@@ -3416,6 +3447,7 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
   data.running_time = running_time;
   data.num_to_report = 0;
   data.may_suppress = FALSE;
+  data.nacked_seqnums = 0;
   g_queue_init (&data.output);
 
   RTP_SESSION_LOCK (sess);
@@ -3491,10 +3523,12 @@ done:
       result =
           sess->callbacks.send_rtcp (sess, source, buffer, output->is_bye,
           sess->send_rtcp_user_data);
+      sess->stats.nacks_sent += data.nacked_seqnums;
     } else {
       GST_DEBUG ("freeing packet callback: %p"
           " do_not_suppress: %d may_suppress: %d",
           sess->callbacks.send_rtcp, do_not_suppress, data.may_suppress);
+      sess->stats.nacks_dropped += data.nacked_seqnums;
       gst_buffer_unref (buffer);
     }
     g_object_unref (source);
diff --git a/gst/rtpmanager/rtpstats.c b/gst/rtpmanager/rtpstats.c
index a73e1c6..4da164c 100644
--- a/gst/rtpmanager/rtpstats.c
+++ b/gst/rtpmanager/rtpstats.c
@@ -31,6 +31,9 @@ rtp_stats_init_defaults (RTPSessionStats * stats)
   rtp_stats_set_bandwidths (stats, -1, -1, -1, -1);
   stats->min_interval = RTP_STATS_MIN_INTERVAL;
   stats->bye_timeout = RTP_STATS_BYE_TIMEOUT;
+  stats->nacks_dropped = 0;
+  stats->nacks_sent = 0;
+  stats->nacks_received = 0;
 }
 
 /**
diff --git a/gst/rtpmanager/rtpstats.h b/gst/rtpmanager/rtpstats.h
index cb9e06c..1f09ffa 100644
--- a/gst/rtpmanager/rtpstats.h
+++ b/gst/rtpmanager/rtpstats.h
@@ -205,6 +205,9 @@ typedef struct {
   guint         active_sources;
   guint         avg_rtcp_packet_size;
   guint         bye_members;
+  guint         nacks_dropped;
+  guint         nacks_sent;
+  guint         nacks_received;
 } RTPSessionStats;
 
 void           rtp_stats_init_defaults              (RTPSessionStats *stats);
