Add a feature to display RTP stats 93/46293/1
authorHyunjun Ko <zzoon.ko@samsung.com>
Wed, 29 Jul 2015 12:02:05 +0000 (21:02 +0900)
committerSangkyu Park <sk1122.park@samsung.com>
Wed, 19 Aug 2015 05:08:08 +0000 (14:08 +0900)
Change-Id: Iad245dafb0d22653a352ccff02158000d698c1b7

gst/rtsp-server/rtsp-client-wfd.c
gst/rtsp-server/rtsp-stream.c
gst/rtsp-server/rtsp-stream.h

index 84a84d0..8737834 100644 (file)
 #define GST_RTSP_WFD_CLIENT_GET_PRIVATE(obj)  \
    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_WFD_CLIENT, GstRTSPWFDClientPrivate))
 
-/* locking order:
- * send_lock, lock, tunnels_lock
- */
+typedef struct _GstRTSPClientRTPStats GstRTSPClientRTPStats;
+
+struct _GstRTSPClientRTPStats {
+  GstRTSPStream *stream;
+  guint64 last_sent_bytes;
+  guint64 sent_bytes;
+  guint last_seqnum;
+  guint seqnum;
+
+  /* Info in RR (Receiver Report) */
+  guint8 fraction_lost;
+  guint32 cumulative_lost_num;
+  guint16 max_seqnum;
+  guint32 arrival_jitter;
+  guint32 lsr;
+  guint32 dlsr;
+  guint32 rtt;
+  guint resent_packets;
+};
 
 struct _GstRTSPWFDClientPrivate
 {
@@ -116,6 +132,12 @@ struct _GstRTSPWFDClientPrivate
 
   gboolean keep_alive_flag;
   GMutex keep_alive_lock;
+
+  /* RTP statistics */
+  GstRTSPClientRTPStats stats;
+  GMutex stats_lock;
+  guint stats_timer_id;
+  gboolean rtcp_stats_enabled;
 };
 
 #define DEFAULT_WFD_TIMEOUT 60
@@ -154,9 +176,11 @@ static void wfd_options_request_done (GstRTSPWFDClient * client);
 static void wfd_get_param_request_done (GstRTSPWFDClient * client);
 static void handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx);
 static void handle_wfd_play (GstRTSPClient * client, GstRTSPContext * ctx);
-static void wfd_set_keep_alive_condition(GstRTSPClient * client);
+static void wfd_set_keep_alive_condition(GstRTSPWFDClient * client);
 static gboolean wfd_ckeck_keep_alive_response (gpointer userdata);
 static gboolean keep_alive_condition(gpointer userdata);
+static gboolean wfd_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
+    GstRTSPStream * stream, GstRTSPContext * ctx);
 
 GstRTSPResult prepare_trigger_request (GstRTSPWFDClient * client,
     GstRTSPMessage * request, GstWFDTriggerType trigger_type, gchar * url);
@@ -195,7 +219,6 @@ gst_rtsp_wfd_client_class_init (GstRTSPWFDClientClass * klass)
   gobject_class->finalize = gst_rtsp_wfd_client_finalize;
 
   //klass->create_sdp = create_sdp;
-  //klass->configure_client_media = default_configure_client_media;
   //klass->configure_client_transport = default_configure_client_transport;
   //klass->params_set = default_params_set;
   //klass->params_get = default_params_get;
@@ -204,6 +227,7 @@ gst_rtsp_wfd_client_class_init (GstRTSPWFDClientClass * klass)
   rtsp_client_class->handle_set_param_request = handle_wfd_set_param_request;
   rtsp_client_class->handle_get_param_request = handle_wfd_get_param_request;
   rtsp_client_class->make_path_from_uri = wfd_make_path_from_uri;
+  rtsp_client_class->configure_client_media = wfd_configure_client_media;
 
   rtsp_client_class->handle_response = handle_wfd_response;
   rtsp_client_class->play_request = handle_wfd_play;
@@ -240,9 +264,16 @@ gst_rtsp_wfd_client_init (GstRTSPWFDClient * client)
   priv->video_resolution_supported = GST_WFD_CEA_640x480P60;
   priv->audio_codec = GST_WFD_AUDIO_AAC;
   priv->keep_alive_flag = FALSE;
+
   g_mutex_init (&priv->keep_alive_lock);
+  g_mutex_init (&priv->stats_lock);
 
   priv->host_address = NULL;
+
+  priv->stats_timer_id = -1;
+  priv->rtcp_stats_enabled = FALSE;
+  memset (&priv->stats, 0x00, sizeof (GstRTSPClientRTPStats));
+
   GST_INFO_OBJECT (client, "Client is initialized");
 }
 
