2 * Copyright (C) 2017 Matthew Waters <matthew@centricular.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
24 /* for GValueArray... */
25 #define GLIB_DISABLE_DEPRECATION_WARNINGS
27 #include "gstwebrtcstats.h"
28 #include "gstwebrtcbin.h"
29 #include "transportstream.h"
30 #include "transportreceivebin.h"
32 #include "webrtctransceiver.h"
34 #define GST_CAT_DEFAULT gst_webrtc_stats_debug
35 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
40 static gsize _init = 0;
42 if (g_once_init_enter (&_init)) {
43 GST_DEBUG_CATEGORY_INIT (gst_webrtc_stats_debug, "webrtcstats", 0,
45 g_once_init_leave (&_init, 1);
50 monotonic_time_as_double_milliseconds (void)
52 return g_get_monotonic_time () / 1000.0;
56 _set_base_stats (GstStructure * s, GstWebRTCStatsType type, double ts,
59 gchar *name = _enum_value_to_string (GST_TYPE_WEBRTC_STATS_TYPE,
62 g_return_if_fail (name != NULL);
64 gst_structure_set_name (s, name);
65 gst_structure_set (s, "type", GST_TYPE_WEBRTC_STATS_TYPE, type, "timestamp",
66 G_TYPE_DOUBLE, ts, "id", G_TYPE_STRING, id, NULL);
72 _get_peer_connection_stats (GstWebRTCBin * webrtc)
74 GstStructure *s = gst_structure_new_empty ("unused");
76 /* FIXME: datachannel */
77 gst_structure_set (s, "data-channels-opened", G_TYPE_UINT, 0,
78 "data-channels-closed", G_TYPE_UINT, 0, "data-channels-requested",
79 G_TYPE_UINT, 0, "data-channels-accepted", G_TYPE_UINT, 0, NULL);
85 _gst_structure_take_structure (GstStructure * s, const char *fieldname,
86 GstStructure ** value_s)
88 GValue v = G_VALUE_INIT;
90 g_value_init (&v, GST_TYPE_STRUCTURE);
91 g_value_take_boxed (&v, *value_s);
93 gst_structure_take_value (s, fieldname, &v);
98 #define CLOCK_RATE_VALUE_TO_SECONDS(v,r) ((double) v / (double) clock_rate)
99 #define FIXED_16_16_TO_DOUBLE(v) ((double) ((v & 0xffff0000) >> 16) + ((v & 0xffff) / 65536.0))
100 #define FIXED_32_32_TO_DOUBLE(v) ((double) ((v & G_GUINT64_CONSTANT (0xffffffff00000000)) >> 32) + ((v & G_GUINT64_CONSTANT (0xffffffff)) / 4294967296.0))
102 /* https://www.w3.org/TR/webrtc-stats/#remoteinboundrtpstats-dict* */
104 _get_stats_from_remote_rtp_source_stats (GstWebRTCBin * webrtc,
105 TransportStream * stream, const GstStructure * source_stats,
106 guint ssrc, guint clock_rate, const gchar * codec_id,
107 const gchar * transport_id, GstStructure * s)
109 gboolean have_rb = FALSE, internal = FALSE;
112 gchar *r_in_id, *out_id;
114 guint fraction_lost, jitter;
117 gst_structure_get_double (s, "timestamp", &ts);
118 gst_structure_get (source_stats, "internal", G_TYPE_BOOLEAN, &internal,
119 "have-rb", G_TYPE_BOOLEAN, &have_rb, NULL);
121 /* This isn't what we're looking for */
122 if (internal == TRUE || have_rb == FALSE)
125 r_in_id = g_strdup_printf ("rtp-remote-inbound-stream-stats_%u", ssrc);
126 out_id = g_strdup_printf ("rtp-outbound-stream-stats_%u", ssrc);
128 r_in = gst_structure_new_empty (r_in_id);
129 _set_base_stats (r_in, GST_WEBRTC_STATS_REMOTE_INBOUND_RTP, ts, r_in_id);
131 /* RTCRtpStreamStats */
132 gst_structure_set (r_in, "local-id", G_TYPE_STRING, out_id, NULL);
133 gst_structure_set (r_in, "ssrc", G_TYPE_UINT, ssrc, NULL);
134 gst_structure_set (r_in, "codec-id", G_TYPE_STRING, codec_id, NULL);
135 gst_structure_set (r_in, "transport-id", G_TYPE_STRING, transport_id, NULL);
136 /* To be added: kind */
138 /* RTCReceivedRtpStreamStats */
140 if (gst_structure_get_int (source_stats, "rb-packetslost", &lost))
141 gst_structure_set (r_in, "packets-lost", G_TYPE_INT, lost, NULL);
143 if (clock_rate && gst_structure_get_uint (source_stats, "rb-jitter", &jitter))
144 gst_structure_set (r_in, "jitter", G_TYPE_DOUBLE,
145 CLOCK_RATE_VALUE_TO_SECONDS (jitter, clock_rate), NULL);
147 /* RTCReceivedRtpStreamStats:
149 unsigned long long packetsReceived;
150 unsigned long packetsDiscarded;
151 unsigned long packetsRepaired;
152 unsigned long burstPacketsLost;
153 unsigned long burstPacketsDiscarded;
154 unsigned long burstLossCount;
155 unsigned long burstDiscardCount;
156 double burstLossRate;
157 double burstDiscardRate;
159 double gapDiscardRate;
161 Can't be implemented frame re-assembly happens after rtpbin:
163 unsigned long framesDropped;
164 unsigned long partialFramesLost;
165 unsigned long fullFramesLost;
168 /* RTCRemoteInboundRTPStreamStats */
170 if (gst_structure_get_uint (source_stats, "rb-fractionlost", &fraction_lost))
171 gst_structure_set (r_in, "fraction-lost", G_TYPE_DOUBLE,
172 (double) fraction_lost / 256.0, NULL);
174 if (gst_structure_get_uint (source_stats, "rb-round-trip", &rtt)) {
175 /* 16.16 fixed point to double */
176 double val = FIXED_16_16_TO_DOUBLE (rtt);
177 gst_structure_set (r_in, "round-trip-time", G_TYPE_DOUBLE, val, NULL);
180 /* RTCRemoteInboundRTPStreamStats:
185 double totalRoundTripTime;
186 unsigned long long reportsReceived;
187 unsigned long long roundTripTimeMeasurements;
190 gst_structure_set (r_in, "gst-rtpsource-stats", GST_TYPE_STRUCTURE,
193 _gst_structure_take_structure (s, r_in_id, &r_in);
201 /* https://www.w3.org/TR/webrtc-stats/#inboundrtpstats-dict*
202 https://www.w3.org/TR/webrtc-stats/#outboundrtpstats-dict* */
204 _get_stats_from_rtp_source_stats (GstWebRTCBin * webrtc,
205 TransportStream * stream, const GstStructure * source_stats,
206 const gchar * codec_id, const gchar * transport_id, GstStructure * s)
208 guint ssrc, fir, pli, nack, jitter;
210 guint64 packets, bytes;
214 gst_structure_get_double (s, "timestamp", &ts);
215 gst_structure_get (source_stats, "ssrc", G_TYPE_UINT, &ssrc, "clock-rate",
216 G_TYPE_INT, &clock_rate, "internal", G_TYPE_BOOLEAN, &internal, NULL);
220 gchar *out_id, *r_in_id;
222 out_id = g_strdup_printf ("rtp-outbound-stream-stats_%u", ssrc);
224 out = gst_structure_new_empty (out_id);
225 _set_base_stats (out, GST_WEBRTC_STATS_OUTBOUND_RTP, ts, out_id);
228 gst_structure_set (out, "ssrc", G_TYPE_UINT, ssrc, NULL);
229 gst_structure_set (out, "codec-id", G_TYPE_STRING, codec_id, NULL);
230 gst_structure_set (out, "transport-id", G_TYPE_STRING, transport_id, NULL);
231 /* To be added: kind */
234 /* RTCSentRtpStreamStats */
235 if (gst_structure_get_uint64 (source_stats, "octets-sent", &bytes))
236 gst_structure_set (out, "bytes-sent", G_TYPE_UINT64, bytes, NULL);
237 if (gst_structure_get_uint64 (source_stats, "packets-sent", &packets))
238 gst_structure_set (out, "packets-sent", G_TYPE_UINT64, packets, NULL);
240 /* RTCOutboundRTPStreamStats */
242 if (gst_structure_get_uint (source_stats, "recv-fir-count", &fir))
243 gst_structure_set (out, "fir-count", G_TYPE_UINT, fir, NULL);
244 if (gst_structure_get_uint (source_stats, "recv-pli-count", &pli))
245 gst_structure_set (out, "pli-count", G_TYPE_UINT, pli, NULL);
246 if (gst_structure_get_uint (source_stats, "recv-nack-count", &nack))
247 gst_structure_set (out, "nack-count", G_TYPE_UINT, nack, NULL);
248 /* XXX: mediaType, trackId, sliCount, qpSum */
250 r_in_id = g_strdup_printf ("rtp-remote-inbound-stream-stats_%u", ssrc);
251 if (gst_structure_has_field (s, r_in_id))
252 gst_structure_set (out, "remote-id", G_TYPE_STRING, r_in_id, NULL);
255 /* RTCOutboundRTPStreamStats:
259 unsigned long sliCount;
260 unsigned long rtxSsrc;
261 DOMString mediaSourceId;
265 DOMHighResTimeStamp lastPacketSentTimestamp;
266 unsigned long long headerBytesSent;
267 unsigned long packetsDiscardedOnSend;
268 unsigned long long bytesDiscardedOnSend;
269 unsigned long fecPacketsSent;
270 unsigned long long retransmittedPacketsSent;
271 unsigned long long retransmittedBytesSent;
272 double averageRtcpInterval;
273 record<USVString, unsigned long long> perDscpPacketsSent;
275 Not relevant because webrtcbin doesn't encode:
277 double targetBitrate;
278 unsigned long long totalEncodedBytesTarget;
279 unsigned long frameWidth;
280 unsigned long frameHeight;
281 unsigned long frameBitDepth;
282 double framesPerSecond;
283 unsigned long framesSent;
284 unsigned long hugeFramesSent;
285 unsigned long framesEncoded;
286 unsigned long keyFramesEncoded;
287 unsigned long framesDiscardedOnSend;
288 unsigned long long qpSum;
289 unsigned long long totalSamplesSent;
290 unsigned long long samplesEncodedWithSilk;
291 unsigned long long samplesEncodedWithCelt;
292 boolean voiceActivityFlag;
293 double totalEncodeTime;
294 double totalPacketSendDelay;
295 RTCQualityLimitationReason qualityLimitationReason;
296 record<DOMString, double> qualityLimitationDurations;
297 unsigned long qualityLimitationResolutionChanges;
298 DOMString encoderImplementation;
301 /* Store the raw stats from GStreamer into the structure for advanced
304 gst_structure_set (out, "gst-rtpsource-stats", GST_TYPE_STRUCTURE,
307 _gst_structure_take_structure (s, out_id, &out);
311 GstStructure *in, *r_out;
312 gchar *r_out_id, *in_id;
313 gboolean have_sr = FALSE;
314 GstStructure *jb_stats = NULL;
316 guint64 jb_lost, duplicates, late, rtx_success;
318 gst_structure_get (source_stats, "have-sr", G_TYPE_BOOLEAN, &have_sr, NULL);
320 for (i = 0; i < stream->remote_ssrcmap->len; i++) {
321 SsrcMapItem *item = g_ptr_array_index (stream->remote_ssrcmap, i);
323 if (item->ssrc == ssrc) {
324 GObject *jb = g_weak_ref_get (&item->rtpjitterbuffer);
327 g_object_get (jb, "stats", &jb_stats, NULL);
335 gst_structure_get (jb_stats, "num-lost", G_TYPE_UINT64, &jb_lost,
336 "num-duplicates", G_TYPE_UINT64, &duplicates, "num-late",
337 G_TYPE_UINT64, &late, "rtx-success-count", G_TYPE_UINT64,
340 in_id = g_strdup_printf ("rtp-inbound-stream-stats_%u", ssrc);
341 r_out_id = g_strdup_printf ("rtp-remote-outbound-stream-stats_%u", ssrc);
343 in = gst_structure_new_empty (in_id);
344 _set_base_stats (in, GST_WEBRTC_STATS_INBOUND_RTP, ts, in_id);
346 /* RTCRtpStreamStats */
347 gst_structure_set (in, "ssrc", G_TYPE_UINT, ssrc, NULL);
348 gst_structure_set (in, "codec-id", G_TYPE_STRING, codec_id, NULL);
349 gst_structure_set (in, "transport-id", G_TYPE_STRING, transport_id, NULL);
350 /* To be added: kind */
353 /* RTCReceivedRtpStreamStats */
355 if (gst_structure_get_uint64 (source_stats, "packets-received", &packets))
356 gst_structure_set (in, "packets-received", G_TYPE_UINT64, packets, NULL);
358 gst_structure_set (in, "packets-lost", G_TYPE_UINT64, jb_lost, NULL);
359 if (gst_structure_get_uint (source_stats, "jitter", &jitter))
360 gst_structure_set (in, "jitter", G_TYPE_DOUBLE,
361 CLOCK_RATE_VALUE_TO_SECONDS (jitter, clock_rate), NULL);
364 gst_structure_set (in, "packets-discarded", G_TYPE_UINT64, late,
365 "packets-repaired", G_TYPE_UINT64, rtx_success, NULL);
368 RTCReceivedRtpStreamStats
372 unsigned long long burstPacketsLost;
373 unsigned long long burstPacketsDiscarded;
374 unsigned long burstLossCount;
375 unsigned long burstDiscardCount;
376 double burstLossRate;
377 double burstDiscardRate;
379 double gapDiscardRate;
381 Not relevant because webrtcbin doesn't decode:
383 unsigned long framesDropped;
384 unsigned long partialFramesLost;
385 unsigned long fullFramesLost;
388 /* RTCInboundRtpStreamStats */
389 gst_structure_set (in, "remote-id", G_TYPE_STRING, r_out_id, NULL);
391 if (gst_structure_get_uint64 (source_stats, "octets-received", &bytes))
392 gst_structure_set (in, "bytes-received", G_TYPE_UINT64, bytes, NULL);
394 if (gst_structure_get_uint (source_stats, "sent-fir-count", &fir))
395 gst_structure_set (in, "fir-count", G_TYPE_UINT, fir, NULL);
396 if (gst_structure_get_uint (source_stats, "sent-pli-count", &pli))
397 gst_structure_set (in, "pli-count", G_TYPE_UINT, pli, NULL);
398 if (gst_structure_get_uint (source_stats, "sent-nack-count", &nack))
399 gst_structure_set (in, "nack-count", G_TYPE_UINT, nack, NULL);
401 gst_structure_set (in, "packets-duplicated", G_TYPE_UINT64, duplicates,
404 /* RTCInboundRtpStreamStats:
408 required DOMString receiverId;
409 double averageRtcpInterval;
410 unsigned long long headerBytesReceived;
411 unsigned long long fecPacketsReceived;
412 unsigned long long fecPacketsDiscarded;
413 unsigned long long bytesReceived;
414 unsigned long long packetsFailedDecryption;
415 record<USVString, unsigned long long> perDscpPacketsReceived;
416 unsigned long nackCount;
417 unsigned long firCount;
418 unsigned long pliCount;
419 unsigned long sliCount;
420 double jitterBufferDelay;
422 Not relevant because webrtcbin doesn't decode or depayload:
423 unsigned long framesDecoded;
424 unsigned long keyFramesDecoded;
425 unsigned long frameWidth;
426 unsigned long frameHeight;
427 unsigned long frameBitDepth;
428 double framesPerSecond;
429 unsigned long long qpSum;
430 double totalDecodeTime;
431 double totalInterFrameDelay;
432 double totalSquaredInterFrameDelay;
433 boolean voiceActivityFlag;
434 DOMHighResTimeStamp lastPacketReceivedTimestamp;
435 double totalProcessingDelay;
436 DOMHighResTimeStamp estimatedPlayoutTimestamp;
437 unsigned long long jitterBufferEmittedCount;
438 unsigned long long totalSamplesReceived;
439 unsigned long long totalSamplesDecoded;
440 unsigned long long samplesDecodedWithSilk;
441 unsigned long long samplesDecodedWithCelt;
442 unsigned long long concealedSamples;
443 unsigned long long silentConcealedSamples;
444 unsigned long long concealmentEvents;
445 unsigned long long insertedSamplesForDeceleration;
446 unsigned long long removedSamplesForAcceleration;
448 double totalAudioEnergy;
449 double totalSamplesDuration;
450 unsigned long framesReceived;
451 DOMString decoderImplementation;
454 r_out = gst_structure_new_empty (r_out_id);
455 _set_base_stats (r_out, GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP, ts, r_out_id);
457 gst_structure_set (r_out, "ssrc", G_TYPE_UINT, ssrc, NULL);
458 gst_structure_set (r_out, "codec-id", G_TYPE_STRING, codec_id, NULL);
459 gst_structure_set (r_out, "transport-id", G_TYPE_STRING, transport_id,
461 /* XXX: mediaType, trackId */
463 /* RTCSentRtpStreamStats */
466 guint sr_bytes, sr_packets;
468 if (gst_structure_get_uint (source_stats, "sr-octet-count", &sr_bytes))
469 gst_structure_set (r_out, "bytes-sent", G_TYPE_UINT, sr_bytes, NULL);
470 if (gst_structure_get_uint (source_stats, "sr-packet-count", &sr_packets))
471 gst_structure_set (r_out, "packets-sent", G_TYPE_UINT, sr_packets,
475 /* RTCSentRtpStreamStats:
479 unsigned long rtxSsrc;
480 DOMString mediaSourceId;
484 DOMHighResTimeStamp lastPacketSentTimestamp;
485 unsigned long long headerBytesSent;
486 unsigned long packetsDiscardedOnSend;
487 unsigned long long bytesDiscardedOnSend;
488 unsigned long fecPacketsSent;
489 unsigned long long retransmittedPacketsSent;
490 unsigned long long retransmittedBytesSent;
491 double averageRtcpInterval;
492 unsigned long sliCount;
494 Can't be implemented because we don't decode:
496 double targetBitrate;
497 unsigned long long totalEncodedBytesTarget;
498 unsigned long frameWidth;
499 unsigned long frameHeight;
500 unsigned long frameBitDepth;
501 double framesPerSecond;
502 unsigned long framesSent;
503 unsigned long hugeFramesSent;
504 unsigned long framesEncoded;
505 unsigned long keyFramesEncoded;
506 unsigned long framesDiscardedOnSend;
507 unsigned long long qpSum;
508 unsigned long long totalSamplesSent;
509 unsigned long long samplesEncodedWithSilk;
510 unsigned long long samplesEncodedWithCelt;
511 boolean voiceActivityFlag;
512 double totalEncodeTime;
513 double totalPacketSendDelay;
514 RTCQualityLimitationReason qualityLimitationReason;
515 record<DOMString, double> qualityLimitationDurations;
516 unsigned long qualityLimitationResolutionChanges;
517 record<USVString, unsigned long long> perDscpPacketsSent;
518 DOMString encoderImplementation;
521 /* RTCRemoteOutboundRtpStreamStats */
525 if (gst_structure_get_uint64 (source_stats, "sr-ntptime", &ntptime)) {
526 /* 16.16 fixed point to double */
527 double val = FIXED_32_32_TO_DOUBLE (ntptime);
528 gst_structure_set (r_out, "remote-timestamp", G_TYPE_DOUBLE, val, NULL);
532 gst_structure_set (r_out, "remote-timestamp", G_TYPE_DOUBLE, 0.0, NULL);
535 gst_structure_set (r_out, "local-id", G_TYPE_STRING, in_id, NULL);
541 /* Store the raw stats from GStreamer into the structure for advanced
544 _gst_structure_take_structure (in, "gst-rtpjitterbuffer-stats", &jb_stats);
546 gst_structure_set (in, "gst-rtpsource-stats", GST_TYPE_STRUCTURE,
549 _gst_structure_take_structure (s, in_id, &in);
550 _gst_structure_take_structure (s, r_out_id, &r_out);
557 /* https://www.w3.org/TR/webrtc-stats/#candidatepair-dict* */
559 _get_stats_from_ice_transport (GstWebRTCBin * webrtc,
560 GstWebRTCICETransport * transport, const GstStructure * twcc_stats,
567 gst_structure_get_double (s, "timestamp", &ts);
569 id = g_strdup_printf ("ice-candidate-pair_%s", GST_OBJECT_NAME (transport));
570 stats = gst_structure_new_empty (id);
571 _set_base_stats (stats, GST_WEBRTC_STATS_TRANSPORT, ts, id);
573 /* XXX: RTCIceCandidatePairStats
574 DOMString transportId;
575 DOMString localCandidateId;
576 DOMString remoteCandidateId;
577 RTCStatsIceCandidatePairState state;
578 unsigned long long priority;
580 unsigned long packetsSent;
581 unsigned long packetsReceived;
582 unsigned long long bytesSent;
583 unsigned long long bytesReceived;
584 DOMHighResTimeStamp lastPacketSentTimestamp;
585 DOMHighResTimeStamp lastPacketReceivedTimestamp;
586 DOMHighResTimeStamp firstRequestTimestamp;
587 DOMHighResTimeStamp lastRequestTimestamp;
588 DOMHighResTimeStamp lastResponseTimestamp;
589 double totalRoundTripTime;
590 double currentRoundTripTime;
591 double availableOutgoingBitrate;
592 double availableIncomingBitrate;
593 unsigned long circuitBreakerTriggerCount;
594 unsigned long long requestsReceived;
595 unsigned long long requestsSent;
596 unsigned long long responsesReceived;
597 unsigned long long responsesSent;
598 unsigned long long retransmissionsReceived;
599 unsigned long long retransmissionsSent;
600 unsigned long long consentRequestsSent;
601 DOMHighResTimeStamp consentExpiredTimestamp;
604 /* XXX: RTCIceCandidateStats
605 DOMString transportId;
607 RTCNetworkType networkType;
611 RTCIceCandidateType candidateType;
614 DOMString relayProtocol;
615 boolean deleted = false;
619 /* XXX: these stats are at the rtp session level but there isn't a specific
620 * stats structure for that. The RTCIceCandidatePairStats is the closest with
621 * the 'availableIncomingBitrate' and 'availableOutgoingBitrate' fields
624 gst_structure_set (stats, "gst-twcc-stats", GST_TYPE_STRUCTURE, twcc_stats,
627 gst_structure_set (s, id, GST_TYPE_STRUCTURE, stats, NULL);
628 gst_structure_free (stats);
633 /* https://www.w3.org/TR/webrtc-stats/#dom-rtctransportstats */
635 _get_stats_from_dtls_transport (GstWebRTCBin * webrtc,
636 GstWebRTCDTLSTransport * transport, const GstStructure * twcc_stats,
644 gst_structure_get_double (s, "timestamp", &ts);
646 id = g_strdup_printf ("transport-stats_%s", GST_OBJECT_NAME (transport));
647 stats = gst_structure_new_empty (id);
648 _set_base_stats (stats, GST_WEBRTC_STATS_TRANSPORT, ts, id);
650 /* XXX: RTCTransportStats
651 unsigned long packetsSent;
652 unsigned long packetsReceived;
653 unsigned long long bytesSent;
654 unsigned long long bytesReceived;
655 DOMString rtcpTransportStatsId;
657 RTCDtlsTransportState dtlsState;
658 DOMString selectedCandidatePairId;
659 DOMString localCertificateId;
660 DOMString remoteCertificateId;
663 /* XXX: RTCCertificateStats
664 DOMString fingerprint;
665 DOMString fingerprintAlgorithm;
666 DOMString base64Certificate;
667 DOMString issuerCertificateId;
670 /* XXX: RTCIceCandidateStats
671 DOMString transportId;
676 RTCIceCandidateType candidateType;
679 boolean deleted = false;
682 gst_structure_set (s, id, GST_TYPE_STRUCTURE, stats, NULL);
683 gst_structure_free (stats);
686 _get_stats_from_ice_transport (webrtc, transport->transport, twcc_stats,
694 _get_stats_from_transport_channel (GstWebRTCBin * webrtc,
695 TransportStream * stream, const gchar * codec_id, guint ssrc,
696 guint clock_rate, GstStructure * s)
698 GstWebRTCDTLSTransport *transport;
699 GObject *rtp_session;
700 GObject *gst_rtp_session;
701 GstStructure *rtp_stats, *twcc_stats;
702 GValueArray *source_stats;
707 gst_structure_get_double (s, "timestamp", &ts);
709 transport = stream->transport;
713 g_signal_emit_by_name (webrtc->rtpbin, "get-internal-session",
714 stream->session_id, &rtp_session);
715 g_object_get (rtp_session, "stats", &rtp_stats, NULL);
716 g_signal_emit_by_name (webrtc->rtpbin, "get-session",
717 stream->session_id, &gst_rtp_session);
718 g_object_get (gst_rtp_session, "twcc-stats", &twcc_stats, NULL);
720 gst_structure_get (rtp_stats, "source-stats", G_TYPE_VALUE_ARRAY,
721 &source_stats, NULL);
723 GST_DEBUG_OBJECT (webrtc, "retrieving rtp stream stats from transport %"
724 GST_PTR_FORMAT " rtp session %" GST_PTR_FORMAT " with %u rtp sources, "
725 "transport %" GST_PTR_FORMAT, stream, rtp_session, source_stats->n_values,
729 _get_stats_from_dtls_transport (webrtc, transport, twcc_stats, s);
731 /* construct stats objects */
732 for (i = 0; i < source_stats->n_values; i++) {
733 const GstStructure *stats;
734 const GValue *val = g_value_array_get_nth (source_stats, i);
735 guint stats_ssrc = 0;
737 stats = gst_value_get_structure (val);
739 /* skip foreign sources */
740 gst_structure_get (stats, "ssrc", G_TYPE_UINT, &stats_ssrc, NULL);
741 if (gst_structure_get_uint (stats, "ssrc", &stats_ssrc) &&
743 _get_stats_from_rtp_source_stats (webrtc, stream, stats, codec_id,
745 else if (gst_structure_get_uint (stats, "rb-ssrc", &stats_ssrc) &&
747 _get_stats_from_remote_rtp_source_stats (webrtc, stream, stats, ssrc,
748 clock_rate, codec_id, transport_id, s);
751 g_object_unref (rtp_session);
752 g_object_unref (gst_rtp_session);
753 gst_structure_free (rtp_stats);
755 gst_structure_free (twcc_stats);
756 g_value_array_free (source_stats);
757 g_free (transport_id);
760 /* https://www.w3.org/TR/webrtc-stats/#codec-dict* */
762 _get_codec_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad,
763 GstStructure * s, gchar ** out_id, guint * out_ssrc, guint * out_clock_rate)
772 gst_structure_get_double (s, "timestamp", &ts);
774 stats = gst_structure_new_empty ("unused");
775 id = g_strdup_printf ("codec-stats-%s", GST_OBJECT_NAME (pad));
776 _set_base_stats (stats, GST_WEBRTC_STATS_CODEC, ts, id);
778 caps = gst_pad_get_current_caps (pad);
779 if (caps && gst_caps_is_fixed (caps)) {
780 GstStructure *caps_s = gst_caps_get_structure (caps, 0);
783 if (gst_structure_get_int (caps_s, "payload", &pt))
784 gst_structure_set (stats, "payload-type", G_TYPE_UINT, pt, NULL);
786 if (gst_structure_get_int (caps_s, "clock-rate", &clock_rate))
787 gst_structure_set (stats, "clock-rate", G_TYPE_UINT, clock_rate, NULL);
789 if (gst_structure_get_uint (caps_s, "ssrc", &ssrc))
790 gst_structure_set (stats, "ssrc", G_TYPE_UINT, ssrc, NULL);
792 /* FIXME: codecType, mimeType, channels, sdpFmtpLine, implementation, transportId */
796 gst_caps_unref (caps);
798 gst_structure_set (s, id, GST_TYPE_STRUCTURE, stats, NULL);
799 gst_structure_free (stats);
810 *out_clock_rate = clock_rate;
814 _get_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad, GstStructure * s)
816 GstWebRTCBinPad *wpad = GST_WEBRTC_BIN_PAD (pad);
817 TransportStream *stream;
819 guint ssrc, clock_rate;
821 _get_codec_stats_from_pad (webrtc, pad, s, &codec_id, &ssrc, &clock_rate);
826 stream = WEBRTC_TRANSCEIVER (wpad->trans)->stream;
830 _get_stats_from_transport_channel (webrtc, stream, codec_id, ssrc,
839 gst_webrtc_bin_create_stats (GstWebRTCBin * webrtc, GstPad * pad)
841 GstStructure *s = gst_structure_new_empty ("application/x-webrtc-stats");
842 double ts = monotonic_time_as_double_milliseconds ();
843 GstStructure *pc_stats;
847 gst_structure_set (s, "timestamp", G_TYPE_DOUBLE, ts, NULL);
849 /* FIXME: better unique IDs */
850 /* FIXME: rate limitting stat updates? */
851 /* FIXME: all stats need to be kept forever */
853 GST_DEBUG_OBJECT (webrtc, "updating stats at time %f", ts);
855 if ((pc_stats = _get_peer_connection_stats (webrtc))) {
856 const gchar *id = "peer-connection-stats";
857 _set_base_stats (pc_stats, GST_WEBRTC_STATS_PEER_CONNECTION, ts, id);
858 gst_structure_set (s, id, GST_TYPE_STRUCTURE, pc_stats, NULL);
859 gst_structure_free (pc_stats);
863 _get_stats_from_pad (webrtc, pad, s);
865 gst_element_foreach_pad (GST_ELEMENT (webrtc),
866 (GstElementForeachPadFunc) _get_stats_from_pad, s);
868 gst_structure_remove_field (s, "timestamp");