Repository: pion/webrtc
Pull request #2086 (2022-01-14 16:56:08)

Add ability to set RTP stream ID on TrackLocal
This change makes it possible to set the RTP stream ID to
allow forwarding and production of simulcast streams.


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

[![Impacted file tree graph](https://codecov.io/gh/pion/webrtc/pull/2086/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/2086?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion)

```diff
@@            Coverage Diff             @@
##           master    #2086      +/-   ##
==========================================
- Coverage   76.80%   70.22%   -6.58%     
==========================================
  Files          85       62      -23     
  Lines        8721     3231    -5490     
==========================================
- Hits         6698     2269    -4429     
+ Misses       1613      846     -767     
+ Partials      410      116     -294     
```

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

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/2086?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) | Coverage Δ | |
|---|---|---|
| [track\_local.go](https://codecov.io/gh/pion/webrtc/pull/2086/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% <ø> (-80.00%)` | :arrow_down: |
| [constants.go](https://codecov.io/gh/pion/webrtc/pull/2086/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/2086/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/2086/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: |
| [stats.go](https://codecov.io/gh/pion/webrtc/pull/2086/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% <0.00%> (-75.00%)` | :arrow_down: |
| [internal/mux/muxfunc.go](https://codecov.io/gh/pion/webrtc/pull/2086/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/2086/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/2086/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/2086/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/2086/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/2086?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/2086?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion). Last update [7004fbb...faee71e](https://codecov.io/gh/pion/webrtc/pull/2086?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).


Patch:
diff --git a/rtpsender.go b/rtpsender.go
index 80a4b72c..7319cf84 100644
--- a/rtpsender.go
+++ b/rtpsender.go
@@ -1,3 +1,4 @@
+//go:build !js
 // +build !js
 
 package webrtc
@@ -107,6 +108,10 @@ func (r *RTPSender) Transport() *DTLSTransport {
 }
 
 func (r *RTPSender) getParameters() RTPSendParameters {
+	var rid string
+	if r.track != nil {
+		rid = r.track.RID()
+	}
 	sendParameters := RTPSendParameters{
 		RTPParameters: r.api.mediaEngine.getRTPParametersByKind(
 			r.kind,
@@ -115,6 +120,7 @@ func (r *RTPSender) getParameters() RTPSendParameters {
 		Encodings: []RTPEncodingParameters{
 			{
 				RTPCodingParameters: RTPCodingParameters{
+					RID:         rid,
 					SSRC:        r.ssrc,
 					PayloadType: r.payloadType,
 				},
diff --git a/track_local.go b/track_local.go
index 42134afb..0002e609 100644
--- a/track_local.go
+++ b/track_local.go
@@ -67,6 +67,9 @@ type TrackLocal interface {
 	// and StreamID would be 'desktop' or 'webcam'
 	ID() string
 
+	// RID is the RTP Stream ID for this track.
+	RID() string
+
 	// StreamID is the group this track belongs too. This must be unique
 	StreamID() string
 
diff --git a/track_local_static.go b/track_local_static.go
index 4275eb85..f1ca8b9e 100644
--- a/track_local_static.go
+++ b/track_local_static.go
@@ -1,3 +1,4 @@
+//go:build !js
 // +build !js
 
 package webrtc
@@ -24,20 +25,33 @@ type trackBinding struct {
 // TrackLocalStaticRTP  is a TrackLocal that has a pre-set codec and accepts RTP Packets.
 // If you wish to send a media.Sample use TrackLocalStaticSample
 type TrackLocalStaticRTP struct {
-	mu           sync.RWMutex
-	bindings     []trackBinding
-	codec        RTPCodecCapability
-	id, streamID string
+	mu                sync.RWMutex
+	bindings          []trackBinding
+	codec             RTPCodecCapability
+	id, rid, streamID string
 }
 
 // NewTrackLocalStaticRTP returns a TrackLocalStaticRTP.
-func NewTrackLocalStaticRTP(c RTPCodecCapability, id, streamID string) (*TrackLocalStaticRTP, error) {
-	return &TrackLocalStaticRTP{
+func NewTrackLocalStaticRTP(c RTPCodecCapability, id, streamID string, options ...func(*TrackLocalStaticRTP)) (*TrackLocalStaticRTP, error) {
+	t := &TrackLocalStaticRTP{
 		codec:    c,
 		bindings: []trackBinding{},
 		id:       id,
 		streamID: streamID,
-	}, nil
+	}
+
+	for _, option := range options {
+		option(t)
+	}
+
+	return t, nil
+}
+
+// WithRTPStreamID sets the RTP stream ID for this TrackLocalStaticRTP.
+func WithRTPStreamID(rid string) func(*TrackLocalStaticRTP) {
+	return func(t *TrackLocalStaticRTP) {
+		t.rid = rid
+	}
 }
 
 // Bind is called by the PeerConnection after negotiation is complete
@@ -86,6 +100,9 @@ func (s *TrackLocalStaticRTP) ID() string { return s.id }
 // StreamID is the group this track belongs too. This must be unique
 func (s *TrackLocalStaticRTP) StreamID() string { return s.streamID }
 
+// RID is the RTP stream identifier.
+func (s *TrackLocalStaticRTP) RID() string { return s.rid }
+
 // Kind controls if this TrackLocal is audio or video
 func (s *TrackLocalStaticRTP) Kind() RTPCodecType {
 	switch {
@@ -173,8 +190,8 @@ type TrackLocalStaticSample struct {
 }
 
 // NewTrackLocalStaticSample returns a TrackLocalStaticSample
-func NewTrackLocalStaticSample(c RTPCodecCapability, id, streamID string) (*TrackLocalStaticSample, error) {
-	rtpTrack, err := NewTrackLocalStaticRTP(c, id, streamID)
+func NewTrackLocalStaticSample(c RTPCodecCapability, id, streamID string, options ...func(*TrackLocalStaticRTP)) (*TrackLocalStaticSample, error) {
+	rtpTrack, err := NewTrackLocalStaticRTP(c, id, streamID, options...)
 	if err != nil {
 		return nil, err
 	}
@@ -192,6 +209,9 @@ func (s *TrackLocalStaticSample) ID() string { return s.rtpTrack.ID() }
 // StreamID is the group this track belongs too. This must be unique
 func (s *TrackLocalStaticSample) StreamID() string { return s.rtpTrack.StreamID() }
 
+// RID is the RTP stream identifier.
+func (s *TrackLocalStaticSample) RID() string { return s.rtpTrack.RID() }
+
 // Kind controls if this TrackLocal is audio or video
 func (s *TrackLocalStaticSample) Kind() RTPCodecType { return s.rtpTrack.Kind() }
 


Test patch:
diff --git a/rtpsender_test.go b/rtpsender_test.go
index 63e7e5fd..46749680 100644
--- a/rtpsender_test.go
+++ b/rtpsender_test.go
@@ -1,3 +1,4 @@
+//go:build !js
 // +build !js
 
 package webrtc
@@ -133,6 +134,34 @@ func Test_RTPSender_GetParameters(t *testing.T) {
 	assert.NotEqual(t, 0, len(parameters.Codecs))
 	assert.Equal(t, 1, len(parameters.Encodings))
 	assert.Equal(t, rtpTransceiver.Sender().ssrc, parameters.Encodings[0].SSRC)
+	assert.Equal(t, "", parameters.Encodings[0].RID)
+
+	closePairNow(t, offerer, answerer)
+}
+
+func Test_RTPSender_GetParameters_WithRID(t *testing.T) {
+	lim := test.TimeOut(time.Second * 10)
+	defer lim.Stop()
+
+	report := test.CheckRoutines(t)
+	defer report()
+
+	offerer, answerer, err := newPair()
+	assert.NoError(t, err)
+
+	rtpTransceiver, err := offerer.AddTransceiverFromKind(RTPCodecTypeVideo)
+	assert.NoError(t, err)
+
+	assert.NoError(t, signalPair(offerer, answerer))
+
+	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion", WithRTPStreamID("moo"))
+	assert.NoError(t, err)
+
+	err = rtpTransceiver.setSendingTrack(track)
+	assert.NoError(t, err)
+
+	parameters := rtpTransceiver.Sender().GetParameters()
+	assert.Equal(t, track.RID(), parameters.Encodings[0].RID)
 
 	closePairNow(t, offerer, answerer)
 }