}
#define CLOCK_RATE_VALUE_TO_SECONDS(v,r) ((double) v / (double) clock_rate)
+#define FIXED_16_16_TO_DOUBLE(v) ((double) ((v & 0xffff0000) >> 16) + ((v & 0xffff) / 65536.0))
+#define FIXED_32_32_TO_DOUBLE(v) ((double) ((v & G_GUINT64_CONSTANT (0xffffffff00000000)) >> 32) + ((v & G_GUINT64_CONSTANT (0xffffffff)) / 4294967296.0))
/* https://www.w3.org/TR/webrtc-stats/#inboundrtpstats-dict*
https://www.w3.org/TR/webrtc-stats/#outboundrtpstats-dict* */
const GstStructure * source_stats, const gchar * codec_id,
const gchar * transport_id, GstStructure * s)
{
- GstStructure *in, *out, *r_in, *r_out;
- gchar *in_id, *out_id, *r_in_id, *r_out_id;
guint ssrc, fir, pli, nack, jitter;
int lost, clock_rate;
guint64 packets, bytes;
- gboolean have_rb = FALSE, sent_rb = FALSE;
+ gboolean internal;
double ts;
gst_structure_get_double (s, "timestamp", &ts);
- gst_structure_get_uint (source_stats, "ssrc", &ssrc);
- gst_structure_get (source_stats, "have-rb", G_TYPE_BOOLEAN, &have_rb,
- "sent_rb", G_TYPE_BOOLEAN, &sent_rb, "clock-rate", G_TYPE_INT,
- &clock_rate, NULL);
-
- in_id = g_strdup_printf ("rtp-inbound-stream-stats_%u", ssrc);
- out_id = g_strdup_printf ("rtp-outbound-stream-stats_%u", ssrc);
- r_in_id = g_strdup_printf ("rtp-remote-inbound-stream-stats_%u", ssrc);
- r_out_id = g_strdup_printf ("rtp-remote-outbound-stream-stats_%u", ssrc);
-
- in = gst_structure_new_empty (in_id);
- _set_base_stats (in, GST_WEBRTC_STATS_INBOUND_RTP, ts, in_id);
-
- /* RTCStreamStats */
- gst_structure_set (in, "ssrc", G_TYPE_UINT, ssrc, NULL);
- gst_structure_set (in, "codec-id", G_TYPE_STRING, codec_id, NULL);
- gst_structure_set (in, "transport-id", G_TYPE_STRING, transport_id, NULL);
- if (gst_structure_get_uint (source_stats, "recv-fir-count", &fir))
- gst_structure_set (in, "fir-count", G_TYPE_UINT, fir, NULL);
- if (gst_structure_get_uint (source_stats, "recv-pli-count", &pli))
- gst_structure_set (in, "pli-count", G_TYPE_UINT, pli, NULL);
- if (gst_structure_get_uint (source_stats, "recv-nack-count", &nack))
- gst_structure_set (in, "nack-count", G_TYPE_UINT, nack, NULL);
- /* XXX: mediaType, trackId, sliCount, qpSum */
-
- /* RTCReceivedRTPStreamStats */
- if (gst_structure_get_uint64 (source_stats, "packets-received", &packets))
- gst_structure_set (in, "packets-received", G_TYPE_UINT64, packets, NULL);
- if (gst_structure_get_uint64 (source_stats, "octets-received", &bytes))
- gst_structure_set (in, "bytes-received", G_TYPE_UINT64, bytes, NULL);
- if (gst_structure_get_int (source_stats, "packets-lost", &lost))
- gst_structure_set (in, "packets-lost", G_TYPE_INT, lost, NULL);
- if (gst_structure_get_uint (source_stats, "jitter", &jitter))
- gst_structure_set (in, "jitter", G_TYPE_DOUBLE,
- CLOCK_RATE_VALUE_TO_SECONDS (jitter, clock_rate), NULL);
-/*
- RTCReceivedRTPStreamStats
+ gst_structure_get (source_stats, "ssrc", G_TYPE_UINT, &ssrc, "clock-rate",
+ G_TYPE_INT, &clock_rate, "internal", G_TYPE_BOOLEAN, &internal, NULL);
+
+ if (internal) {
+ GstStructure *r_in, *out;
+ gchar *out_id, *r_in_id;
+
+ out_id = g_strdup_printf ("rtp-outbound-stream-stats_%u", ssrc);
+ r_in_id = g_strdup_printf ("rtp-remote-inbound-stream-stats_%u", ssrc);
+
+ r_in = gst_structure_new_empty (r_in_id);
+ _set_base_stats (r_in, GST_WEBRTC_STATS_REMOTE_INBOUND_RTP, ts, r_in_id);
+
+ /* RTCStreamStats */
+ gst_structure_set (r_in, "local-id", G_TYPE_STRING, out_id, NULL);
+ gst_structure_set (r_in, "ssrc", G_TYPE_UINT, ssrc, NULL);
+ gst_structure_set (r_in, "codec-id", G_TYPE_STRING, codec_id, NULL);
+ gst_structure_set (r_in, "transport-id", G_TYPE_STRING, transport_id, NULL);
+ /* XXX: mediaType, trackId, sliCount, qpSum */
+
+ if (gst_structure_get_uint64 (source_stats, "packets-received", &packets))
+ gst_structure_set (r_in, "packets-received", G_TYPE_UINT64, packets,
+ NULL);
+ if (gst_structure_get_int (source_stats, "packets-lost", &lost))
+ gst_structure_set (r_in, "packets-lost", G_TYPE_INT, lost, NULL);
+ if (gst_structure_get_uint (source_stats, "jitter", &jitter))
+ gst_structure_set (r_in, "jitter", G_TYPE_DOUBLE,
+ CLOCK_RATE_VALUE_TO_SECONDS (jitter, clock_rate), NULL);
+
+/* XXX: RTCReceivedRTPStreamStats
double fractionLost;
unsigned long packetsDiscarded;
unsigned long packetsFailedDecryption;
double gapDiscardRate;
*/
- /* RTCInboundRTPStreamStats */
- gst_structure_set (in, "remote-id", G_TYPE_STRING, r_out_id, NULL);
- /* XXX: framesDecoded, lastPacketReceivedTimestamp */
+ /* RTCRemoteInboundRTPStreamStats */
+ /* XXX: framesDecoded, lastPacketReceivedTimestamp */
- r_in = gst_structure_new_empty (r_in_id);
- _set_base_stats (r_in, GST_WEBRTC_STATS_REMOTE_INBOUND_RTP, ts, r_in_id);
+ out = gst_structure_new_empty (out_id);
+ _set_base_stats (out, GST_WEBRTC_STATS_OUTBOUND_RTP, ts, out_id);
- /* RTCStreamStats */
- gst_structure_set (r_in, "ssrc", G_TYPE_UINT, ssrc, NULL);
- gst_structure_set (r_in, "codec-id", G_TYPE_STRING, codec_id, NULL);
- gst_structure_set (r_in, "transport-id", G_TYPE_STRING, transport_id, NULL);
- /* XXX: mediaType, trackId, sliCount, qpSum */
+ /* RTCStreamStats */
+ gst_structure_set (out, "ssrc", G_TYPE_UINT, ssrc, NULL);
+ gst_structure_set (out, "codec-id", G_TYPE_STRING, codec_id, NULL);
+ gst_structure_set (out, "transport-id", G_TYPE_STRING, transport_id, NULL);
+ if (gst_structure_get_uint (source_stats, "sent-fir-count", &fir))
+ gst_structure_set (out, "fir-count", G_TYPE_UINT, fir, NULL);
+ if (gst_structure_get_uint (source_stats, "sent-pli-count", &pli))
+ gst_structure_set (out, "pli-count", G_TYPE_UINT, pli, NULL);
+ if (gst_structure_get_uint (source_stats, "sent-nack-count", &nack))
+ gst_structure_set (out, "nack-count", G_TYPE_UINT, nack, NULL);
+ /* XXX: mediaType, trackId, sliCount, qpSum */
- /* RTCReceivedRTPStreamStats */
- if (sent_rb) {
- if (gst_structure_get_uint (source_stats, "sent-rb-jitter", &jitter))
- gst_structure_set (r_in, "jitter", G_TYPE_DOUBLE,
- CLOCK_RATE_VALUE_TO_SECONDS (jitter, clock_rate), NULL);
- if (gst_structure_get_int (source_stats, "sent-rb-packetslost", &lost))
- gst_structure_set (r_in, "packets-lost", G_TYPE_INT, lost, NULL);
- /* packetsReceived, bytesReceived */
+/* RTCSentRTPStreamStats */
+ if (gst_structure_get_uint64 (source_stats, "octets-sent", &bytes))
+ gst_structure_set (out, "bytes-sent", G_TYPE_UINT64, bytes, NULL);
+ if (gst_structure_get_uint64 (source_stats, "packets-sent", &packets))
+ gst_structure_set (out, "packets-sent", G_TYPE_UINT64, packets, NULL);
+/* XXX:
+ unsigned long packetsDiscardedOnSend;
+ unsigned long long bytesDiscardedOnSend;
+*/
+
+ /* RTCOutboundRTPStreamStats */
+ gst_structure_set (out, "remote-id", G_TYPE_STRING, r_in_id, NULL);
+/* XXX:
+ DOMHighResTimeStamp lastPacketSentTimestamp;
+ double targetBitrate;
+ unsigned long framesEncoded;
+ double totalEncodeTime;
+ double averageRTCPInterval;
+*/
+ gst_structure_set (s, out_id, GST_TYPE_STRUCTURE, out, NULL);
+ gst_structure_set (s, r_in_id, GST_TYPE_STRUCTURE, r_in, NULL);
+
+ gst_structure_free (out);
+ gst_structure_free (r_in);
+
+ g_free (out_id);
+ g_free (r_in_id);
} else {
- /* default values */
- gst_structure_set (r_in, "jitter", G_TYPE_DOUBLE, 0.0, "packets-lost",
- G_TYPE_INT, 0, NULL);
- }
-/* XXX: RTCReceivedRTPStreamStats
+ GstStructure *in, *r_out;
+ gchar *r_out_id, *in_id;
+ gboolean have_rb = FALSE, have_sr = FALSE;
+
+ gst_structure_get (source_stats, "have-rb", G_TYPE_BOOLEAN, &have_rb,
+ "have-sr", G_TYPE_BOOLEAN, &have_sr, NULL);
+
+ in_id = g_strdup_printf ("rtp-inbound-stream-stats_%u", ssrc);
+ r_out_id = g_strdup_printf ("rtp-remote-outbound-stream-stats_%u", ssrc);
+
+ in = gst_structure_new_empty (in_id);
+ _set_base_stats (in, GST_WEBRTC_STATS_INBOUND_RTP, ts, in_id);
+
+ /* RTCStreamStats */
+ gst_structure_set (in, "ssrc", G_TYPE_UINT, ssrc, NULL);
+ gst_structure_set (in, "codec-id", G_TYPE_STRING, codec_id, NULL);
+ gst_structure_set (in, "transport-id", G_TYPE_STRING, transport_id, NULL);
+ if (gst_structure_get_uint (source_stats, "recv-fir-count", &fir))
+ gst_structure_set (in, "fir-count", G_TYPE_UINT, fir, NULL);
+ if (gst_structure_get_uint (source_stats, "recv-pli-count", &pli))
+ gst_structure_set (in, "pli-count", G_TYPE_UINT, pli, NULL);
+ if (gst_structure_get_uint (source_stats, "recv-nack-count", &nack))
+ gst_structure_set (in, "nack-count", G_TYPE_UINT, nack, NULL);
+ /* XXX: mediaType, trackId, sliCount, qpSum */
+
+ /* RTCReceivedRTPStreamStats */
+ if (gst_structure_get_uint64 (source_stats, "packets-received", &packets))
+ gst_structure_set (in, "packets-received", G_TYPE_UINT64, packets, NULL);
+ if (gst_structure_get_uint64 (source_stats, "octets-received", &bytes))
+ gst_structure_set (in, "bytes-received", G_TYPE_UINT64, bytes, NULL);
+ if (gst_structure_get_int (source_stats, "packets-lost", &lost))
+ gst_structure_set (in, "packets-lost", G_TYPE_INT, lost, NULL);
+ if (gst_structure_get_uint (source_stats, "jitter", &jitter))
+ gst_structure_set (in, "jitter", G_TYPE_DOUBLE,
+ CLOCK_RATE_VALUE_TO_SECONDS (jitter, clock_rate), NULL);
+/*
+ RTCReceivedRTPStreamStats
double fractionLost;
unsigned long packetsDiscarded;
unsigned long packetsFailedDecryption;
double gapDiscardRate;
*/
- /* RTCRemoteInboundRTPStreamStats */
- gst_structure_set (r_in, "local-id", G_TYPE_STRING, out_id, NULL);
- if (have_rb) {
- guint32 rtt;
- if (gst_structure_get_uint (source_stats, "rb-round-trip", &rtt)) {
- /* 16.16 fixed point to double */
- double val =
- (double) ((rtt & 0xffff0000) >> 16) + ((rtt & 0xffff) / 65536.0);
- gst_structure_set (r_in, "round-trip-time", G_TYPE_DOUBLE, val, NULL);
+ /* RTCInboundRTPStreamStats */
+ gst_structure_set (in, "remote-id", G_TYPE_STRING, r_out_id, NULL);
+ /* XXX: framesDecoded, lastPacketReceivedTimestamp */
+
+ r_out = gst_structure_new_empty (r_out_id);
+ _set_base_stats (r_out, GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP, ts, r_out_id);
+ /* RTCStreamStats */
+ gst_structure_set (r_out, "ssrc", G_TYPE_UINT, ssrc, NULL);
+ gst_structure_set (r_out, "codec-id", G_TYPE_STRING, codec_id, NULL);
+ gst_structure_set (r_out, "transport-id", G_TYPE_STRING, transport_id,
+ NULL);
+ if (have_rb) {
+ guint32 rtt;
+ if (gst_structure_get_uint (source_stats, "rb-round-trip", &rtt)) {
+ /* 16.16 fixed point to double */
+ double val = FIXED_16_16_TO_DOUBLE (rtt);
+ gst_structure_set (r_out, "round-trip-time", G_TYPE_DOUBLE, val, NULL);
+ }
+ } else {
+ /* default values */
+ gst_structure_set (r_out, "round-trip-time", G_TYPE_DOUBLE, 0.0, NULL);
}
- } else {
- /* default values */
- gst_structure_set (r_in, "round-trip-time", G_TYPE_DOUBLE, 0.0, NULL);
- }
- /* XXX: framesDecoded, lastPacketReceivedTimestamp */
-
- out = gst_structure_new_empty (out_id);
- _set_base_stats (out, GST_WEBRTC_STATS_OUTBOUND_RTP, ts, out_id);
-
- /* RTCStreamStats */
- gst_structure_set (out, "ssrc", G_TYPE_UINT, ssrc, NULL);
- gst_structure_set (out, "codec-id", G_TYPE_STRING, codec_id, NULL);
- gst_structure_set (out, "transport-id", G_TYPE_STRING, transport_id, NULL);
- if (gst_structure_get_uint (source_stats, "sent-fir-count", &fir))
- gst_structure_set (out, "fir-count", G_TYPE_UINT, fir, NULL);
- if (gst_structure_get_uint (source_stats, "sent-pli-count", &pli))
- gst_structure_set (out, "pli-count", G_TYPE_UINT, pli, NULL);
- if (gst_structure_get_uint (source_stats, "sent-nack-count", &nack))
- gst_structure_set (out, "nack-count", G_TYPE_UINT, nack, NULL);
- /* XXX: mediaType, trackId, sliCount, qpSum */
+ /* XXX: mediaType, trackId, sliCount, qpSum */
/* RTCSentRTPStreamStats */
- if (gst_structure_get_uint64 (source_stats, "octets-sent", &bytes))
- gst_structure_set (out, "bytes-sent", G_TYPE_UINT64, bytes, NULL);
- if (gst_structure_get_uint64 (source_stats, "packets-sent", &packets))
- gst_structure_set (out, "packets-sent", G_TYPE_UINT64, packets, NULL);
+ if (have_sr) {
+ if (gst_structure_get_uint64 (source_stats, "sr-octet-count", &bytes))
+ gst_structure_set (r_out, "bytes-sent", G_TYPE_UINT64, bytes, NULL);
+ if (gst_structure_get_uint64 (source_stats, "sr-packet-count", &packets))
+ gst_structure_set (r_out, "packets-sent", G_TYPE_UINT64, packets, NULL);
+ }
/* XXX:
unsigned long packetsDiscardedOnSend;
unsigned long long bytesDiscardedOnSend;
*/
- /* RTCOutboundRTPStreamStats */
- gst_structure_set (out, "remote-id", G_TYPE_STRING, r_in_id, NULL);
-/* XXX:
- DOMHighResTimeStamp lastPacketSentTimestamp;
- double targetBitrate;
- unsigned long framesEncoded;
- double totalEncodeTime;
- double averageRTCPInterval;
-*/
-
- r_out = gst_structure_new_empty (r_out_id);
- _set_base_stats (r_out, GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP, ts, r_out_id);
- /* RTCStreamStats */
- gst_structure_set (r_out, "ssrc", G_TYPE_UINT, ssrc, NULL);
- gst_structure_set (r_out, "codec-id", G_TYPE_STRING, codec_id, NULL);
- gst_structure_set (r_out, "transport-id", G_TYPE_STRING, transport_id, NULL);
- /* XXX: mediaType, trackId, sliCount, qpSum */
-
-/* RTCSentRTPStreamStats */
-/* if (gst_structure_get_uint64 (source_stats, "octets-sent", &bytes))
- gst_structure_set (r_out, "bytes-sent", G_TYPE_UINT64, bytes, NULL);
- if (gst_structure_get_uint64 (source_stats, "packets-sent", &packets))
- gst_structure_set (r_out, "packets-sent", G_TYPE_UINT64, packets, NULL);*/
-/* XXX:
- unsigned long packetsDiscardedOnSend;
- unsigned long long bytesDiscardedOnSend;
-*/
+ if (have_sr) {
+ guint64 ntptime;
+ if (gst_structure_get_uint64 (source_stats, "sr-ntptime", &ntptime)) {
+ /* 16.16 fixed point to double */
+ double val = FIXED_32_32_TO_DOUBLE (ntptime);
+ gst_structure_set (r_out, "remote-timestamp", G_TYPE_DOUBLE, val, NULL);
+ }
+ } else {
+ /* default values */
+ gst_structure_set (r_out, "remote-timestamp", G_TYPE_DOUBLE, 0.0, NULL);
+ }
- gst_structure_set (r_out, "local-id", G_TYPE_STRING, in_id, NULL);
+ gst_structure_set (r_out, "local-id", G_TYPE_STRING, in_id, NULL);
- gst_structure_set (s, in_id, GST_TYPE_STRUCTURE, in, NULL);
- gst_structure_set (s, out_id, GST_TYPE_STRUCTURE, out, NULL);
- gst_structure_set (s, r_in_id, GST_TYPE_STRUCTURE, r_in, NULL);
- gst_structure_set (s, r_out_id, GST_TYPE_STRUCTURE, r_out, NULL);
+ gst_structure_set (s, in_id, GST_TYPE_STRUCTURE, in, NULL);
+ gst_structure_set (s, r_out_id, GST_TYPE_STRUCTURE, r_out, NULL);
- gst_structure_free (in);
- gst_structure_free (out);
- gst_structure_free (r_in);
- gst_structure_free (r_out);
+ gst_structure_free (in);
+ gst_structure_free (r_out);
- g_free (in_id);
- g_free (out_id);
- g_free (r_in_id);
- g_free (r_out_id);
+ g_free (in_id);
+ g_free (r_out_id);
+ }
}
/* https://www.w3.org/TR/webrtc-stats/#candidatepair-dict* */
for (i = 0; i < source_stats->n_values; i++) {
const GstStructure *stats;
const GValue *val = g_value_array_get_nth (source_stats, i);
- gboolean internal;
guint stats_ssrc = 0;
stats = gst_value_get_structure (val);
- /* skip internal or foreign sources */
- gst_structure_get (stats,
- "internal", G_TYPE_BOOLEAN, &internal,
- "ssrc", G_TYPE_UINT, &stats_ssrc, NULL);
- if (internal || (ssrc && stats_ssrc && ssrc != stats_ssrc))
+ /* skip foreign sources */
+ gst_structure_get (stats, "ssrc", G_TYPE_UINT, &stats_ssrc, NULL);
+ if (ssrc && stats_ssrc && ssrc != stats_ssrc)
continue;
_get_stats_from_rtp_source_stats (webrtc, stats, codec_id, transport_id, s);