github.com/pion/webrtc/v4@v4.0.1/datachannel.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  //go:build !js
     5  // +build !js
     6  
     7  package webrtc
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"math"
    14  	"sync"
    15  	"sync/atomic"
    16  	"time"
    17  
    18  	"github.com/pion/datachannel"
    19  	"github.com/pion/logging"
    20  	"github.com/pion/webrtc/v4/pkg/rtcerr"
    21  )
    22  
    23  const dataChannelBufferSize = math.MaxUint16 // message size limit for Chromium
    24  var errSCTPNotEstablished = errors.New("SCTP not established")
    25  
    26  // DataChannel represents a WebRTC DataChannel
    27  // The DataChannel interface represents a network channel
    28  // which can be used for bidirectional peer-to-peer transfers of arbitrary data
    29  type DataChannel struct {
    30  	mu sync.RWMutex
    31  
    32  	statsID                    string
    33  	label                      string
    34  	ordered                    bool
    35  	maxPacketLifeTime          *uint16
    36  	maxRetransmits             *uint16
    37  	protocol                   string
    38  	negotiated                 bool
    39  	id                         *uint16
    40  	readyState                 atomic.Value // DataChannelState
    41  	bufferedAmountLowThreshold uint64
    42  	detachCalled               bool
    43  	readLoopActive             chan struct{}
    44  	isGracefulClosed           bool
    45  
    46  	// The binaryType represents attribute MUST, on getting, return the value to
    47  	// which it was last set. On setting, if the new value is either the string
    48  	// "blob" or the string "arraybuffer", then set the IDL attribute to this
    49  	// new value. Otherwise, throw a SyntaxError. When an DataChannel object
    50  	// is created, the binaryType attribute MUST be initialized to the string
    51  	// "blob". This attribute controls how binary data is exposed to scripts.
    52  	// binaryType                 string
    53  
    54  	onMessageHandler    func(DataChannelMessage)
    55  	openHandlerOnce     sync.Once
    56  	onOpenHandler       func()
    57  	dialHandlerOnce     sync.Once
    58  	onDialHandler       func()
    59  	onCloseHandler      func()
    60  	onBufferedAmountLow func()
    61  	onErrorHandler      func(error)
    62  
    63  	sctpTransport *SCTPTransport
    64  	dataChannel   *datachannel.DataChannel
    65  
    66  	// A reference to the associated api object used by this datachannel
    67  	api *API
    68  	log logging.LeveledLogger
    69  }
    70  
    71  // NewDataChannel creates a new DataChannel.
    72  // This constructor is part of the ORTC API. It is not
    73  // meant to be used together with the basic WebRTC API.
    74  func (api *API) NewDataChannel(transport *SCTPTransport, params *DataChannelParameters) (*DataChannel, error) {
    75  	d, err := api.newDataChannel(params, nil, api.settingEngine.LoggerFactory.NewLogger("ortc"))
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	err = d.open(transport)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	return d, nil
    86  }
    87  
    88  // newDataChannel is an internal constructor for the data channel used to
    89  // create the DataChannel object before the networking is set up.
    90  func (api *API) newDataChannel(params *DataChannelParameters, sctpTransport *SCTPTransport, log logging.LeveledLogger) (*DataChannel, error) {
    91  	// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #5)
    92  	if len(params.Label) > 65535 {
    93  		return nil, &rtcerr.TypeError{Err: ErrStringSizeLimit}
    94  	}
    95  
    96  	d := &DataChannel{
    97  		sctpTransport:     sctpTransport,
    98  		statsID:           fmt.Sprintf("DataChannel-%d", time.Now().UnixNano()),
    99  		label:             params.Label,
   100  		protocol:          params.Protocol,
   101  		negotiated:        params.Negotiated,
   102  		id:                params.ID,
   103  		ordered:           params.Ordered,
   104  		maxPacketLifeTime: params.MaxPacketLifeTime,
   105  		maxRetransmits:    params.MaxRetransmits,
   106  		api:               api,
   107  		log:               log,
   108  	}
   109  
   110  	d.setReadyState(DataChannelStateConnecting)
   111  	return d, nil
   112  }
   113  
   114  // open opens the datachannel over the sctp transport
   115  func (d *DataChannel) open(sctpTransport *SCTPTransport) error {
   116  	association := sctpTransport.association()
   117  	if association == nil {
   118  		return errSCTPNotEstablished
   119  	}
   120  
   121  	d.mu.Lock()
   122  	if d.sctpTransport != nil { // already open
   123  		d.mu.Unlock()
   124  		return nil
   125  	}
   126  	d.sctpTransport = sctpTransport
   127  	var channelType datachannel.ChannelType
   128  	var reliabilityParameter uint32
   129  
   130  	switch {
   131  	case d.maxPacketLifeTime == nil && d.maxRetransmits == nil:
   132  		if d.ordered {
   133  			channelType = datachannel.ChannelTypeReliable
   134  		} else {
   135  			channelType = datachannel.ChannelTypeReliableUnordered
   136  		}
   137  
   138  	case d.maxRetransmits != nil:
   139  		reliabilityParameter = uint32(*d.maxRetransmits)
   140  		if d.ordered {
   141  			channelType = datachannel.ChannelTypePartialReliableRexmit
   142  		} else {
   143  			channelType = datachannel.ChannelTypePartialReliableRexmitUnordered
   144  		}
   145  	default:
   146  		reliabilityParameter = uint32(*d.maxPacketLifeTime)
   147  		if d.ordered {
   148  			channelType = datachannel.ChannelTypePartialReliableTimed
   149  		} else {
   150  			channelType = datachannel.ChannelTypePartialReliableTimedUnordered
   151  		}
   152  	}
   153  
   154  	cfg := &datachannel.Config{
   155  		ChannelType:          channelType,
   156  		Priority:             datachannel.ChannelPriorityNormal,
   157  		ReliabilityParameter: reliabilityParameter,
   158  		Label:                d.label,
   159  		Protocol:             d.protocol,
   160  		Negotiated:           d.negotiated,
   161  		LoggerFactory:        d.api.settingEngine.LoggerFactory,
   162  	}
   163  
   164  	if d.id == nil {
   165  		// avoid holding lock when generating ID, since id generation locks
   166  		d.mu.Unlock()
   167  		var dcID *uint16
   168  		err := d.sctpTransport.generateAndSetDataChannelID(d.sctpTransport.dtlsTransport.role(), &dcID)
   169  		if err != nil {
   170  			return err
   171  		}
   172  		d.mu.Lock()
   173  		d.id = dcID
   174  	}
   175  	dc, err := datachannel.Dial(association, *d.id, cfg)
   176  	if err != nil {
   177  		d.mu.Unlock()
   178  		return err
   179  	}
   180  
   181  	// bufferedAmountLowThreshold and onBufferedAmountLow might be set earlier
   182  	dc.SetBufferedAmountLowThreshold(d.bufferedAmountLowThreshold)
   183  	dc.OnBufferedAmountLow(d.onBufferedAmountLow)
   184  	d.mu.Unlock()
   185  
   186  	d.onDial()
   187  	d.handleOpen(dc, false, d.negotiated)
   188  	return nil
   189  }
   190  
   191  // Transport returns the SCTPTransport instance the DataChannel is sending over.
   192  func (d *DataChannel) Transport() *SCTPTransport {
   193  	d.mu.RLock()
   194  	defer d.mu.RUnlock()
   195  
   196  	return d.sctpTransport
   197  }
   198  
   199  // After onOpen is complete check that the user called detach
   200  // and provide an error message if the call was missed
   201  func (d *DataChannel) checkDetachAfterOpen() {
   202  	d.mu.RLock()
   203  	defer d.mu.RUnlock()
   204  
   205  	if d.api.settingEngine.detach.DataChannels && !d.detachCalled {
   206  		d.log.Warn("webrtc.DetachDataChannels() enabled but didn't Detach, call Detach from OnOpen")
   207  	}
   208  }
   209  
   210  // OnOpen sets an event handler which is invoked when
   211  // the underlying data transport has been established (or re-established).
   212  func (d *DataChannel) OnOpen(f func()) {
   213  	d.mu.Lock()
   214  	d.openHandlerOnce = sync.Once{}
   215  	d.onOpenHandler = f
   216  	d.mu.Unlock()
   217  
   218  	if d.ReadyState() == DataChannelStateOpen {
   219  		// If the data channel is already open, call the handler immediately.
   220  		go d.openHandlerOnce.Do(func() {
   221  			f()
   222  			d.checkDetachAfterOpen()
   223  		})
   224  	}
   225  }
   226  
   227  func (d *DataChannel) onOpen() {
   228  	d.mu.RLock()
   229  	handler := d.onOpenHandler
   230  	if d.isGracefulClosed {
   231  		d.mu.RUnlock()
   232  		return
   233  	}
   234  	d.mu.RUnlock()
   235  
   236  	if handler != nil {
   237  		go d.openHandlerOnce.Do(func() {
   238  			handler()
   239  			d.checkDetachAfterOpen()
   240  		})
   241  	}
   242  }
   243  
   244  // OnDial sets an event handler which is invoked when the
   245  // peer has been dialed, but before said peer has responded
   246  func (d *DataChannel) OnDial(f func()) {
   247  	d.mu.Lock()
   248  	d.dialHandlerOnce = sync.Once{}
   249  	d.onDialHandler = f
   250  	d.mu.Unlock()
   251  
   252  	if d.ReadyState() == DataChannelStateOpen {
   253  		// If the data channel is already open, call the handler immediately.
   254  		go d.dialHandlerOnce.Do(f)
   255  	}
   256  }
   257  
   258  func (d *DataChannel) onDial() {
   259  	d.mu.RLock()
   260  	handler := d.onDialHandler
   261  	if d.isGracefulClosed {
   262  		d.mu.RUnlock()
   263  		return
   264  	}
   265  	d.mu.RUnlock()
   266  
   267  	if handler != nil {
   268  		go d.dialHandlerOnce.Do(handler)
   269  	}
   270  }
   271  
   272  // OnClose sets an event handler which is invoked when
   273  // the underlying data transport has been closed.
   274  // Note: Due to backwards compatibility, there is a chance that
   275  // OnClose can be called, even if the GracefulClose is used.
   276  // If this is the case for you, you can deregister OnClose
   277  // prior to GracefulClose.
   278  func (d *DataChannel) OnClose(f func()) {
   279  	d.mu.Lock()
   280  	defer d.mu.Unlock()
   281  	d.onCloseHandler = f
   282  }
   283  
   284  func (d *DataChannel) onClose() {
   285  	d.mu.RLock()
   286  	handler := d.onCloseHandler
   287  	d.mu.RUnlock()
   288  
   289  	if handler != nil {
   290  		go handler()
   291  	}
   292  }
   293  
   294  // OnMessage sets an event handler which is invoked on a binary
   295  // message arrival over the sctp transport from a remote peer.
   296  // OnMessage can currently receive messages up to 16384 bytes
   297  // in size. Check out the detach API if you want to use larger
   298  // message sizes. Note that browser support for larger messages
   299  // is also limited.
   300  func (d *DataChannel) OnMessage(f func(msg DataChannelMessage)) {
   301  	d.mu.Lock()
   302  	defer d.mu.Unlock()
   303  	d.onMessageHandler = f
   304  }
   305  
   306  func (d *DataChannel) onMessage(msg DataChannelMessage) {
   307  	d.mu.RLock()
   308  	handler := d.onMessageHandler
   309  	if d.isGracefulClosed {
   310  		d.mu.RUnlock()
   311  		return
   312  	}
   313  	d.mu.RUnlock()
   314  
   315  	if handler == nil {
   316  		return
   317  	}
   318  	handler(msg)
   319  }
   320  
   321  func (d *DataChannel) handleOpen(dc *datachannel.DataChannel, isRemote, isAlreadyNegotiated bool) {
   322  	d.mu.Lock()
   323  	if d.isGracefulClosed {
   324  		d.mu.Unlock()
   325  		return
   326  	}
   327  	d.dataChannel = dc
   328  	bufferedAmountLowThreshold := d.bufferedAmountLowThreshold
   329  	onBufferedAmountLow := d.onBufferedAmountLow
   330  	d.mu.Unlock()
   331  	d.setReadyState(DataChannelStateOpen)
   332  
   333  	// Fire the OnOpen handler immediately not using pion/datachannel
   334  	// * detached datachannels have no read loop, the user needs to read and query themselves
   335  	// * remote datachannels should fire OnOpened. This isn't spec compliant, but we can't break behavior yet
   336  	// * already negotiated datachannels should fire OnOpened
   337  	if d.api.settingEngine.detach.DataChannels || isRemote || isAlreadyNegotiated {
   338  		// bufferedAmountLowThreshold and onBufferedAmountLow might be set earlier
   339  		d.dataChannel.SetBufferedAmountLowThreshold(bufferedAmountLowThreshold)
   340  		d.dataChannel.OnBufferedAmountLow(onBufferedAmountLow)
   341  		d.onOpen()
   342  	} else {
   343  		dc.OnOpen(func() {
   344  			d.onOpen()
   345  		})
   346  	}
   347  
   348  	d.mu.Lock()
   349  	defer d.mu.Unlock()
   350  
   351  	if d.isGracefulClosed {
   352  		return
   353  	}
   354  
   355  	if !d.api.settingEngine.detach.DataChannels {
   356  		d.readLoopActive = make(chan struct{})
   357  		go d.readLoop()
   358  	}
   359  }
   360  
   361  // OnError sets an event handler which is invoked when
   362  // the underlying data transport cannot be read.
   363  func (d *DataChannel) OnError(f func(err error)) {
   364  	d.mu.Lock()
   365  	defer d.mu.Unlock()
   366  	d.onErrorHandler = f
   367  }
   368  
   369  func (d *DataChannel) onError(err error) {
   370  	d.mu.RLock()
   371  	handler := d.onErrorHandler
   372  	if d.isGracefulClosed {
   373  		d.mu.RUnlock()
   374  		return
   375  	}
   376  	d.mu.RUnlock()
   377  
   378  	if handler != nil {
   379  		go handler(err)
   380  	}
   381  }
   382  
   383  func (d *DataChannel) readLoop() {
   384  	defer func() {
   385  		d.mu.Lock()
   386  		readLoopActive := d.readLoopActive
   387  		d.mu.Unlock()
   388  		defer close(readLoopActive)
   389  	}()
   390  	buffer := make([]byte, dataChannelBufferSize)
   391  	for {
   392  		n, isString, err := d.dataChannel.ReadDataChannel(buffer)
   393  		if err != nil {
   394  			d.setReadyState(DataChannelStateClosed)
   395  			if !errors.Is(err, io.EOF) {
   396  				d.onError(err)
   397  			}
   398  			d.onClose()
   399  			return
   400  		}
   401  
   402  		m := DataChannelMessage{Data: make([]byte, n), IsString: isString}
   403  		copy(m.Data, buffer[:n])
   404  
   405  		// NB: Why was DataChannelMessage not passed as a pointer value?
   406  		d.onMessage(m) // nolint:staticcheck
   407  	}
   408  }
   409  
   410  // Send sends the binary message to the DataChannel peer
   411  func (d *DataChannel) Send(data []byte) error {
   412  	err := d.ensureOpen()
   413  	if err != nil {
   414  		return err
   415  	}
   416  
   417  	_, err = d.dataChannel.WriteDataChannel(data, false)
   418  	return err
   419  }
   420  
   421  // SendText sends the text message to the DataChannel peer
   422  func (d *DataChannel) SendText(s string) error {
   423  	err := d.ensureOpen()
   424  	if err != nil {
   425  		return err
   426  	}
   427  
   428  	_, err = d.dataChannel.WriteDataChannel([]byte(s), true)
   429  	return err
   430  }
   431  
   432  func (d *DataChannel) ensureOpen() error {
   433  	d.mu.RLock()
   434  	defer d.mu.RUnlock()
   435  	if d.ReadyState() != DataChannelStateOpen {
   436  		return io.ErrClosedPipe
   437  	}
   438  	return nil
   439  }
   440  
   441  // Detach allows you to detach the underlying datachannel. This provides
   442  // an idiomatic API to work with, however it disables the OnMessage callback.
   443  // Before calling Detach you have to enable this behavior by calling
   444  // webrtc.DetachDataChannels(). Combining detached and normal data channels
   445  // is not supported.
   446  // Please refer to the data-channels-detach example and the
   447  // pion/datachannel documentation for the correct way to handle the
   448  // resulting DataChannel object.
   449  func (d *DataChannel) Detach() (datachannel.ReadWriteCloser, error) {
   450  	d.mu.Lock()
   451  
   452  	if !d.api.settingEngine.detach.DataChannels {
   453  		return nil, errDetachNotEnabled
   454  	}
   455  
   456  	if d.dataChannel == nil {
   457  		return nil, errDetachBeforeOpened
   458  	}
   459  
   460  	d.detachCalled = true
   461  
   462  	dataChannel := d.dataChannel
   463  	d.mu.Unlock()
   464  
   465  	// Remove the reference from SCTPTransport so that the datachannel
   466  	// can be garbage collected on close
   467  	d.sctpTransport.lock.Lock()
   468  	n := len(d.sctpTransport.dataChannels)
   469  	j := 0
   470  	for i := 0; i < n; i++ {
   471  		if d == d.sctpTransport.dataChannels[i] {
   472  			continue
   473  		}
   474  		d.sctpTransport.dataChannels[j] = d.sctpTransport.dataChannels[i]
   475  		j++
   476  	}
   477  	for i := j; i < n; i++ {
   478  		d.sctpTransport.dataChannels[i] = nil
   479  	}
   480  	d.sctpTransport.dataChannels = d.sctpTransport.dataChannels[:j]
   481  	d.sctpTransport.lock.Unlock()
   482  
   483  	return dataChannel, nil
   484  }
   485  
   486  // Close Closes the DataChannel. It may be called regardless of whether
   487  // the DataChannel object was created by this peer or the remote peer.
   488  func (d *DataChannel) Close() error {
   489  	return d.close(false)
   490  }
   491  
   492  // GracefulClose Closes the DataChannel. It may be called regardless of whether
   493  // the DataChannel object was created by this peer or the remote peer. It also waits
   494  // for any goroutines it started to complete. This is only safe to call outside of
   495  // DataChannel callbacks or if in a callback, in its own goroutine.
   496  func (d *DataChannel) GracefulClose() error {
   497  	return d.close(true)
   498  }
   499  
   500  // Normally, close only stops writes from happening, so graceful=true
   501  // will wait for reads to be finished based on underlying SCTP association
   502  // closure or a SCTP reset stream from the other side. This is safe to call
   503  // with graceful=true after tearing down a PeerConnection but not
   504  // necessarily before. For example, if you used a vnet and dropped all packets
   505  // right before closing the DataChannel, you'd need never see a reset stream.
   506  func (d *DataChannel) close(shouldGracefullyClose bool) error {
   507  	d.mu.Lock()
   508  	d.isGracefulClosed = true
   509  	readLoopActive := d.readLoopActive
   510  	if shouldGracefullyClose && readLoopActive != nil {
   511  		defer func() {
   512  			<-readLoopActive
   513  		}()
   514  	}
   515  	haveSctpTransport := d.dataChannel != nil
   516  	d.mu.Unlock()
   517  
   518  	if d.ReadyState() == DataChannelStateClosed {
   519  		return nil
   520  	}
   521  
   522  	d.setReadyState(DataChannelStateClosing)
   523  	if !haveSctpTransport {
   524  		return nil
   525  	}
   526  
   527  	return d.dataChannel.Close()
   528  }
   529  
   530  // Label represents a label that can be used to distinguish this
   531  // DataChannel object from other DataChannel objects. Scripts are
   532  // allowed to create multiple DataChannel objects with the same label.
   533  func (d *DataChannel) Label() string {
   534  	d.mu.RLock()
   535  	defer d.mu.RUnlock()
   536  
   537  	return d.label
   538  }
   539  
   540  // Ordered returns true if the DataChannel is ordered, and false if
   541  // out-of-order delivery is allowed.
   542  func (d *DataChannel) Ordered() bool {
   543  	d.mu.RLock()
   544  	defer d.mu.RUnlock()
   545  
   546  	return d.ordered
   547  }
   548  
   549  // MaxPacketLifeTime represents the length of the time window (msec) during
   550  // which transmissions and retransmissions may occur in unreliable mode.
   551  func (d *DataChannel) MaxPacketLifeTime() *uint16 {
   552  	d.mu.RLock()
   553  	defer d.mu.RUnlock()
   554  
   555  	return d.maxPacketLifeTime
   556  }
   557  
   558  // MaxRetransmits represents the maximum number of retransmissions that are
   559  // attempted in unreliable mode.
   560  func (d *DataChannel) MaxRetransmits() *uint16 {
   561  	d.mu.RLock()
   562  	defer d.mu.RUnlock()
   563  
   564  	return d.maxRetransmits
   565  }
   566  
   567  // Protocol represents the name of the sub-protocol used with this
   568  // DataChannel.
   569  func (d *DataChannel) Protocol() string {
   570  	d.mu.RLock()
   571  	defer d.mu.RUnlock()
   572  
   573  	return d.protocol
   574  }
   575  
   576  // Negotiated represents whether this DataChannel was negotiated by the
   577  // application (true), or not (false).
   578  func (d *DataChannel) Negotiated() bool {
   579  	d.mu.RLock()
   580  	defer d.mu.RUnlock()
   581  
   582  	return d.negotiated
   583  }
   584  
   585  // ID represents the ID for this DataChannel. The value is initially
   586  // null, which is what will be returned if the ID was not provided at
   587  // channel creation time, and the DTLS role of the SCTP transport has not
   588  // yet been negotiated. Otherwise, it will return the ID that was either
   589  // selected by the script or generated. After the ID is set to a non-null
   590  // value, it will not change.
   591  func (d *DataChannel) ID() *uint16 {
   592  	d.mu.RLock()
   593  	defer d.mu.RUnlock()
   594  
   595  	return d.id
   596  }
   597  
   598  // ReadyState represents the state of the DataChannel object.
   599  func (d *DataChannel) ReadyState() DataChannelState {
   600  	if v, ok := d.readyState.Load().(DataChannelState); ok {
   601  		return v
   602  	}
   603  	return DataChannelState(0)
   604  }
   605  
   606  // BufferedAmount represents the number of bytes of application data
   607  // (UTF-8 text and binary data) that have been queued using send(). Even
   608  // though the data transmission can occur in parallel, the returned value
   609  // MUST NOT be decreased before the current task yielded back to the event
   610  // loop to prevent race conditions. The value does not include framing
   611  // overhead incurred by the protocol, or buffering done by the operating
   612  // system or network hardware. The value of BufferedAmount slot will only
   613  // increase with each call to the send() method as long as the ReadyState is
   614  // open; however, BufferedAmount does not reset to zero once the channel
   615  // closes.
   616  func (d *DataChannel) BufferedAmount() uint64 {
   617  	d.mu.RLock()
   618  	defer d.mu.RUnlock()
   619  
   620  	if d.dataChannel == nil {
   621  		return 0
   622  	}
   623  	return d.dataChannel.BufferedAmount()
   624  }
   625  
   626  // BufferedAmountLowThreshold represents the threshold at which the
   627  // bufferedAmount is considered to be low. When the bufferedAmount decreases
   628  // from above this threshold to equal or below it, the bufferedamountlow
   629  // event fires. BufferedAmountLowThreshold is initially zero on each new
   630  // DataChannel, but the application may change its value at any time.
   631  // The threshold is set to 0 by default.
   632  func (d *DataChannel) BufferedAmountLowThreshold() uint64 {
   633  	d.mu.RLock()
   634  	defer d.mu.RUnlock()
   635  
   636  	if d.dataChannel == nil {
   637  		return d.bufferedAmountLowThreshold
   638  	}
   639  	return d.dataChannel.BufferedAmountLowThreshold()
   640  }
   641  
   642  // SetBufferedAmountLowThreshold is used to update the threshold.
   643  // See BufferedAmountLowThreshold().
   644  func (d *DataChannel) SetBufferedAmountLowThreshold(th uint64) {
   645  	d.mu.Lock()
   646  	defer d.mu.Unlock()
   647  
   648  	d.bufferedAmountLowThreshold = th
   649  
   650  	if d.dataChannel != nil {
   651  		d.dataChannel.SetBufferedAmountLowThreshold(th)
   652  	}
   653  }
   654  
   655  // OnBufferedAmountLow sets an event handler which is invoked when
   656  // the number of bytes of outgoing data becomes lower than or equal to the
   657  // BufferedAmountLowThreshold.
   658  func (d *DataChannel) OnBufferedAmountLow(f func()) {
   659  	d.mu.Lock()
   660  	defer d.mu.Unlock()
   661  
   662  	d.onBufferedAmountLow = f
   663  	if d.dataChannel != nil {
   664  		d.dataChannel.OnBufferedAmountLow(f)
   665  	}
   666  }
   667  
   668  func (d *DataChannel) getStatsID() string {
   669  	d.mu.Lock()
   670  	defer d.mu.Unlock()
   671  	return d.statsID
   672  }
   673  
   674  func (d *DataChannel) collectStats(collector *statsReportCollector) {
   675  	collector.Collecting()
   676  
   677  	d.mu.Lock()
   678  	defer d.mu.Unlock()
   679  
   680  	stats := DataChannelStats{
   681  		Timestamp: statsTimestampNow(),
   682  		Type:      StatsTypeDataChannel,
   683  		ID:        d.statsID,
   684  		Label:     d.label,
   685  		Protocol:  d.protocol,
   686  		// TransportID string `json:"transportId"`
   687  		State: d.ReadyState(),
   688  	}
   689  
   690  	if d.id != nil {
   691  		stats.DataChannelIdentifier = int32(*d.id)
   692  	}
   693  
   694  	if d.dataChannel != nil {
   695  		stats.MessagesSent = d.dataChannel.MessagesSent()
   696  		stats.BytesSent = d.dataChannel.BytesSent()
   697  		stats.MessagesReceived = d.dataChannel.MessagesReceived()
   698  		stats.BytesReceived = d.dataChannel.BytesReceived()
   699  	}
   700  
   701  	collector.Collect(stats.ID, stats)
   702  }
   703  
   704  func (d *DataChannel) setReadyState(r DataChannelState) {
   705  	d.readyState.Store(r)
   706  }