Repository: pions/webrtc
Pull request #397 (2019-02-10 22:30:07)

Partial Reliability
Connect reliability parameter
Relates to #334
Note
* This branch depends on:
  - data@sctp-pr
  - sctp@sctp-pr
cc @backkem, @Sean-Der, @kc5nra 


enobufs: @backkem As you mentioned earlier, datachannel ID thing seems to have been correctly implemented already, so I will not touch that part.  Please review if I correctly wired the paramters with datachannel (dcep layer).
coveralls: ## Pull Request Test Coverage Report for [Build 1974](https://coveralls.io/builds/21558746)

* **72** of **84**   **(85.71%)**  changed or added relevant lines in **3** files are covered.
* **27** unchanged lines in **2** files lost coverage.
* Overall coverage decreased (**-0.4%**) to **79.297%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [rtcpeerconnection.go](https://coveralls.io/builds/21558746/source?filename=rtcpeerconnection.go#L1289) | 20 | 22 | 90.91%
| [rtcdatachannel.go](https://coveralls.io/builds/21558746/source?filename=rtcdatachannel.go#L165) | 29 | 32 | 90.63%
| [rtcsctptransport.go](https://coveralls.io/builds/21558746/source?filename=rtcsctptransport.go#L148) | 23 | 30 | 76.67%
<!-- | **Total:** | **72** | **84** | **85.71%** | -->

|  Files with Coverage Reduction | New Missed Lines | % |
| :-----|--------------|--: |
| [rtcdtlstransport.go](https://coveralls.io/builds/21558746/source?filename=rtcdtlstransport.go#L127) | 4 | 76.3% |
| [rtcpeerconnection.go](https://coveralls.io/builds/21558746/source?filename=rtcpeerconnection.go#L957) | 23 | 73.66% |
<!-- | **Total:** | **27** |  | -->

|  Totals | [![Coverage Status](https://coveralls.io/builds/21558746/badge)](https://coveralls.io/builds/21558746) |
| :-- | --: |
| Change from base [Build 1970](https://coveralls.io/builds/21553802): |  -0.4% |
| Covered Lines: | 3949 |
| Relevant Lines: | 4980 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/.gitignore b/.gitignore
index 5aebb07a..3f0acb4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,4 @@ vendor/
 *.ivf
 tags
 cover.out
+*.sw[poe]
diff --git a/datachannel.go b/datachannel.go
index 0f4e746c..f7d8c067 100644
--- a/datachannel.go
+++ b/datachannel.go
@@ -127,14 +127,15 @@ func (api *API) newDataChannel(params *DataChannelParameters) (*DataChannel, err
 		return nil, &rtcerr.TypeError{Err: ErrStringSizeLimit}
 	}
 
-	d := &DataChannel{
-		Label:      params.Label,
-		ID:         &params.ID,
-		ReadyState: DataChannelStateConnecting,
-		api:        api,
-	}
-
-	return d, nil
+	return &DataChannel{
+		Label:             params.Label,
+		ID:                &params.ID,
+		Ordered:           params.Ordered,
+		MaxPacketLifeTime: params.MaxPacketLifeTime,
+		MaxRetransmits:    params.MaxRetransmits,
+		ReadyState:        DataChannelStateConnecting,
+		api:               api,
+	}, nil
 }
 
 // open opens the datachannel over the sctp transport
@@ -147,10 +148,37 @@ func (d *DataChannel) open(sctpTransport *SCTPTransport) error {
 		return err
 	}
 
+	var channelType datachannel.ChannelType
+	var reliabilityParameteer uint32
+
+	switch {
+	case d.MaxPacketLifeTime == nil && d.MaxRetransmits == nil:
+		if d.Ordered {
+			channelType = datachannel.ChannelTypeReliable
+		} else {
+			channelType = datachannel.ChannelTypeReliableUnordered
+		}
+
+	case d.MaxRetransmits != nil:
+		reliabilityParameteer = uint32(*d.MaxRetransmits)
+		if d.Ordered {
+			channelType = datachannel.ChannelTypePartialReliableRexmit
+		} else {
+			channelType = datachannel.ChannelTypePartialReliableRexmitUnordered
+		}
+	default:
+		reliabilityParameteer = uint32(*d.MaxPacketLifeTime)
+		if d.Ordered {
+			channelType = datachannel.ChannelTypePartialReliableTimed
+		} else {
+			channelType = datachannel.ChannelTypePartialReliableTimedUnordered
+		}
+	}
+
 	cfg := &datachannel.Config{
-		ChannelType:          datachannel.ChannelTypeReliable,   // TODO: Wiring
+		ChannelType:          channelType,
 		Priority:             datachannel.ChannelPriorityNormal, // TODO: Wiring
-		ReliabilityParameter: 0,                                 // TODO: Wiring
+		ReliabilityParameter: reliabilityParameteer,
 		Label:                d.Label,
 	}
 
diff --git a/datachannelparameters.go b/datachannelparameters.go
index 8abec00a..dbf3dc9d 100644
--- a/datachannelparameters.go
+++ b/datachannelparameters.go
@@ -2,6 +2,9 @@ package webrtc
 
 // DataChannelParameters describes the configuration of the DataChannel.
 type DataChannelParameters struct {
-	Label string `json:"label"`
-	ID    uint16 `json:"id"`
+	Label             string  `json:"label"`
+	ID                uint16  `json:"id"`
+	Ordered           bool    `json:"ordered"`
+	MaxPacketLifeTime *uint16 `json:"maxPacketLifeTime"`
+	MaxRetransmits    *uint16 `json:"maxRetransmits"`
 }
diff --git a/go.mod b/go.mod
index 1fbc1b1c..a50757e1 100644
--- a/go.mod
+++ b/go.mod
@@ -5,11 +5,11 @@ require (
 	github.com/pions/dtls v1.2.1
 	github.com/pions/rtcp v1.0.0
 	github.com/pions/rtp v1.0.0
-	github.com/pions/sctp v1.3.1
 	github.com/pions/sdp/v2 v2.0.0
+	github.com/pions/sctp v1.4.0
 	github.com/pions/srtp v1.0.3
 	github.com/pions/stun v0.2.0
-	github.com/pions/transport v0.1.0
+	github.com/pions/transport v0.2.0
 	github.com/pkg/errors v0.8.1
 )
 
diff --git a/go.sum b/go.sum
index 1a38f7c6..73a8804e 100644
--- a/go.sum
+++ b/go.sum
@@ -29,11 +29,11 @@ github.com/pions/rtcp v1.0.0 h1:kYGe6RegZ63yVDkqXaru1+kHZAqHEufP3zfRAGKPycI=
 github.com/pions/rtcp v1.0.0/go.mod h1:Q5twXlqiz775Yn37X0cl4lAsfSk8EiHgeNkte59jBY4=
 github.com/pions/rtp v1.0.0 h1:H/TUg7bhgBT/mQsUx0adW3cmgwqPmygoYbbRTc3Y7Ek=
 github.com/pions/rtp v1.0.0/go.mod h1:GDIt4UYlSz7za4vfaLqihGJJ+yLvgPshnqrF/lm3vcM=
-github.com/pions/sctp v1.3.0/go.mod h1:GZTG/xApE7wdUFEQq2Rmzgxl/+YaB/L1k8xUl1D5bmo=
-github.com/pions/sctp v1.3.1 h1:V5cRHMt+G9ufc44ITZvcEj7/nUyDukkB3Qr08TT29k4=
-github.com/pions/sctp v1.3.1/go.mod h1:GZTG/xApE7wdUFEQq2Rmzgxl/+YaB/L1k8xUl1D5bmo=
 github.com/pions/sdp/v2 v2.0.0 h1:tWh8ehKPtXTaFYF12sBAHqYmhV36Q7YTmm3O6ycNa6M=
 github.com/pions/sdp/v2 v2.0.0/go.mod h1:KGRBcHfpkgJXjrzKJz2wj/Jf1KWnsHdoIiqtayQ5QmE=
+github.com/pions/sctp v1.3.0/go.mod h1:GZTG/xApE7wdUFEQq2Rmzgxl/+YaB/L1k8xUl1D5bmo=
+github.com/pions/sctp v1.4.0 h1:U8SAVk+nWa2248SZGHCYsNyOqe/DM5+TKOAlh9Qdw8c=
+github.com/pions/sctp v1.4.0/go.mod h1:dAna+Ct/aIIFiGW45yhGzuQjULWD7ni1vjoKHa9DsyU=
 github.com/pions/srtp v1.0.3 h1:0rlg7yUHQblFA1e451mhx50IkA7+e48ja5K8mljyMYY=
 github.com/pions/srtp v1.0.3/go.mod h1:egXe0STDyQDXLm7hjOMzuk7rkAhJ1SHOx+tTgtw/cQs=
 github.com/pions/stun v0.2.0 h1:spIzpfkEg6HV+2iIo6qeOsAjtadZKzbXbrd2e9ZCCcs=
@@ -41,6 +41,8 @@ github.com/pions/stun v0.2.0/go.mod h1:rMdCIsqqnTLC4MOHJE3LNiFQRfIjUDzI1kzx//7oP
 github.com/pions/transport v0.0.0-20190110151433-e7cbf7d5f464/go.mod h1:HLhzI7I0k8TyiQ99hfRZNRf84lG76eaFnZHnVy/wFnM=
 github.com/pions/transport v0.1.0 h1:9IEn3i8pmK8rMyQIqhT2RozgXJNH4k+IuNDzV5y+ddw=
 github.com/pions/transport v0.1.0/go.mod h1:HLhzI7I0k8TyiQ99hfRZNRf84lG76eaFnZHnVy/wFnM=
+github.com/pions/transport v0.2.0 h1:e3B5V7rATCNCxl0qlU0S0ofpt1E77X5pCbeUVQ0ntpA=
+github.com/pions/transport v0.2.0/go.mod h1:HLhzI7I0k8TyiQ99hfRZNRf84lG76eaFnZHnVy/wFnM=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
diff --git a/peerconnection.go b/peerconnection.go
index b948b746..d7b0a2da 100644
--- a/peerconnection.go
+++ b/peerconnection.go
@@ -1128,10 +1128,6 @@ func (pc *PeerConnection) AddTrack(track *Track) (*RTPSender, error) {
 // 	panic("not implemented yet") // FIXME NOT-IMPLEMENTED nolint
 // }
 
-// ------------------------------------------------------------------------
-// --- FIXME - BELOW CODE NEEDS RE-ORGANIZATION - https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api
-// ------------------------------------------------------------------------
-
 // CreateDataChannel creates a new DataChannel object with the given label
 // and optional DataChannelInit used to configure properties of the
 // underlying channel such as data reliability.
@@ -1145,12 +1141,12 @@ func (pc *PeerConnection) CreateDataChannel(label string, options *DataChannelIn
 	// implements all options. DataChannelParameters implements the
 	// options that actually have an effect at this point.
 	params := &DataChannelParameters{
-		Label: label,
+		Label:   label,
+		Ordered: true,
 	}
 
 	// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #19)
-	if options == nil ||
-		options.ID == nil {
+	if options == nil || options.ID == nil {
 		var err error
 		if params.ID, err = pc.generateDataChannelID(true); err != nil {
 			return nil, err
@@ -1159,100 +1155,46 @@ func (pc *PeerConnection) CreateDataChannel(label string, options *DataChannelIn
 		params.ID = *options.ID
 	}
 
-	// TODO: Re-enable validation of the parameters once they are implemented.
-	/*
-		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #3)
-		// Some variables defined explicitly despite their implicit zero values to
-		// allow better readability to understand what is happening. Additionally,
-		// some members are set to a non zero value default due to the default
-		// definitions in https://w3c.github.io/webrtc-pc/#dom-rtcdatachannelinit
-		// which are later overwriten by the options if any were specified.
-		channel := DataChannel{
-			rtcPeerConnection: pc,
-			// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #4)
-			Label:             label,
-			Ordered:           true,
-			MaxPacketLifeTime: nil,
-			MaxRetransmits:    nil,
-			Protocol:          "",
-			Negotiated:        false,
-			ID:                nil,
-			Priority:          PriorityTypeLow,
-			// https://w3c.github.io/webrtc-pc/#dfn-create-an-rtcdatachannel (Step #3)
-			BufferedAmount: 0,
-		}
-
-		if options != nil {
-			// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #7)
-			if options.MaxPacketLifeTime != nil {
-				channel.MaxPacketLifeTime = options.MaxPacketLifeTime
-			}
-
-			// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #8)
-			if options.MaxRetransmits != nil {
-				channel.MaxRetransmits = options.MaxRetransmits
-			}
-
-			// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #9)
-			if options.Ordered != nil {
-				channel.Ordered = *options.Ordered
-			}
-
-			// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #10)
-			if options.Protocol != nil {
-				channel.Protocol = *options.Protocol
-			}
-
-			// https://w3c.github.io/webrtc-pc/#peer-to-peer-da	ta-api (Step #12)
-			if options.Negotiated != nil {
-				channel.Negotiated = *options.Negotiated
-			}
-
-			// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #13)
-			if options.ID != nil && channel.Negotiated {
-				channel.ID = options.ID
-			}
-
-			// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #15)
-			if options.Priority != nil {
-				channel.Priority = *options.Priority
-			}
+	if options != nil {
+		// Ordered indicates if data is allowed to be delivered out of order. The
+		// default value of true, guarantees that data will be delivered in order.
+		if options.Ordered != nil {
+			params.Ordered = *options.Ordered
 		}
 
-		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #11)
-		if len(channel.Protocol) > 65535 {
-			return nil, &rtcerr.TypeError{Err: ErrStringSizeLimit}
+		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #7)
+		if options.MaxPacketLifeTime != nil {
+			params.MaxPacketLifeTime = options.MaxPacketLifeTime
 		}
 
-		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #14)
-		if channel.Negotiated && channel.ID == nil {
-			return nil, &rtcerr.TypeError{Err: ErrNegotiatedWithoutID}
+		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #8)
+		if options.MaxRetransmits != nil {
+			params.MaxRetransmits = options.MaxRetransmits
 		}
 
-		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #16)
-		if channel.MaxPacketLifeTime != nil && channel.MaxRetransmits != nil {
-			return nil, &rtcerr.TypeError{Err: ErrRetransmitsOrPacketLifeTime}
-		}
-
-		// FIXME https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-createdatachannel (Step #17)
-
-
-		// // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #18)
-		if *channel.ID > 65534 {
-			return nil, &rtcerr.TypeError{Err: ErrMaxDataChannelID}
+		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #9)
+		if options.Ordered != nil {
+			params.Ordered = *options.Ordered
 		}
+	}
 
-		if pc.sctpTransport.State == SCTPTransportStateConnected &&
-			*channel.ID >= *pc.sctpTransport.MaxChannels {
-			return nil, &rtcerr.OperationError{Err: ErrMaxDataChannelID}
-		}
-	*/
+	// TODO: Enable validation of other parameters once they are implemented.
+	// - Protocol
+	// - Negotiated
+	// - Priority:
+	//
+	// See https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api for details
 
 	d, err := pc.api.newDataChannel(params)
 	if err != nil {
 		return nil, err
 	}
 
+	// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #16)
+	if d.MaxPacketLifeTime != nil && d.MaxRetransmits != nil {
+		return nil, &rtcerr.TypeError{Err: ErrRetransmitsOrPacketLifeTime}
+	}
+
 	// Remember datachannel
 	pc.dataChannels[params.ID] = d
 
diff --git a/sctptransport.go b/sctptransport.go
index e57efa55..f4bdf5d2 100644
--- a/sctptransport.go
+++ b/sctptransport.go
@@ -135,12 +135,40 @@ func (r *SCTPTransport) acceptDataChannels() {
 			return
 		}
 
+		var ordered = true
+		var maxRetransmits *uint16
+		var maxPacketLifeTime *uint16
+		var val = uint16(dc.Config.ReliabilityParameter)
+
+		switch dc.Config.ChannelType {
+		case datachannel.ChannelTypeReliable:
+			ordered = true
+		case datachannel.ChannelTypeReliableUnordered:
+			ordered = false
+		case datachannel.ChannelTypePartialReliableRexmit:
+			ordered = true
+			maxRetransmits = &val
+		case datachannel.ChannelTypePartialReliableRexmitUnordered:
+			ordered = false
+			maxRetransmits = &val
+		case datachannel.ChannelTypePartialReliableTimed:
+			ordered = true
+			maxPacketLifeTime = &val
+		case datachannel.ChannelTypePartialReliableTimedUnordered:
+			ordered = false
+			maxPacketLifeTime = &val
+		default:
+		}
+
 		sid := dc.StreamIdentifier()
 		rtcDC := &DataChannel{
-			ID:         &sid,
-			Label:      dc.Config.Label,
-			ReadyState: DataChannelStateOpen,
-			api:        r.api,
+			ID:                &sid,
+			Label:             dc.Config.Label,
+			Ordered:           ordered,
+			MaxPacketLifeTime: maxPacketLifeTime,
+			MaxRetransmits:    maxRetransmits,
+			ReadyState:        DataChannelStateOpen,
+			api:               r.api,
 		}
 
 		<-r.onDataChannel(rtcDC)


Test patch:
diff --git a/datachannel_test.go b/datachannel_test.go
index f9016bdc..751d2504 100644
--- a/datachannel_test.go
+++ b/datachannel_test.go
@@ -3,6 +3,7 @@ package webrtc
 import (
 	"crypto/rand"
 	"encoding/binary"
+	"io"
 	"math/big"
 	"testing"
 	"time"
@@ -13,6 +14,23 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+func closePair(t *testing.T, pc1, pc2 io.Closer, done chan bool) {
+	var err error
+	select {
+	case <-time.After(10 * time.Second):
+		t.Fatalf("Datachannel Send Test Timeout")
+	case <-done:
+		err = pc1.Close()
+		if err != nil {
+			t.Fatalf("Failed to close offer PC")
+		}
+		err = pc2.Close()
+		if err != nil {
+			t.Fatalf("Failed to close answer PC")
+		}
+	}
+}
+
 func TestGenerateDataChannelID(t *testing.T) {
 	api := NewAPI()
 
@@ -64,6 +82,8 @@ func TestDataChannel_Send(t *testing.T) {
 		t.Fatalf("Failed to create a PC pair for testing")
 	}
 
+	assert.True(t, dc.Ordered, "Ordered should be set to true")
+
 	dc.OnOpen(func() {
 		e := dc.Send(sugar.PayloadString{Data: []byte("Ping")})
 		if e != nil {
@@ -75,6 +95,8 @@ func TestDataChannel_Send(t *testing.T) {
 	})
 
 	answerPC.OnDataChannel(func(d *DataChannel) {
+		assert.True(t, d.Ordered, "Ordered should be set to true")
+
 		d.OnMessage(func(payload sugar.Payload) {
 			e := d.Send(sugar.PayloadBinary{Data: []byte("Pong")})
 			if e != nil {
@@ -89,19 +111,7 @@ func TestDataChannel_Send(t *testing.T) {
 		t.Fatalf("Failed to signal our PC pair for testing")
 	}
 
-	select {
-	case <-time.After(10 * time.Second):
-		t.Fatalf("Datachannel Send Test Timeout")
-	case <-done:
-		err = offerPC.Close()
-		if err != nil {
-			t.Fatalf("Failed to close offer PC")
-		}
-		err = answerPC.Close()
-		if err != nil {
-			t.Fatalf("Failed to close answer PC")
-		}
-	}
+	closePair(t, offerPC, answerPC, done)
 }
 
 func TestDataChannel_EventHandlers(t *testing.T) {
@@ -210,3 +220,89 @@ func TestDataChannel_MessagesAreOrdered(t *testing.T) {
 	}
 	assert.EqualValues(t, expected, values)
 }
+
+func setUpReliabilityParamTest(t *testing.T, options *DataChannelInit) (*PeerConnection, *PeerConnection, *DataChannel, chan bool) {
+	api := NewAPI()
+	offerPC, answerPC, err := api.newPair()
+	if err != nil {
+		t.Fatalf("Failed to create a PC pair for testing")
+	}
+	done := make(chan bool)
+
+	dc, err := offerPC.CreateDataChannel("data", options)
+	if err != nil {
+		t.Fatalf("Failed to create a PC pair for testing")
+	}
+
+	return offerPC, answerPC, dc, done
+}
+
+func closeReliabilityParamTest(t *testing.T, pc1, pc2 *PeerConnection, done chan bool) {
+	err := signalPair(pc1, pc2)
+	if err != nil {
+		t.Fatalf("Failed to signal our PC pair for testing")
+	}
+
+	closePair(t, pc1, pc2, done)
+}
+
+func TestDataChannelParamters(t *testing.T) {
+	report := test.CheckRoutines(t)
+	defer report()
+
+	t.Run("MaxPacketLifeTime exchange", func(t *testing.T) {
+		var ordered = true
+		var maxPacketLifeTime uint16 = 3
+		options := &DataChannelInit{
+			Ordered:           &ordered,
+			MaxPacketLifeTime: &maxPacketLifeTime,
+		}
+
+		offerPC, answerPC, dc, done := setUpReliabilityParamTest(t, options)
+
+		// Check if parameters are correctly set
+		assert.True(t, dc.Ordered, "Ordered should be set to true")
+		if assert.NotNil(t, dc.MaxPacketLifeTime, "should not be nil") {
+			assert.Equal(t, maxPacketLifeTime, *dc.MaxPacketLifeTime, "should match")
+		}
+
+		answerPC.OnDataChannel(func(d *DataChannel) {
+			// Check if parameters are correctly set
+			assert.True(t, d.Ordered, "Ordered should be set to true")
+			if assert.NotNil(t, d.MaxPacketLifeTime, "should not be nil") {
+				assert.Equal(t, maxPacketLifeTime, *d.MaxPacketLifeTime, "should match")
+			}
+			done <- true
+		})
+
+		closeReliabilityParamTest(t, offerPC, answerPC, done)
+	})
+
+	t.Run("MaxRetransmits exchange", func(t *testing.T) {
+		var ordered = false
+		var maxRetransmits uint16 = 3000
+		options := &DataChannelInit{
+			Ordered:        &ordered,
+			MaxRetransmits: &maxRetransmits,
+		}
+
+		offerPC, answerPC, dc, done := setUpReliabilityParamTest(t, options)
+
+		// Check if parameters are correctly set
+		assert.False(t, dc.Ordered, "Ordered should be set to false")
+		if assert.NotNil(t, dc.MaxRetransmits, "should not be nil") {
+			assert.Equal(t, maxRetransmits, *dc.MaxRetransmits, "should match")
+		}
+
+		answerPC.OnDataChannel(func(d *DataChannel) {
+			// Check if parameters are correctly set
+			assert.False(t, d.Ordered, "Ordered should be set to false")
+			if assert.NotNil(t, d.MaxRetransmits, "should not be nil") {
+				assert.Equal(t, maxRetransmits, *d.MaxRetransmits, "should match")
+			}
+			done <- true
+		})
+
+		closeReliabilityParamTest(t, offerPC, answerPC, done)
+	})
+}