mirror of
https://github.com/pion/webrtc.git
synced 2025-10-06 23:52:51 +08:00
154 lines
3.5 KiB
Go
154 lines
3.5 KiB
Go
package webrtc
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/pions/webrtc/pkg/datachannel"
|
|
)
|
|
|
|
// RTCDataChannel represents a WebRTC DataChannel
|
|
// The RTCDataChannel interface represents a network channel
|
|
// which can be used for bidirectional peer-to-peer transfers of arbitrary data
|
|
type RTCDataChannel struct {
|
|
sync.RWMutex
|
|
|
|
Onmessage func(datachannel.Payload)
|
|
ID uint16
|
|
Label string
|
|
|
|
rtcPeerConnection *RTCPeerConnection
|
|
}
|
|
|
|
// RTCPriorityType determines the priority of a data channel.
|
|
type RTCPriorityType int
|
|
|
|
const (
|
|
// RTCPriorityTypeVeryLow corresponds to "below normal"
|
|
RTCPriorityTypeVeryLow RTCPriorityType = iota + 1
|
|
|
|
// RTCPriorityTypeLow corresponds to "normal"
|
|
RTCPriorityTypeLow
|
|
|
|
// RTCPriorityTypeMedium corresponds to "high"
|
|
RTCPriorityTypeMedium
|
|
|
|
// RTCPriorityTypeHigh corresponds to "extra high"
|
|
RTCPriorityTypeHigh
|
|
)
|
|
|
|
func (p RTCPriorityType) String() string {
|
|
switch p {
|
|
case RTCPriorityTypeVeryLow:
|
|
return "very-low"
|
|
case RTCPriorityTypeLow:
|
|
return "low"
|
|
case RTCPriorityTypeMedium:
|
|
return "medium"
|
|
case RTCPriorityTypeHigh:
|
|
return "high"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
// RTCDataChannelInit can be used to configure properties of the underlying channel such as data reliability.
|
|
type RTCDataChannelInit struct {
|
|
Ordered bool
|
|
MaxPacketLifeTime *uint16
|
|
MaxRetransmits *uint16
|
|
Protocol string
|
|
Negotiated bool
|
|
ID uint16
|
|
Priority RTCPriorityType
|
|
}
|
|
|
|
// CreateDataChannel creates a new RTCDataChannel object with the given label and optitional options.
|
|
func (r *RTCPeerConnection) CreateDataChannel(label string, options *RTCDataChannelInit) (*RTCDataChannel, error) {
|
|
if r.IsClosed {
|
|
return nil, &InvalidStateError{Err: ErrConnectionClosed}
|
|
}
|
|
|
|
if len(label) > 65535 {
|
|
return nil, &TypeError{Err: ErrInvalidValue}
|
|
}
|
|
|
|
// Defaults
|
|
ordered := true
|
|
priority := RTCPriorityTypeLow
|
|
negotiated := false
|
|
|
|
if options != nil {
|
|
ordered = options.Ordered
|
|
priority = options.Priority
|
|
negotiated = options.Negotiated
|
|
}
|
|
|
|
var id uint16
|
|
if negotiated {
|
|
id = options.ID
|
|
} else {
|
|
var err error
|
|
id, err = r.generateDataChannelID(true) // TODO: base on DTLS role
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if id > 65534 {
|
|
return nil, &TypeError{Err: ErrInvalidValue}
|
|
}
|
|
|
|
if r.sctp.State == RTCSctpTransportStateConnected &&
|
|
id >= r.sctp.MaxChannels {
|
|
return nil, &OperationError{Err: ErrMaxDataChannels}
|
|
}
|
|
|
|
_ = ordered // TODO
|
|
_ = priority // TODO
|
|
res := &RTCDataChannel{
|
|
Label: label,
|
|
ID: id,
|
|
rtcPeerConnection: r,
|
|
}
|
|
|
|
// Remember datachannel
|
|
r.dataChannels[id] = res
|
|
|
|
// Send opening message
|
|
// r.networkManager.SendOpenChannelMessage(id, label)
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (r *RTCPeerConnection) generateDataChannelID(client bool) (uint16, error) {
|
|
var id uint16
|
|
if !client {
|
|
id++
|
|
}
|
|
|
|
for ; id < r.sctp.MaxChannels-1; id += 2 {
|
|
_, ok := r.dataChannels[id]
|
|
if !ok {
|
|
return id, nil
|
|
}
|
|
}
|
|
return 0, &OperationError{Err: ErrMaxDataChannels}
|
|
}
|
|
|
|
// SendOpenChannelMessage is a test to send OpenChannel manually
|
|
func (d *RTCDataChannel) SendOpenChannelMessage() error {
|
|
if err := d.rtcPeerConnection.networkManager.SendOpenChannelMessage(d.ID, d.Label); err != nil {
|
|
return &UnknownError{Err: err}
|
|
}
|
|
return nil
|
|
|
|
}
|
|
|
|
// Send sends the passed message to the DataChannel peer
|
|
func (d *RTCDataChannel) Send(p datachannel.Payload) error {
|
|
if err := d.rtcPeerConnection.networkManager.SendDataChannelMessage(p, d.ID); err != nil {
|
|
return &UnknownError{Err: err}
|
|
}
|
|
return nil
|
|
}
|