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/#inboundrtpstats-dict*
103 https://www.w3.org/TR/webrtc-stats/#outboundrtpstats-dict* */
105 _get_stats_from_rtp_source_stats (GstWebRTCBin * webrtc,
106 TransportStream * stream, const GstStructure * source_stats,
107 const gchar * codec_id, const gchar * transport_id, GstStructure * s)
109 guint ssrc, fir, pli, nack, jitter;
110 int lost, clock_rate;
111 guint64 packets, bytes;
115 gst_structure_get_double (s, "timestamp", &ts);
116 gst_structure_get (source_stats, "ssrc", G_TYPE_UINT, &ssrc, "clock-rate",
117 G_TYPE_INT, &clock_rate, "internal", G_TYPE_BOOLEAN, &internal, NULL);
120 GstStructure *r_in, *out;
121 gchar *out_id, *r_in_id;
122 gboolean have_rb = FALSE;
124 out_id = g_strdup_printf ("rtp-outbound-stream-stats_%u", ssrc);
125 r_in_id = g_strdup_printf ("rtp-remote-inbound-stream-stats_%u", ssrc);
127 gst_structure_get (source_stats, "have-rb", G_TYPE_BOOLEAN, &have_rb, NULL);
129 r_in = gst_structure_new_empty (r_in_id);
130 _set_base_stats (r_in, GST_WEBRTC_STATS_REMOTE_INBOUND_RTP, ts, r_in_id);
132 /* RTCRtpStreamStats */
133 gst_structure_set (r_in, "local-id", G_TYPE_STRING, out_id, NULL);
134 gst_structure_set (r_in, "ssrc", G_TYPE_UINT, ssrc, NULL);
135 gst_structure_set (r_in, "codec-id", G_TYPE_STRING, codec_id, NULL);
136 gst_structure_set (r_in, "transport-id", G_TYPE_STRING, transport_id, NULL);
137 /* To be added: kind */
139 /* RTCReceivedRtpStreamStats:
143 unsigned long long packetsReceived;
144 long long packetsLost;
146 unsigned long packetsDiscarded;
147 unsigned long packetsRepaired;
148 unsigned long burstPacketsLost;
149 unsigned long burstPacketsDiscarded;
150 unsigned long burstLossCount;
151 unsigned long burstDiscardCount;
152 double burstLossRate;
153 double burstDiscardRate;
155 double gapDiscardRate;
157 Can't be implemented frame re-assembly happens after rtpbin:
159 unsigned long framesDropped;
160 unsigned long partialFramesLost;
161 unsigned long fullFramesLost;
165 /* RTCRemoteInboundRTPStreamStats */
169 if (gst_structure_get_uint (source_stats, "rb-round-trip", &rtt)) {
170 /* 16.16 fixed point to double */
171 double val = FIXED_16_16_TO_DOUBLE (rtt);
172 gst_structure_set (r_in, "round-trip-time", G_TYPE_DOUBLE, val, NULL);
176 /* RTCRemoteInboundRTPStreamStats:
181 double totalRoundTripTime;
182 unsigned long long reportsReceived;
183 unsigned long long roundTripTimeMeasurements;
186 out = gst_structure_new_empty (out_id);
187 _set_base_stats (out, GST_WEBRTC_STATS_OUTBOUND_RTP, ts, out_id);
190 gst_structure_set (out, "ssrc", G_TYPE_UINT, ssrc, NULL);
191 gst_structure_set (out, "codec-id", G_TYPE_STRING, codec_id, NULL);
192 gst_structure_set (out, "transport-id", G_TYPE_STRING, transport_id, NULL);
193 /* To be added: kind */
196 /* RTCSentRtpStreamStats */
197 if (gst_structure_get_uint64 (source_stats, "octets-sent", &bytes))
198 gst_structure_set (out, "bytes-sent", G_TYPE_UINT64, bytes, NULL);
199 if (gst_structure_get_uint64 (source_stats, "packets-sent", &packets))
200 gst_structure_set (out, "packets-sent", G_TYPE_UINT64, packets, NULL);
202 /* RTCOutboundRTPStreamStats */
204 if (gst_structure_get_uint (source_stats, "recv-fir-count", &fir))
205 gst_structure_set (out, "fir-count", G_TYPE_UINT, fir, NULL);
206 if (gst_structure_get_uint (source_stats, "recv-pli-count", &pli))
207 gst_structure_set (out, "pli-count", G_TYPE_UINT, pli, NULL);
208 if (gst_structure_get_uint (source_stats, "recv-nack-count", &nack))
209 gst_structure_set (out, "nack-count", G_TYPE_UINT, nack, NULL);
210 /* XXX: mediaType, trackId, sliCount, qpSum */
212 gst_structure_set (out, "remote-id", G_TYPE_STRING, r_in_id, NULL);
215 /* RTCOutboundRTPStreamStats:
219 unsigned long sliCount;
220 unsigned long rtxSsrc;
221 DOMString mediaSourceId;
225 DOMHighResTimeStamp lastPacketSentTimestamp;
226 unsigned long long headerBytesSent;
227 unsigned long packetsDiscardedOnSend;
228 unsigned long long bytesDiscardedOnSend;
229 unsigned long fecPacketsSent;
230 unsigned long long retransmittedPacketsSent;
231 unsigned long long retransmittedBytesSent;
232 double averageRtcpInterval;
233 record<USVString, unsigned long long> perDscpPacketsSent;
235 Not relevant because webrtcbin doesn't encode:
237 double targetBitrate;
238 unsigned long long totalEncodedBytesTarget;
239 unsigned long frameWidth;
240 unsigned long frameHeight;
241 unsigned long frameBitDepth;
242 double framesPerSecond;
243 unsigned long framesSent;
244 unsigned long hugeFramesSent;
245 unsigned long framesEncoded;
246 unsigned long keyFramesEncoded;
247 unsigned long framesDiscardedOnSend;
248 unsigned long long qpSum;
249 unsigned long long totalSamplesSent;
250 unsigned long long samplesEncodedWithSilk;
251 unsigned long long samplesEncodedWithCelt;
252 boolean voiceActivityFlag;
253 double totalEncodeTime;
254 double totalPacketSendDelay;
255 RTCQualityLimitationReason qualityLimitationReason;
256 record<DOMString, double> qualityLimitationDurations;
257 unsigned long qualityLimitationResolutionChanges;
258 DOMString encoderImplementation;
261 /* Store the raw stats from GStreamer into the structure for advanced
264 gst_structure_set (out, "gst-rtpsource-stats", GST_TYPE_STRUCTURE,
268 _gst_structure_take_structure (s, out_id, &out);
269 _gst_structure_take_structure (s, r_in_id, &r_in);
274 GstStructure *in, *r_out;
275 gchar *r_out_id, *in_id;
276 gboolean have_sr = FALSE;
277 GstStructure *jb_stats = NULL;
279 guint64 jb_lost, duplicates, late, rtx_success;
281 gst_structure_get (source_stats, "have-sr", G_TYPE_BOOLEAN, &have_sr, NULL);
283 for (i = 0; i < stream->remote_ssrcmap->len; i++) {
285 &g_array_index (stream->remote_ssrcmap, SsrcMapItem, i);
287 if (item->ssrc == ssrc) {
288 GObject *jb = g_weak_ref_get (&item->rtpjitterbuffer);
291 g_object_get (jb, "stats", &jb_stats, NULL);
299 gst_structure_get (jb_stats, "num-lost", G_TYPE_UINT64, &jb_lost,
300 "num-duplicates", G_TYPE_UINT64, &duplicates, "num-late",
301 G_TYPE_UINT64, &late, "rtx-success-count", G_TYPE_UINT64,
304 in_id = g_strdup_printf ("rtp-inbound-stream-stats_%u", ssrc);
305 r_out_id = g_strdup_printf ("rtp-remote-outbound-stream-stats_%u", ssrc);
307 in = gst_structure_new_empty (in_id);
308 _set_base_stats (in, GST_WEBRTC_STATS_INBOUND_RTP, ts, in_id);
310 /* RTCRtpStreamStats */
311 gst_structure_set (in, "ssrc", G_TYPE_UINT, ssrc, NULL);
312 gst_structure_set (in, "codec-id", G_TYPE_STRING, codec_id, NULL);
313 gst_structure_set (in, "transport-id", G_TYPE_STRING, transport_id, NULL);
314 /* To be added: kind */
317 /* RTCReceivedRtpStreamStats */
319 if (gst_structure_get_uint64 (source_stats, "packets-received", &packets))
320 gst_structure_set (in, "packets-received", G_TYPE_UINT64, packets, NULL);
322 gst_structure_set (in, "packets-lost", G_TYPE_UINT64, jb_lost, NULL);
323 if (gst_structure_get_uint (source_stats, "jitter", &jitter))
324 gst_structure_set (in, "jitter", G_TYPE_DOUBLE,
325 CLOCK_RATE_VALUE_TO_SECONDS (jitter, clock_rate), NULL);
328 gst_structure_set (in, "packets-discarded", G_TYPE_UINT64, late,
329 "packets-repaired", G_TYPE_UINT64, rtx_success, NULL);
332 RTCReceivedRtpStreamStats
336 unsigned long long burstPacketsLost;
337 unsigned long long burstPacketsDiscarded;
338 unsigned long burstLossCount;
339 unsigned long burstDiscardCount;
340 double burstLossRate;
341 double burstDiscardRate;
343 double gapDiscardRate;
345 Not relevant because webrtcbin doesn't decode:
347 unsigned long framesDropped;
348 unsigned long partialFramesLost;
349 unsigned long fullFramesLost;
352 /* RTCInboundRtpStreamStats */
353 gst_structure_set (in, "remote-id", G_TYPE_STRING, r_out_id, NULL);
355 if (gst_structure_get_uint64 (source_stats, "octets-received", &bytes))
356 gst_structure_set (in, "bytes-received", G_TYPE_UINT64, bytes, NULL);
358 if (gst_structure_get_uint (source_stats, "sent-fir-count", &fir))
359 gst_structure_set (in, "fir-count", G_TYPE_UINT, fir, NULL);
360 if (gst_structure_get_uint (source_stats, "sent-pli-count", &pli))
361 gst_structure_set (in, "pli-count", G_TYPE_UINT, pli, NULL);
362 if (gst_structure_get_uint (source_stats, "sent-nack-count", &nack))
363 gst_structure_set (in, "nack-count", G_TYPE_UINT, nack, NULL);
365 gst_structure_set (in, "packets-duplicated", G_TYPE_UINT64, duplicates,
368 /* RTCInboundRtpStreamStats:
372 required DOMString receiverId;
373 double averageRtcpInterval;
374 unsigned long long headerBytesReceived;
375 unsigned long long fecPacketsReceived;
376 unsigned long long fecPacketsDiscarded;
377 unsigned long long bytesReceived;
378 unsigned long long packetsFailedDecryption;
379 record<USVString, unsigned long long> perDscpPacketsReceived;
380 unsigned long nackCount;
381 unsigned long firCount;
382 unsigned long pliCount;
383 unsigned long sliCount;
384 double jitterBufferDelay;
386 Not relevant because webrtcbin doesn't decode or depayload:
387 unsigned long framesDecoded;
388 unsigned long keyFramesDecoded;
389 unsigned long frameWidth;
390 unsigned long frameHeight;
391 unsigned long frameBitDepth;
392 double framesPerSecond;
393 unsigned long long qpSum;
394 double totalDecodeTime;
395 double totalInterFrameDelay;
396 double totalSquaredInterFrameDelay;
397 boolean voiceActivityFlag;
398 DOMHighResTimeStamp lastPacketReceivedTimestamp;
399 double totalProcessingDelay;
400 DOMHighResTimeStamp estimatedPlayoutTimestamp;
401 unsigned long long jitterBufferEmittedCount;
402 unsigned long long totalSamplesReceived;
403 unsigned long long totalSamplesDecoded;
404 unsigned long long samplesDecodedWithSilk;
405 unsigned long long samplesDecodedWithCelt;
406 unsigned long long concealedSamples;
407 unsigned long long silentConcealedSamples;
408 unsigned long long concealmentEvents;
409 unsigned long long insertedSamplesForDeceleration;
410 unsigned long long removedSamplesForAcceleration;
412 double totalAudioEnergy;
413 double totalSamplesDuration;
414 unsigned long framesReceived;
415 DOMString decoderImplementation;
418 r_out = gst_structure_new_empty (r_out_id);
419 _set_base_stats (r_out, GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP, ts, r_out_id);
421 gst_structure_set (r_out, "ssrc", G_TYPE_UINT, ssrc, NULL);
422 gst_structure_set (r_out, "codec-id", G_TYPE_STRING, codec_id, NULL);
423 gst_structure_set (r_out, "transport-id", G_TYPE_STRING, transport_id,
425 /* XXX: mediaType, trackId */
427 /* RTCSentRtpStreamStats */
430 if (gst_structure_get_uint64 (source_stats, "sr-octet-count", &bytes))
431 gst_structure_set (r_out, "bytes-sent", G_TYPE_UINT64, bytes, NULL);
432 if (gst_structure_get_uint64 (source_stats, "sr-packet-count", &packets))
433 gst_structure_set (r_out, "packets-sent", G_TYPE_UINT64, packets, NULL);
436 /* RTCSentRtpStreamStats:
440 unsigned long rtxSsrc;
441 DOMString mediaSourceId;
445 DOMHighResTimeStamp lastPacketSentTimestamp;
446 unsigned long long headerBytesSent;
447 unsigned long packetsDiscardedOnSend;
448 unsigned long long bytesDiscardedOnSend;
449 unsigned long fecPacketsSent;
450 unsigned long long retransmittedPacketsSent;
451 unsigned long long retransmittedBytesSent;
452 double averageRtcpInterval;
453 unsigned long sliCount;
455 Can't be implemented because we don't decode:
457 double targetBitrate;
458 unsigned long long totalEncodedBytesTarget;
459 unsigned long frameWidth;
460 unsigned long frameHeight;
461 unsigned long frameBitDepth;
462 double framesPerSecond;
463 unsigned long framesSent;
464 unsigned long hugeFramesSent;
465 unsigned long framesEncoded;
466 unsigned long keyFramesEncoded;
467 unsigned long framesDiscardedOnSend;
468 unsigned long long qpSum;
469 unsigned long long totalSamplesSent;
470 unsigned long long samplesEncodedWithSilk;
471 unsigned long long samplesEncodedWithCelt;
472 boolean voiceActivityFlag;
473 double totalEncodeTime;
474 double totalPacketSendDelay;
475 RTCQualityLimitationReason qualityLimitationReason;
476 record<DOMString, double> qualityLimitationDurations;
477 unsigned long qualityLimitationResolutionChanges;
478 record<USVString, unsigned long long> perDscpPacketsSent;
479 DOMString encoderImplementation;
482 /* RTCRemoteOutboundRtpStreamStats */
486 if (gst_structure_get_uint64 (source_stats, "sr-ntptime", &ntptime)) {
487 /* 16.16 fixed point to double */
488 double val = FIXED_32_32_TO_DOUBLE (ntptime);
489 gst_structure_set (r_out, "remote-timestamp", G_TYPE_DOUBLE, val, NULL);
493 gst_structure_set (r_out, "remote-timestamp", G_TYPE_DOUBLE, 0.0, NULL);
496 gst_structure_set (r_out, "local-id", G_TYPE_STRING, in_id, NULL);
502 /* Store the raw stats from GStreamer into the structure for advanced
505 _gst_structure_take_structure (in, "gst-rtpjitterbuffer-stats", &jb_stats);
507 gst_structure_set (in, "gst-rtpsource-stats", GST_TYPE_STRUCTURE,
510 _gst_structure_take_structure (s, in_id, &in);
511 _gst_structure_take_structure (s, r_out_id, &r_out);
518 /* https://www.w3.org/TR/webrtc-stats/#candidatepair-dict* */
520 _get_stats_from_ice_transport (GstWebRTCBin * webrtc,
521 GstWebRTCICETransport * transport, GstStructure * s)
527 gst_structure_get_double (s, "timestamp", &ts);
529 id = g_strdup_printf ("ice-candidate-pair_%s", GST_OBJECT_NAME (transport));
530 stats = gst_structure_new_empty (id);
531 _set_base_stats (stats, GST_WEBRTC_STATS_TRANSPORT, ts, id);
533 /* XXX: RTCIceCandidatePairStats
534 DOMString transportId;
535 DOMString localCandidateId;
536 DOMString remoteCandidateId;
537 RTCStatsIceCandidatePairState state;
538 unsigned long long priority;
540 unsigned long packetsSent;
541 unsigned long packetsReceived;
542 unsigned long long bytesSent;
543 unsigned long long bytesReceived;
544 DOMHighResTimeStamp lastPacketSentTimestamp;
545 DOMHighResTimeStamp lastPacketReceivedTimestamp;
546 DOMHighResTimeStamp firstRequestTimestamp;
547 DOMHighResTimeStamp lastRequestTimestamp;
548 DOMHighResTimeStamp lastResponseTimestamp;
549 double totalRoundTripTime;
550 double currentRoundTripTime;
551 double availableOutgoingBitrate;
552 double availableIncomingBitrate;
553 unsigned long circuitBreakerTriggerCount;
554 unsigned long long requestsReceived;
555 unsigned long long requestsSent;
556 unsigned long long responsesReceived;
557 unsigned long long responsesSent;
558 unsigned long long retransmissionsReceived;
559 unsigned long long retransmissionsSent;
560 unsigned long long consentRequestsSent;
561 DOMHighResTimeStamp consentExpiredTimestamp;
564 /* XXX: RTCIceCandidateStats
565 DOMString transportId;
567 RTCNetworkType networkType;
571 RTCIceCandidateType candidateType;
574 DOMString relayProtocol;
575 boolean deleted = false;
579 gst_structure_set (s, id, GST_TYPE_STRUCTURE, stats, NULL);
580 gst_structure_free (stats);
585 /* https://www.w3.org/TR/webrtc-stats/#dom-rtctransportstats */
587 _get_stats_from_dtls_transport (GstWebRTCBin * webrtc,
588 GstWebRTCDTLSTransport * transport, GstStructure * s)
595 gst_structure_get_double (s, "timestamp", &ts);
597 id = g_strdup_printf ("transport-stats_%s", GST_OBJECT_NAME (transport));
598 stats = gst_structure_new_empty (id);
599 _set_base_stats (stats, GST_WEBRTC_STATS_TRANSPORT, ts, id);
601 /* XXX: RTCTransportStats
602 unsigned long packetsSent;
603 unsigned long packetsReceived;
604 unsigned long long bytesSent;
605 unsigned long long bytesReceived;
606 DOMString rtcpTransportStatsId;
608 RTCDtlsTransportState dtlsState;
609 DOMString selectedCandidatePairId;
610 DOMString localCertificateId;
611 DOMString remoteCertificateId;
614 /* XXX: RTCCertificateStats
615 DOMString fingerprint;
616 DOMString fingerprintAlgorithm;
617 DOMString base64Certificate;
618 DOMString issuerCertificateId;
621 /* XXX: RTCIceCandidateStats
622 DOMString transportId;
627 RTCIceCandidateType candidateType;
630 boolean deleted = false;
633 gst_structure_set (s, id, GST_TYPE_STRUCTURE, stats, NULL);
634 gst_structure_free (stats);
636 ice_id = _get_stats_from_ice_transport (webrtc, transport->transport, s);
643 _get_stats_from_transport_channel (GstWebRTCBin * webrtc,
644 TransportStream * stream, const gchar * codec_id, guint ssrc,
647 GstWebRTCDTLSTransport *transport;
648 GObject *rtp_session;
649 GstStructure *rtp_stats;
650 GValueArray *source_stats;
655 gst_structure_get_double (s, "timestamp", &ts);
657 transport = stream->transport;
661 g_signal_emit_by_name (webrtc->rtpbin, "get-internal-session",
662 stream->session_id, &rtp_session);
663 g_object_get (rtp_session, "stats", &rtp_stats, NULL);
665 gst_structure_get (rtp_stats, "source-stats", G_TYPE_VALUE_ARRAY,
666 &source_stats, NULL);
668 GST_DEBUG_OBJECT (webrtc, "retrieving rtp stream stats from transport %"
669 GST_PTR_FORMAT " rtp session %" GST_PTR_FORMAT " with %u rtp sources, "
670 "transport %" GST_PTR_FORMAT, stream, rtp_session, source_stats->n_values,
673 transport_id = _get_stats_from_dtls_transport (webrtc, transport, s);
675 /* construct stats objects */
676 for (i = 0; i < source_stats->n_values; i++) {
677 const GstStructure *stats;
678 const GValue *val = g_value_array_get_nth (source_stats, i);
679 guint stats_ssrc = 0;
681 stats = gst_value_get_structure (val);
683 /* skip foreign sources */
684 gst_structure_get (stats, "ssrc", G_TYPE_UINT, &stats_ssrc, NULL);
685 if (ssrc && stats_ssrc && ssrc != stats_ssrc)
688 _get_stats_from_rtp_source_stats (webrtc, stream, stats, codec_id,
692 g_object_unref (rtp_session);
693 gst_structure_free (rtp_stats);
694 g_value_array_free (source_stats);
695 g_free (transport_id);
698 /* https://www.w3.org/TR/webrtc-stats/#codec-dict* */
700 _get_codec_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad,
701 GstStructure * s, gchar ** out_id, guint * out_ssrc)
709 gst_structure_get_double (s, "timestamp", &ts);
711 stats = gst_structure_new_empty ("unused");
712 id = g_strdup_printf ("codec-stats-%s", GST_OBJECT_NAME (pad));
713 _set_base_stats (stats, GST_WEBRTC_STATS_CODEC, ts, id);
715 caps = gst_pad_get_current_caps (pad);
716 if (caps && gst_caps_is_fixed (caps)) {
717 GstStructure *caps_s = gst_caps_get_structure (caps, 0);
720 if (gst_structure_get_int (caps_s, "payload", &pt))
721 gst_structure_set (stats, "payload-type", G_TYPE_UINT, pt, NULL);
723 if (gst_structure_get_int (caps_s, "clock-rate", &clock_rate))
724 gst_structure_set (stats, "clock-rate", G_TYPE_UINT, clock_rate, NULL);
726 if (gst_structure_get_uint (caps_s, "ssrc", &ssrc))
727 gst_structure_set (stats, "ssrc", G_TYPE_UINT, ssrc, NULL);
729 /* FIXME: codecType, mimeType, channels, sdpFmtpLine, implementation, transportId */
733 gst_caps_unref (caps);
735 gst_structure_set (s, id, GST_TYPE_STRUCTURE, stats, NULL);
736 gst_structure_free (stats);
748 _get_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad, GstStructure * s)
750 GstWebRTCBinPad *wpad = GST_WEBRTC_BIN_PAD (pad);
751 TransportStream *stream;
755 _get_codec_stats_from_pad (webrtc, pad, s, &codec_id, &ssrc);
760 stream = WEBRTC_TRANSCEIVER (wpad->trans)->stream;
764 _get_stats_from_transport_channel (webrtc, stream, codec_id, ssrc, s);
772 gst_webrtc_bin_create_stats (GstWebRTCBin * webrtc, GstPad * pad)
774 GstStructure *s = gst_structure_new_empty ("application/x-webrtc-stats");
775 double ts = monotonic_time_as_double_milliseconds ();
776 GstStructure *pc_stats;
780 gst_structure_set (s, "timestamp", G_TYPE_DOUBLE, ts, NULL);
782 /* FIXME: better unique IDs */
783 /* FIXME: rate limitting stat updates? */
784 /* FIXME: all stats need to be kept forever */
786 GST_DEBUG_OBJECT (webrtc, "updating stats at time %f", ts);
788 if ((pc_stats = _get_peer_connection_stats (webrtc))) {
789 const gchar *id = "peer-connection-stats";
790 _set_base_stats (pc_stats, GST_WEBRTC_STATS_PEER_CONNECTION, ts, id);
791 gst_structure_set (s, id, GST_TYPE_STRUCTURE, pc_stats, NULL);
792 gst_structure_free (pc_stats);
796 _get_stats_from_pad (webrtc, pad, s);
798 gst_element_foreach_pad (GST_ELEMENT (webrtc),
799 (GstElementForeachPadFunc) _get_stats_from_pad, s);
801 gst_structure_remove_field (s, "timestamp");