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, GstStructure * s)
566 gst_structure_get_double (s, "timestamp", &ts);
568 id = g_strdup_printf ("ice-candidate-pair_%s", GST_OBJECT_NAME (transport));
569 stats = gst_structure_new_empty (id);
570 _set_base_stats (stats, GST_WEBRTC_STATS_TRANSPORT, ts, id);
572 /* XXX: RTCIceCandidatePairStats
573 DOMString transportId;
574 DOMString localCandidateId;
575 DOMString remoteCandidateId;
576 RTCStatsIceCandidatePairState state;
577 unsigned long long priority;
579 unsigned long packetsSent;
580 unsigned long packetsReceived;
581 unsigned long long bytesSent;
582 unsigned long long bytesReceived;
583 DOMHighResTimeStamp lastPacketSentTimestamp;
584 DOMHighResTimeStamp lastPacketReceivedTimestamp;
585 DOMHighResTimeStamp firstRequestTimestamp;
586 DOMHighResTimeStamp lastRequestTimestamp;
587 DOMHighResTimeStamp lastResponseTimestamp;
588 double totalRoundTripTime;
589 double currentRoundTripTime;
590 double availableOutgoingBitrate;
591 double availableIncomingBitrate;
592 unsigned long circuitBreakerTriggerCount;
593 unsigned long long requestsReceived;
594 unsigned long long requestsSent;
595 unsigned long long responsesReceived;
596 unsigned long long responsesSent;
597 unsigned long long retransmissionsReceived;
598 unsigned long long retransmissionsSent;
599 unsigned long long consentRequestsSent;
600 DOMHighResTimeStamp consentExpiredTimestamp;
603 /* XXX: RTCIceCandidateStats
604 DOMString transportId;
606 RTCNetworkType networkType;
610 RTCIceCandidateType candidateType;
613 DOMString relayProtocol;
614 boolean deleted = false;
618 gst_structure_set (s, id, GST_TYPE_STRUCTURE, stats, NULL);
619 gst_structure_free (stats);
624 /* https://www.w3.org/TR/webrtc-stats/#dom-rtctransportstats */
626 _get_stats_from_dtls_transport (GstWebRTCBin * webrtc,
627 GstWebRTCDTLSTransport * transport, GstStructure * s)
634 gst_structure_get_double (s, "timestamp", &ts);
636 id = g_strdup_printf ("transport-stats_%s", GST_OBJECT_NAME (transport));
637 stats = gst_structure_new_empty (id);
638 _set_base_stats (stats, GST_WEBRTC_STATS_TRANSPORT, ts, id);
640 /* XXX: RTCTransportStats
641 unsigned long packetsSent;
642 unsigned long packetsReceived;
643 unsigned long long bytesSent;
644 unsigned long long bytesReceived;
645 DOMString rtcpTransportStatsId;
647 RTCDtlsTransportState dtlsState;
648 DOMString selectedCandidatePairId;
649 DOMString localCertificateId;
650 DOMString remoteCertificateId;
653 /* XXX: RTCCertificateStats
654 DOMString fingerprint;
655 DOMString fingerprintAlgorithm;
656 DOMString base64Certificate;
657 DOMString issuerCertificateId;
660 /* XXX: RTCIceCandidateStats
661 DOMString transportId;
666 RTCIceCandidateType candidateType;
669 boolean deleted = false;
672 gst_structure_set (s, id, GST_TYPE_STRUCTURE, stats, NULL);
673 gst_structure_free (stats);
675 ice_id = _get_stats_from_ice_transport (webrtc, transport->transport, s);
682 _get_stats_from_transport_channel (GstWebRTCBin * webrtc,
683 TransportStream * stream, const gchar * codec_id, guint ssrc,
684 guint clock_rate, GstStructure * s)
686 GstWebRTCDTLSTransport *transport;
687 GObject *rtp_session;
688 GstStructure *rtp_stats;
689 GValueArray *source_stats;
694 gst_structure_get_double (s, "timestamp", &ts);
696 transport = stream->transport;
700 g_signal_emit_by_name (webrtc->rtpbin, "get-internal-session",
701 stream->session_id, &rtp_session);
702 g_object_get (rtp_session, "stats", &rtp_stats, NULL);
704 gst_structure_get (rtp_stats, "source-stats", G_TYPE_VALUE_ARRAY,
705 &source_stats, NULL);
707 GST_DEBUG_OBJECT (webrtc, "retrieving rtp stream stats from transport %"
708 GST_PTR_FORMAT " rtp session %" GST_PTR_FORMAT " with %u rtp sources, "
709 "transport %" GST_PTR_FORMAT, stream, rtp_session, source_stats->n_values,
712 transport_id = _get_stats_from_dtls_transport (webrtc, transport, s);
714 /* construct stats objects */
715 for (i = 0; i < source_stats->n_values; i++) {
716 const GstStructure *stats;
717 const GValue *val = g_value_array_get_nth (source_stats, i);
718 guint stats_ssrc = 0;
720 stats = gst_value_get_structure (val);
722 /* skip foreign sources */
723 gst_structure_get (stats, "ssrc", G_TYPE_UINT, &stats_ssrc, NULL);
724 if (gst_structure_get_uint (stats, "ssrc", &stats_ssrc) &&
726 _get_stats_from_rtp_source_stats (webrtc, stream, stats, codec_id,
728 else if (gst_structure_get_uint (stats, "rb-ssrc", &stats_ssrc) &&
730 _get_stats_from_remote_rtp_source_stats (webrtc, stream, stats, ssrc,
731 clock_rate, codec_id, transport_id, s);
734 g_object_unref (rtp_session);
735 gst_structure_free (rtp_stats);
736 g_value_array_free (source_stats);
737 g_free (transport_id);
740 /* https://www.w3.org/TR/webrtc-stats/#codec-dict* */
742 _get_codec_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad,
743 GstStructure * s, gchar ** out_id, guint * out_ssrc, guint * out_clock_rate)
752 gst_structure_get_double (s, "timestamp", &ts);
754 stats = gst_structure_new_empty ("unused");
755 id = g_strdup_printf ("codec-stats-%s", GST_OBJECT_NAME (pad));
756 _set_base_stats (stats, GST_WEBRTC_STATS_CODEC, ts, id);
758 caps = gst_pad_get_current_caps (pad);
759 if (caps && gst_caps_is_fixed (caps)) {
760 GstStructure *caps_s = gst_caps_get_structure (caps, 0);
763 if (gst_structure_get_int (caps_s, "payload", &pt))
764 gst_structure_set (stats, "payload-type", G_TYPE_UINT, pt, NULL);
766 if (gst_structure_get_int (caps_s, "clock-rate", &clock_rate))
767 gst_structure_set (stats, "clock-rate", G_TYPE_UINT, clock_rate, NULL);
769 if (gst_structure_get_uint (caps_s, "ssrc", &ssrc))
770 gst_structure_set (stats, "ssrc", G_TYPE_UINT, ssrc, NULL);
772 /* FIXME: codecType, mimeType, channels, sdpFmtpLine, implementation, transportId */
776 gst_caps_unref (caps);
778 gst_structure_set (s, id, GST_TYPE_STRUCTURE, stats, NULL);
779 gst_structure_free (stats);
790 *out_clock_rate = clock_rate;
794 _get_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad, GstStructure * s)
796 GstWebRTCBinPad *wpad = GST_WEBRTC_BIN_PAD (pad);
797 TransportStream *stream;
799 guint ssrc, clock_rate;
801 _get_codec_stats_from_pad (webrtc, pad, s, &codec_id, &ssrc, &clock_rate);
806 stream = WEBRTC_TRANSCEIVER (wpad->trans)->stream;
810 _get_stats_from_transport_channel (webrtc, stream, codec_id, ssrc,
819 gst_webrtc_bin_create_stats (GstWebRTCBin * webrtc, GstPad * pad)
821 GstStructure *s = gst_structure_new_empty ("application/x-webrtc-stats");
822 double ts = monotonic_time_as_double_milliseconds ();
823 GstStructure *pc_stats;
827 gst_structure_set (s, "timestamp", G_TYPE_DOUBLE, ts, NULL);
829 /* FIXME: better unique IDs */
830 /* FIXME: rate limitting stat updates? */
831 /* FIXME: all stats need to be kept forever */
833 GST_DEBUG_OBJECT (webrtc, "updating stats at time %f", ts);
835 if ((pc_stats = _get_peer_connection_stats (webrtc))) {
836 const gchar *id = "peer-connection-stats";
837 _set_base_stats (pc_stats, GST_WEBRTC_STATS_PEER_CONNECTION, ts, id);
838 gst_structure_set (s, id, GST_TYPE_STRUCTURE, pc_stats, NULL);
839 gst_structure_free (pc_stats);
843 _get_stats_from_pad (webrtc, pad, s);
845 gst_element_foreach_pad (GST_ELEMENT (webrtc),
846 (GstElementForeachPadFunc) _get_stats_from_pad, s);
848 gst_structure_remove_field (s, "timestamp");