PROP_USE_PIPELINE_CLOCK,
PROP_RTCP_MIN_INTERVAL,
PROP_PROBATION,
+ PROP_STATS,
PROP_LAST
};
GstClockTime send_latency;
gboolean use_pipeline_clock;
+
+ guint rtx_count;
};
/* callbacks to handle actions from the session manager */
static void gst_rtp_session_clear_pt_map (GstRtpSession * rtpsession);
+static GstStructure *gst_rtp_session_create_stats (GstRtpSession * rtpsession);
+
static guint gst_rtp_session_signals[LAST_SIGNAL] = { 0 };
static void
0, G_MAXUINT, DEFAULT_PROBATION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstRtpSession::stats:
+ *
+ * Various session statistics. This property returns a GstStructure
+ * with name application/x-rtp-session-stats with the following fields:
+ *
+ * "rtx-count" G_TYPE_UINT The number of retransmission events
+ * received from downstream (in receiver mode)
+ * "rtx-drop-count" G_TYPE_UINT The number of retransmission events
+ * dropped (due to bandwidth constraints)
+ * "sent-nack-count" G_TYPE_UINT Number of NACKs sent
+ * "recv-nack-count" G_TYPE_UINT Number of NACKs received
+ *
+ * Since: 1.3.1
+ */
+ g_object_class_install_property (gobject_class, PROP_STATS,
+ g_param_spec_boxed ("stats", "Statistics",
+ "Various statistics", GST_TYPE_STRUCTURE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_rtp_session_change_state);
gstelement_class->request_new_pad =
gst_segment_init (&rtpsession->send_rtp_seg, GST_FORMAT_UNDEFINED);
rtpsession->priv->thread_stopped = TRUE;
+
+ rtpsession->priv->rtx_count = 0;
}
static void
case PROP_PROBATION:
g_object_get_property (G_OBJECT (priv->session), "probation", value);
break;
+ case PROP_STATS:
+ g_value_take_boxed (value, gst_rtp_session_create_stats (rtpsession));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
+static GstStructure *
+gst_rtp_session_create_stats (GstRtpSession * rtpsession)
+{
+ GstStructure *s;
+
+ g_object_get (rtpsession->priv->session, "stats", &s, NULL);
+ gst_structure_set (s, "rtx-count", G_TYPE_UINT, rtpsession->priv->rtx_count,
+ NULL);
+
+ return s;
+}
+
static void
get_current_times (GstRtpSession * rtpsession, GstClockTime * running_time,
guint64 * ntpnstime)
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))
PROP_RTCP_FEEDBACK_RETENTION_WINDOW,
PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
PROP_PROBATION,
+ PROP_STATS,
PROP_LAST
};
0, G_MAXUINT, DEFAULT_PROBATION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * RTPSession::stats:
+ *
+ * Various session statistics. This property returns a GstStructure
+ * with name application/x-rtp-session-stats with the following fields:
+ *
+ * "rtx-drop-count" G_TYPE_UINT The number of retransmission events
+ * dropped (due to bandwidth constraints)
+ * "sent-nack-count" G_TYPE_UINT Number of NACKs sent
+ * "recv-nack-count" G_TYPE_UINT Number of NACKs received
+ *
+ * Since: 1.3.1
+ */
+ g_object_class_install_property (gobject_class, PROP_STATS,
+ g_param_spec_boxed ("stats", "Statistics",
+ "Various statistics", GST_TYPE_STRUCTURE,
+ 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);
return res;
}
+static GstStructure *
+rtp_session_create_stats (RTPSession * sess)
+{
+ GstStructure *s;
+
+ s = gst_structure_new ("application/x-rtp-session-stats",
+ "rtx-drop-count", G_TYPE_UINT, sess->stats.nacks_dropped,
+ "sent-nack-count", G_TYPE_UINT, sess->stats.nacks_sent,
+ "recv-nack-count", G_TYPE_UINT, sess->stats.nacks_received, NULL);
+
+ return s;
+}
+
static void
rtp_session_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
case PROP_PROBATION:
g_value_set_uint (value, sess->probation);
break;
+ case PROP_STATS:
+ g_value_take_boxed (value, rtp_session_create_stats (sess));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
GST_BUFFER_TIMESTAMP (fci_buffer) = pinfo->running_time;
}
+ sess->stats.nacks_received++;
+
RTP_SESSION_UNLOCK (sess);
g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_FEEDBACK_RTCP], 0,
type, fbtype, sender_ssrc, media_ssrc, fci_buffer);
gboolean is_early;
gboolean may_suppress;
GQueue output;
+ guint nacked_seqnums;
} ReportData;
static void
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);
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);
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);