@@ -260,7 +291,12 @@ gst_rtsp_wfd_client_finalize (GObject * obj)
 
   if (priv->host_address)
     g_free (priv->host_address);
+
+  if (priv->stats_timer_id > 0)
+    g_source_remove(priv->stats_timer_id);
+
   g_mutex_clear (&priv->keep_alive_lock);
+  g_mutex_clear (&priv->stats_lock);
   G_OBJECT_CLASS (gst_rtsp_wfd_client_parent_class)->finalize (obj);
 }
 
@@ -319,6 +355,94 @@ gst_rtsp_wfd_client_start_wfd (GstRTSPWFDClient * client)
   return;
 }
 
+static gboolean
+wfd_display_rtp_stats(gpointer userdata)
+{
+  guint16 seqnum = 0;
+  guint64 bytes = 0;
+
+  GstRTSPWFDClient *client = NULL;
+  GstRTSPWFDClientPrivate *priv = NULL;
+
+  client = (GstRTSPWFDClient *) userdata;
+  priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  if (!priv) {
+    GST_ERROR("No priv");
+    return FALSE;
+  }
+
+  g_mutex_lock(&priv->stats_lock);
+
+  seqnum = gst_rtsp_stream_get_current_seqnum (priv->stats.stream);
+  bytes = gst_rtsp_stream_get_udp_sent_bytes (priv->stats.stream);
+
+  GST_INFO ("----------------------------------------------------\n");
+  GST_INFO ("Sent RTP packets : %d", seqnum - priv->stats.last_seqnum);
+  GST_INFO ("Sent Bytes of RTP packets : %lld bytes", bytes - priv->stats.last_sent_bytes);
+
+  priv->stats.last_seqnum = seqnum;
+  priv->stats.last_sent_bytes = bytes;
+
+  if (priv->rtcp_stats_enabled) {
+    GST_INFO ("Fraction Lost: %d", priv->stats.fraction_lost);
+    GST_INFO ("Cumulative number of packets lost: %d", priv->stats.cumulative_lost_num);
+    GST_INFO ("Extended highest sequence number received: %d", priv->stats.max_seqnum);
+    GST_INFO ("Interarrival Jitter: %d", priv->stats.arrival_jitter);
+    GST_INFO ("Round trip time : %d", priv->stats.rtt);
+  }
+
+  GST_INFO ("----------------------------------------------------\n");
+
+  g_mutex_unlock(&priv->stats_lock);
+
+  return TRUE;
+}
+
+static void
+on_rtcp_stats (GstRTSPStream *stream, GstStructure *stats, GstRTSPClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  guint fraction_lost, exthighestseq, jitter, lsr, dlsr, rtt;
+  gint packetslost;
+
+  if (!priv) return;
+
+  g_mutex_lock(&priv->stats_lock);
+
+  gst_structure_get_uint (stats, "rb-fractionlost", &fraction_lost);
+  gst_structure_get_int (stats, "rb-packetslost", &packetslost);
+  gst_structure_get_uint (stats, "rb-exthighestseq", &exthighestseq);
+  gst_structure_get_uint (stats, "rb-jitter", &jitter);
+  gst_structure_get_uint (stats, "rb-lsr", &lsr);
+  gst_structure_get_uint (stats, "rb-dlsr", &dlsr);
+  gst_structure_get_uint (stats, "rb-round-trip", &rtt);
+
+  if (!priv->rtcp_stats_enabled)
+    priv->rtcp_stats_enabled = TRUE;
+
+  priv->stats.stream = stream;
+  priv->stats.fraction_lost = (guint8)fraction_lost;
+  priv->stats.cumulative_lost_num += (guint32)fraction_lost;
+  priv->stats.max_seqnum = (guint16)exthighestseq;
+  priv->stats.arrival_jitter = (guint32)jitter;
+  priv->stats.lsr = (guint32)lsr;
+  priv->stats.dlsr = (guint32)dlsr;
+  priv->stats.rtt = (guint32)rtt;
+
+  g_mutex_unlock(&priv->stats_lock);
+}
+
+static gboolean
+wfd_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
+    GstRTSPStream * stream, GstRTSPContext * ctx)
+{
+  if (stream)
+    g_signal_connect (stream, "rtcp-statistics", (GCallback) on_rtcp_stats, client);
+
+  return GST_RTSP_CLIENT_CLASS (gst_rtsp_wfd_client_parent_class)->configure_client_media (client, media, stream, ctx);
+}
 static void
 wfd_options_request_done (GstRTSPWFDClient * client)
 {
@@ -791,7 +915,14 @@ wfd_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri)
 static void
 handle_wfd_play (GstRTSPClient * client, GstRTSPContext * ctx)
 {
-  wfd_set_keep_alive_condition(client);
+  GstRTSPWFDClient *_client = GST_RTSP_WFD_CLIENT (client);
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_if_fail (priv != NULL);
+
+  wfd_set_keep_alive_condition(_client);
+  
+  priv->stats_timer_id = g_timeout_add (2000, wfd_display_rtp_stats, _client);
 }
 
 static void
