Repository: pion/webrtc
Pull request #2112 (2022-02-03 00:48:13)

Add SCTPTransportStats
#### Description
Adds functions to get SCTPTransport stats defined in https://www.w3.org/TR/webrtc-stats/#dom-rtcsctptransportstats. This PR is in conjunction with https://github.com/pion/sctp/pull/205. 


codecov[bot]: # [Codecov](https://codecov.io/gh/pion/webrtc/pull/2112?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) Report
> Merging [#2112](https://codecov.io/gh/pion/webrtc/pull/2112?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) (99bec0f) into [master](https://codecov.io/gh/pion/webrtc/commit/8796a5c5a7359e12f0164823631d6e25579a4260?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) (8796a5c) will **decrease** coverage by `6.96%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/pion/webrtc/pull/2112/graphs/tree.svg?width=650&height=150&src=pr&token=XOOuQo07I2&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion)](https://codecov.io/gh/pion/webrtc/pull/2112?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion)

```diff
@@            Coverage Diff             @@
##           master    #2112      +/-   ##
==========================================
- Coverage   77.25%   70.28%   -6.97%     
==========================================
  Files          84       61      -23     
  Lines        8783     3224    -5559     
==========================================
- Hits         6785     2266    -4519     
+ Misses       1590      843     -747     
+ Partials      408      115     -293     
```

| Flag | Coverage Δ | |
|---|---|---|
| go | `?` | |
| wasm | `70.28% <ø> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/pion/webrtc/pull/2112?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) | Coverage Δ | |
|---|---|---|
| [stats.go](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-c3RhdHMuZ28=) | `0.00% <ø> (-75.00%)` | :arrow_down: |
| [constants.go](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-Y29uc3RhbnRzLmdv) | `0.00% <0.00%> (-100.00%)` | :arrow_down: |
| [icecandidatepair.go](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-aWNlY2FuZGlkYXRlcGFpci5nbw==) | `0.00% <0.00%> (-81.82%)` | :arrow_down: |
| [rtpcodec.go](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-cnRwY29kZWMuZ28=) | `13.33% <0.00%> (-80.00%)` | :arrow_down: |
| [track\_local.go](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-dHJhY2tfbG9jYWwuZ28=) | `0.00% <0.00%> (-80.00%)` | :arrow_down: |
| [internal/mux/muxfunc.go](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-aW50ZXJuYWwvbXV4L211eGZ1bmMuZ28=) | `9.09% <0.00%> (-63.64%)` | :arrow_down: |
| [icemux.go](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-aWNlbXV4Lmdv) | `0.00% <0.00%> (-54.55%)` | :arrow_down: |
| [atomicbool.go](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-YXRvbWljYm9vbC5nbw==) | `57.14% <0.00%> (-42.86%)` | :arrow_down: |
| [sdpsemantics.go](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-c2Rwc2VtYW50aWNzLmdv) | `0.00% <0.00%> (-34.49%)` | :arrow_down: |
| ... and [38 more](https://codecov.io/gh/pion/webrtc/pull/2112/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pion/webrtc/pull/2112?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pion/webrtc/pull/2112?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion). Last update [8796a5c...99bec0f](https://codecov.io/gh/pion/webrtc/pull/2112?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion).

Sean-Der: I am sorry this didn't get merged sooner @wawesomeNOGUI this is a good change.

I am gonna fix up and merge now.
wawesomeNOGUI: @Sean-Der No worries! Sorry I uploaded all those commits in such a messy way:P

Patch:
diff --git a/sctptransport.go b/sctptransport.go
index c96fd173..f2f33e4b 100644
--- a/sctptransport.go
+++ b/sctptransport.go
@@ -362,9 +362,9 @@ func (r *SCTPTransport) State() SCTPTransportState {
 func (r *SCTPTransport) collectStats(collector *statsReportCollector) {
 	collector.Collecting()
 
-	stats := TransportStats{
+	stats := SCTPTransportStats{
 		Timestamp: statsTimestampFrom(time.Now()),
-		Type:      StatsTypeTransport,
+		Type:      StatsTypeSCTPTransport,
 		ID:        "sctpTransport",
 	}
 
@@ -372,6 +372,10 @@ func (r *SCTPTransport) collectStats(collector *statsReportCollector) {
 	if association != nil {
 		stats.BytesSent = association.BytesSent()
 		stats.BytesReceived = association.BytesReceived()
+		stats.SmoothedRoundTripTime = association.SRTT() * 0.001 // convert milliseconds to seconds
+		stats.CongestionWindow = association.CWND()
+		stats.ReceiverWindow = association.RWND()
+		stats.MTU = association.MTU()
 	}
 
 	collector.Collect(stats.ID, stats)
diff --git a/stats.go b/stats.go
index 3d17fd6b..35cbea5b 100644
--- a/stats.go
+++ b/stats.go
@@ -67,6 +67,8 @@ func UnmarshalStatsJSON(b []byte) (Stats, error) {
 		return unmarshalICECandidateStats(b)
 	case StatsTypeCertificate:
 		return unmarshalCertificateStats(b)
+	case StatsTypeSCTPTransport:
+		return unmarshalSCTPTransportStats(b)
 	default:
 		return nil, fmt.Errorf("type: %w", ErrUnknownType)
 	}
@@ -132,6 +134,9 @@ const (
 
 	// StatsTypeCertificate is used by CertificateStats.
 	StatsTypeCertificate StatsType = "certificate"
+
+	// StatsTypeSCTPTransport is used by SCTPTransportStats
+	StatsTypeSCTPTransport StatsType = "sctp-transport"
 )
 
 // MediaKind indicates the kind of media (audio or video)
@@ -1980,3 +1985,53 @@ func unmarshalCertificateStats(b []byte) (CertificateStats, error) {
 	}
 	return certificateStats, nil
 }
+
+// SCTPTransportStats contains information about a certificate used by an SCTPTransport.
+type SCTPTransportStats struct {
+	// Timestamp is the timestamp associated with this object.
+	Timestamp StatsTimestamp `json:"timestamp"`
+
+	// Type is the object's StatsType
+	Type StatsType `json:"type"`
+
+	// ID is a unique id that is associated with the component inspected to produce
+	// this Stats object. Two Stats objects will have the same ID if they were produced
+	// by inspecting the same underlying object.
+	ID string `json:"id"`
+
+	// TransportID is the identifier of the object that was inspected to produce the
+	// RTCTransportStats for the DTLSTransport and ICETransport supporting the SCTP transport.
+	TransportID string `json:"transportId"`
+
+	// SmoothedRoundTripTime is the latest smoothed round-trip time value, corresponding to spinfo_srtt defined in [RFC6458]
+	// but converted to seconds. If there has been no round-trip time measurements yet, this value is undefined.
+	SmoothedRoundTripTime float64 `json:"smoothedRoundTripTime"`
+
+	// CongestionWindow is the latest congestion window, corresponding to spinfo_cwnd defined in [RFC6458].
+	CongestionWindow uint32 `json:"congestionWindow"`
+
+	// ReceiverWindow is the latest receiver window, corresponding to sstat_rwnd defined in [RFC6458].
+	ReceiverWindow uint32 `json:"receiverWindow"`
+
+	// MTU is the latest maximum transmission unit, corresponding to spinfo_mtu defined in [RFC6458].
+	MTU uint32 `json:"mtu"`
+
+	// UNACKData is the number of unacknowledged DATA chunks, corresponding to sstat_unackdata defined in [RFC6458].
+	UNACKData uint32 `json:"unackData"`
+
+	// BytesSent represents the total number of bytes sent on this SCTPTransport
+	BytesSent uint64 `json:"bytesSent"`
+
+	// BytesReceived represents the total number of bytes received on this SCTPTransport
+	BytesReceived uint64 `json:"bytesReceived"`
+}
+
+func (s SCTPTransportStats) statsMarker() {}
+
+func unmarshalSCTPTransportStats(b []byte) (SCTPTransportStats, error) {
+	var sctpTransportStats SCTPTransportStats
+	if err := json.Unmarshal(b, &sctpTransportStats); err != nil {
+		return SCTPTransportStats{}, fmt.Errorf("unmarshal sctp transport stats: %w", err)
+	}
+	return sctpTransportStats, nil
+}


Test patch:
diff --git a/stats_go_test.go b/stats_go_test.go
index 6e716c5f..45375da7 100644
--- a/stats_go_test.go
+++ b/stats_go_test.go
@@ -1069,6 +1069,15 @@ func getTransportStats(t *testing.T, report StatsReport, statsID string) Transpo
 	return transportStats
 }
 
+func getSctpTransportStats(t *testing.T, report StatsReport) SCTPTransportStats {
+	stats, ok := report["sctpTransport"]
+	assert.True(t, ok)
+	transportStats, ok := stats.(SCTPTransportStats)
+	assert.True(t, ok)
+	assert.Equal(t, transportStats.Type, StatsTypeSCTPTransport)
+	return transportStats
+}
+
 func getCertificateStats(t *testing.T, report StatsReport, certificate *Certificate) CertificateStats {
 	certificateStats, ok := report.GetCertificateStats(certificate)
 	assert.True(t, ok)
@@ -1314,8 +1323,8 @@ func TestPeerConnection_GetStats(t *testing.T) {
 	assert.GreaterOrEqual(t, offerICETransportStats.BytesSent, answerICETransportStats.BytesReceived)
 	assert.GreaterOrEqual(t, answerICETransportStats.BytesSent, offerICETransportStats.BytesReceived)
 
-	answerSCTPTransportStats := getTransportStats(t, reportPCAnswer, "sctpTransport")
-	offerSCTPTransportStats := getTransportStats(t, reportPCOffer, "sctpTransport")
+	answerSCTPTransportStats := getSctpTransportStats(t, reportPCAnswer)
+	offerSCTPTransportStats := getSctpTransportStats(t, reportPCOffer)
 	assert.GreaterOrEqual(t, offerSCTPTransportStats.BytesSent, answerSCTPTransportStats.BytesReceived)
 	assert.GreaterOrEqual(t, answerSCTPTransportStats.BytesSent, offerSCTPTransportStats.BytesReceived)