@@ -2301,12 +2432,9 @@ keep_alive_condition(gpointer userdata)
 }
 
 static
-void wfd_set_keep_alive_condition(GstRTSPClient * client)
+void wfd_set_keep_alive_condition(GstRTSPWFDClient * client)
 {
-  GstRTSPWFDClient *wfd_client;
-  wfd_client = GST_RTSP_WFD_CLIENT(client);
-
-  g_timeout_add((DEFAULT_WFD_TIMEOUT-5)*1000, keep_alive_condition, wfd_client);
+  g_timeout_add((DEFAULT_WFD_TIMEOUT-5)*1000, keep_alive_condition, client);
 }
 
 void
@@ -2612,3 +2740,4 @@ void gst_rtsp_wfd_client_set_keep_alive_flag(GstRTSPWFDClient *client, gboolean
     priv->keep_alive_flag = flag;
   g_mutex_unlock(&priv->keep_alive_lock);
 }
+
index 862404b..8e1b216 100644 (file)
@@ -153,6 +153,7 @@ enum
 {
   SIGNAL_NEW_RTP_ENCODER,
   SIGNAL_NEW_RTCP_ENCODER,
+  SIGNAL_RTCP_STATS,
   SIGNAL_LAST
 };
 
@@ -210,6 +211,11 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass)
       G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
       G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
 
+  gst_rtsp_stream_signals[SIGNAL_RTCP_STATS] =
+      g_signal_new ("rtcp-statistics", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
+      G_TYPE_NONE, 1, GST_TYPE_STRUCTURE);
+
   GST_DEBUG_CATEGORY_INIT (rtsp_stream_debug, "rtspstream", 0, "GstRTSPStream");
 
   ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
@@ -1395,6 +1401,8 @@ check_transport (GObject * source, GstRTSPStream * stream)
 
       dump_structure (stats);
 
+      g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_RTCP_STATS], 0, stats);
+
       rtcp_from = gst_structure_get_string (stats, "rtcp-from");
       if ((trans = find_transport (stream, rtcp_from))) {
         GST_INFO ("%p: found transport %p for source  %p", stream, trans,
@@ -1439,16 +1447,18 @@ on_ssrc_active (GObject * session, GObject * source, GstRTSPStream * stream)
     GST_INFO ("%p: source %p in transport %p is active", stream, source, trans);
     gst_rtsp_stream_transport_keep_alive (trans);
   }
-#ifdef DUMP_STATS
   {
     GstStructure *stats;
     g_object_get (source, "stats", &stats, NULL);
     if (stats) {
+      g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_RTCP_STATS], 0, stats);
+
+#ifdef DUMP_STATS
       dump_structure (stats);
+#endif
       gst_structure_free (stats);
     }
   }
-#endif
 }
 
 static void
@@ -2519,6 +2529,21 @@ gst_rtsp_stream_get_current_seqnum (GstRTSPStream * stream)
   return seqnum;
 }
 
+guint64
+gst_rtsp_stream_get_udp_sent_bytes (GstRTSPStream *stream)
+{
+  GstRTSPStreamPrivate *priv;
+  guint64 bytes = 0;
+
+  g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0);
+
+  priv = stream->priv;
+
+  g_object_get (G_OBJECT (priv->udpsink[0]), "bytes-to-serve", &bytes, NULL);
+
+  return bytes;
+}
+
 /**
  * gst_rtsp_stream_transport_filter:
  * @stream: a #GstRTSPStream
index 135689e..dddbbf4 100644 (file)
@@ -153,8 +153,9 @@ gboolean          gst_rtsp_stream_query_position   (GstRTSPStream * stream,
 gboolean          gst_rtsp_stream_query_stop       (GstRTSPStream * stream,
                                                     gint64 * stop);
 
-void              gst_rtsp_stream_set_seqnum_offset          (GstRTSPStream *stream, guint16 seqnum);
-guint16           gst_rtsp_stream_get_current_seqnum          (GstRTSPStream *stream);
+void              gst_rtsp_stream_set_seqnum_offset   (GstRTSPStream *stream, guint16 seqnum);
+guint16           gst_rtsp_stream_get_current_seqnum  (GstRTSPStream *stream);
+guint64           gst_rtsp_stream_get_udp_sent_bytes  (GstRTSPStream *stream);
 
 /**
  * GstRTSPStreamTransportFilterFunc: