Re-organize CreateDataChannel function and add limited spec compliance

This commit is contained in:
Konstantin Itskov
2018-09-04 12:11:17 -04:00
parent 3ac52b89d8
commit 0a2568695a
11 changed files with 286 additions and 89 deletions

View File

@@ -50,10 +50,22 @@ var (
// IceCandidatePoolSize was made after RTCPeerConnection has been initialized. // IceCandidatePoolSize was made after RTCPeerConnection has been initialized.
ErrModifyingIceCandidatePoolSize = errors.New("ice candidate pool size cannot be modified") ErrModifyingIceCandidatePoolSize = errors.New("ice candidate pool size cannot be modified")
// ErrInvalidValue indicates that an invalid value was provided. // ErrStringSizeLimit indicates that the character size limit of string is
ErrInvalidValue = errors.New("invalid value") // exceeded. The limit is hardcoded to 65535 according to specifications.
ErrStringSizeLimit = errors.New("data channel label exceeds size limit")
// ErrMaxDataChannels indicates that the maximum number of data channels // ErrMaxDataChannelID indicates that the maximum number ID that could be
// was reached. // specified for a data channel has been exceeded.
ErrMaxDataChannels = errors.New("maximum number of datachannels reached") ErrMaxDataChannelID = errors.New("maximum number ID for datachannel specified")
// ErrNegotiatedWithoutID indicates that an attempt to create a data channel
// was made while setting the negotiated option to true without providing
// the negotiated channel ID.
ErrNegotiatedWithoutID = errors.New("negotiated set without channel id")
// ErrRetransmitsOrPacketLifeTime indicates that an attempt to create a data
// channel was made with both options MaxPacketLifeTime and MaxRetransmits
// set together. Such configuration is not supported by the specification
// and is mutually exclusive.
ErrRetransmitsOrPacketLifeTime = errors.New("both MaxPacketLifeTime and MaxRetransmits was set")
) )

View File

@@ -46,9 +46,9 @@ func main() {
} }
} }
// Register the Onmessage to handle incoming messages // Register the OnMessage to handle incoming messages
dataChannel.Lock() dataChannel.Lock()
dataChannel.Onmessage = func(payload datachannel.Payload) { dataChannel.OnMessage = func(payload datachannel.Payload) {
switch p := payload.(type) { switch p := payload.(type) {
case *datachannel.PayloadString: case *datachannel.PayloadString:
fmt.Printf("Message '%s' from DataChannel '%s' payload '%s'\n", p.PayloadType().String(), dataChannel.Label, string(p.Data)) fmt.Printf("Message '%s' from DataChannel '%s' payload '%s'\n", p.PayloadType().String(), dataChannel.Label, string(p.Data))

View File

@@ -70,7 +70,7 @@ func main() {
d.Lock() d.Lock()
defer d.Unlock() defer d.Unlock()
d.Onmessage = func(payload datachannel.Payload) { d.OnMessage = func(payload datachannel.Payload) {
switch p := payload.(type) { switch p := payload.(type) {
case *datachannel.PayloadString: case *datachannel.PayloadString:
fmt.Printf("Message '%s' from DataChannel '%s' payload '%s'\n", p.PayloadType().String(), d.Label, string(p.Data)) fmt.Printf("Message '%s' from DataChannel '%s' payload '%s'\n", p.PayloadType().String(), d.Label, string(p.Data))

View File

@@ -31,7 +31,7 @@ func buildPeerConnection() *webrtc.RTCPeerConnection {
} }
d.Lock() d.Lock()
d.Onmessage = func(payload datachannel.Payload) { d.OnMessage = func(payload datachannel.Payload) {
switch p := payload.(type) { switch p := payload.(type) {
case *datachannel.PayloadString: case *datachannel.PayloadString:
fmt.Printf("Message '%s' from DataChannel '%s' payload '%s'\n", p.PayloadType().String(), d.Label, string(p.Data)) fmt.Printf("Message '%s' from DataChannel '%s' payload '%s'\n", p.PayloadType().String(), d.Label, string(p.Data))

View File

@@ -31,7 +31,7 @@ func buildPeerConnection() *webrtc.RTCPeerConnection {
d.Lock() d.Lock()
defer d.Unlock() defer d.Unlock()
d.Onmessage = func(payload datachannel.Payload) { d.OnMessage = func(payload datachannel.Payload) {
switch p := payload.(type) { switch p := payload.(type) {
case *datachannel.PayloadString: case *datachannel.PayloadString:
fmt.Printf("Message '%s' from DataChannel '%s' payload '%s'\n", p.PayloadType().String(), d.Label, string(p.Data)) fmt.Printf("Message '%s' from DataChannel '%s' payload '%s'\n", p.PayloadType().String(), d.Label, string(p.Data))

View File

@@ -13,16 +13,101 @@ import (
type RTCDataChannel struct { type RTCDataChannel struct {
sync.RWMutex sync.RWMutex
Onmessage func(datachannel.Payload) // Label represents a label that can be used to distinguish this
ID uint16 // RTCDataChannel object from other RTCDataChannel objects. Scripts are
Label string // allowed to create multiple RTCDataChannel objects with the same label.
Label string
// Ordered represents if the RTCDataChannel is ordered, and false if
// out-of-order delivery is allowed.
Ordered bool
// MaxPacketLifeTime represents the length of the time window (msec) during
// which transmissions and retransmissions may occur in unreliable mode.
MaxPacketLifeTime *uint16
// MaxRetransmits represents the maximum number of retransmissions that are
// attempted in unreliable mode.
MaxRetransmits *uint16
// Protocol represents the name of the sub-protocol used with this
// RTCDataChannel.
Protocol string
// Negotiated represents whether this RTCDataChannel was negotiated by the
// application (true), or not (false).
Negotiated bool
// ID represents the ID for this RTCDataChannel. The value is initally null,
// which is what will be returned if the ID was not provided at channel
// creation time, and the DTLS role of the SCTP transport has not yet been
// negotiated. Otherwise, it will return the ID that was either selected by
// the script or generated. After the ID is set to a non-null value, it will
// not change.
ID *uint16
// Priority represents the priority for this RTCDataChannel. The priority is
// assigned at channel creation time.
Priority RTCPriorityType
// ReadyState represents the state of the RTCDataChannel object.
ReadyState RTCDataChannelState
// BufferedAmount represents the number of bytes of application data
// (UTF-8 text and binary data) that have been queued using send(). Even
// though the data transmission can occur in parallel, the returned value
// MUST NOT be decreased before the current task yielded back to the event
// loop to prevent race conditions. The value does not include framing
// overhead incurred by the protocol, or buffering done by the operating
// system or network hardware. The value of BufferedAmount slot will only
// increase with each call to the send() method as long as the ReadyState is
// open; however, BufferedAmount does not reset to zero once the channel
// closes.
BufferedAmount uint64
// BufferedAmountLowThreshold represents the threshold at which the
// bufferedAmount is considered to be low. When the bufferedAmount decreases
// from above this threshold to equal or below it, the bufferedamountlow
// event fires. BufferedAmountLowThreshold is initially zero on each new
// RTCDataChannel, but the application may change its value at any time.
BufferedAmountLowThreshold uint64
// The binaryType represents attribute MUST, on getting, return the value to
// which it was last set. On setting, if the new value is either the string
// "blob" or the string "arraybuffer", then set the IDL attribute to this
// new value. Otherwise, throw a SyntaxError. When an RTCDataChannel object
// is created, the binaryType attribute MUST be initialized to the string
// "blob". This attribute controls how binary data is exposed to scripts.
// binaryType string
// OnOpen func()
// OnBufferedAmountLow func()
// OnError func()
// OnClose func()
OnMessage func(datachannel.Payload)
rtcPeerConnection *RTCPeerConnection rtcPeerConnection *RTCPeerConnection
} }
// // Close closes the RTCDataChannel. It may be called regardless of whether the
// // RTCDataChannel object was created by this peer or the remote peer.
// func (d *RTCDataChannel) Close() error {
// if d.ReadyState == RTCDataChannelStateClosing || d.ReadyState == RTCDataChannelStateClosed {
// return nil
// }
//
// d.ReadyState = RTCDataChannelStateClosing
//
// // if err := d.rtcPeerConnection.networkManager.SendOpenChannelMessage(d.ID, d.Label); err != nil {
// // return &rtcerr.UnknownError{Err: err}
// // }
// return nil
//
// }
// SendOpenChannelMessage is a test to send OpenChannel manually // SendOpenChannelMessage is a test to send OpenChannel manually
func (d *RTCDataChannel) SendOpenChannelMessage() error { func (d *RTCDataChannel) SendOpenChannelMessage() error {
if err := d.rtcPeerConnection.networkManager.SendOpenChannelMessage(d.ID, d.Label); err != nil { if err := d.rtcPeerConnection.networkManager.SendOpenChannelMessage(*d.ID, d.Label); err != nil {
return &rtcerr.UnknownError{Err: err} return &rtcerr.UnknownError{Err: err}
} }
return nil return nil
@@ -31,7 +116,7 @@ func (d *RTCDataChannel) SendOpenChannelMessage() error {
// Send sends the passed message to the DataChannel peer // Send sends the passed message to the DataChannel peer
func (d *RTCDataChannel) Send(p datachannel.Payload) error { func (d *RTCDataChannel) Send(p datachannel.Payload) error {
if err := d.rtcPeerConnection.networkManager.SendDataChannelMessage(p, d.ID); err != nil { if err := d.rtcPeerConnection.networkManager.SendDataChannelMessage(p, *d.ID); err != nil {
return &rtcerr.UnknownError{Err: err} return &rtcerr.UnknownError{Err: err}
} }
return nil return nil

View File

@@ -10,16 +10,16 @@ func TestGenerateDataChannelID(t *testing.T) {
c *RTCPeerConnection c *RTCPeerConnection
result uint16 result uint16
}{ }{
{true, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{}}, 0}, {true, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{}}, 0},
{true, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{1: nil}}, 0}, {true, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{1: nil}}, 0},
{true, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{0: nil}}, 2}, {true, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{0: nil}}, 2},
{true, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{0: nil, 2: nil}}, 4}, {true, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{0: nil, 2: nil}}, 4},
{true, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{0: nil, 4: nil}}, 2}, {true, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{0: nil, 4: nil}}, 2},
{false, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{}}, 1}, {false, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{}}, 1},
{false, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{0: nil}}, 1}, {false, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{0: nil}}, 1},
{false, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{1: nil}}, 3}, {false, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{1: nil}}, 3},
{false, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{1: nil, 3: nil}}, 5}, {false, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{1: nil, 3: nil}}, 5},
{false, &RTCPeerConnection{sctp: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{1: nil, 5: nil}}, 3}, {false, &RTCPeerConnection{SctpTransport: newRTCSctpTransport(), dataChannels: map[uint16]*RTCDataChannel{1: nil, 5: nil}}, 3},
} }
for _, testCase := range testCases { for _, testCase := range testCases {

View File

@@ -5,8 +5,7 @@ package webrtc
type RTCDataChannelInit struct { type RTCDataChannelInit struct {
// Ordered indicates if data is allowed to be delivered out of order. The // 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. // default value of true, guarantees that data will be delivered in order.
// TODO make sure defaults to true Ordered *bool
Ordered bool
// MaxPacketLifeTime limits the time (in milliseconds) during which the // MaxPacketLifeTime limits the time (in milliseconds) during which the
// channel will transmit or retransmit data if not acknowledged. This value // channel will transmit or retransmit data if not acknowledged. This value
@@ -19,7 +18,7 @@ type RTCDataChannelInit struct {
MaxRetransmits *uint16 MaxRetransmits *uint16
// Protocol describes the subprotocol name used for this channel. // Protocol describes the subprotocol name used for this channel.
Protocol string Protocol *string
// Negotiated describes if the data channel is created by the local peer or // Negotiated describes if the data channel is created by the local peer or
// the remote peer. The default value of false tells the user agent to // the remote peer. The default value of false tells the user agent to
@@ -27,11 +26,11 @@ type RTCDataChannelInit struct {
// corresponding RTCDataChannel. If set to true, it is up to the application // corresponding RTCDataChannel. If set to true, it is up to the application
// to negotiate the channel and create an RTCDataChannel with the same id // to negotiate the channel and create an RTCDataChannel with the same id
// at the other peer. // at the other peer.
Negotiated bool Negotiated *bool
// ID overrides the default selection of ID for this channel. // ID overrides the default selection of ID for this channel.
ID uint16 ID *uint16
// Priority describes the priority of this channel. // Priority describes the priority of this channel.
Priority RTCPriorityType Priority *RTCPriorityType
} }

View File

@@ -67,7 +67,7 @@ type RTCPeerConnection struct {
// IceConnectionState attribute returns the ICE connection state of the // IceConnectionState attribute returns the ICE connection state of the
// RTCPeerConnection instance. // RTCPeerConnection instance.
// IceConnectionState RTCIceConnectionState // IceConnectionState RTCIceConnectionState // FIXME SWAP-FOR-THIS
IceConnectionState ice.ConnectionState // FIXME REMOVE IceConnectionState ice.ConnectionState // FIXME REMOVE
// ConnectionState attribute returns the connection state of the // ConnectionState attribute returns the connection state of the
@@ -81,15 +81,15 @@ type RTCPeerConnection struct {
isClosed bool isClosed bool
negotiationNeeded bool // FIXME NOT-USED negotiationNeeded bool // FIXME NOT-USED
// lastOffer string LastOffer string // FIXME NOT-USED
// lastAnswer string LastAnswer string // FIXME NOT-USED
// Media // Media
mediaEngine *MediaEngine mediaEngine *MediaEngine
rtpTransceivers []*RTCRtpTransceiver rtpTransceivers []*RTCRtpTransceiver
// SCTP // SctpTransport
sctp *RTCSctpTransport SctpTransport *RTCSctpTransport
// DataChannels // DataChannels
dataChannels map[uint16]*RTCDataChannel dataChannels map[uint16]*RTCDataChannel
@@ -123,7 +123,7 @@ func New(configuration RTCConfiguration) (*RTCPeerConnection, error) {
SignalingState: RTCSignalingStateStable, SignalingState: RTCSignalingStateStable,
ConnectionState: RTCPeerConnectionStateNew, ConnectionState: RTCPeerConnectionStateNew,
mediaEngine: DefaultMediaEngine, mediaEngine: DefaultMediaEngine,
sctp: newRTCSctpTransport(), SctpTransport: newRTCSctpTransport(),
dataChannels: make(map[uint16]*RTCDataChannel), dataChannels: make(map[uint16]*RTCDataChannel),
} }
var err error var err error
@@ -553,31 +553,105 @@ func (pc *RTCPeerConnection) AddTransceiver() RTCRtpTransceiver {
// --- FIXME - BELOW CODE NEEDS RE-ORGANIZATION - https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api // --- FIXME - BELOW CODE NEEDS RE-ORGANIZATION - https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// CreateDataChannel creates a new RTCDataChannel object with the given label and optitional options. // CreateDataChannel creates a new RTCDataChannel object with the given label
// and optitional RTCDataChannelInit used to configure properties of the
// underlying channel such as data reliability.
func (pc *RTCPeerConnection) CreateDataChannel(label string, options *RTCDataChannelInit) (*RTCDataChannel, error) { func (pc *RTCPeerConnection) CreateDataChannel(label string, options *RTCDataChannelInit) (*RTCDataChannel, error) {
// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #2)
if pc.isClosed { if pc.isClosed {
return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
} }
// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #5)
if len(label) > 65535 { if len(label) > 65535 {
return nil, &rtcerr.TypeError{Err: ErrInvalidValue} return nil, &rtcerr.TypeError{Err: ErrStringSizeLimit}
} }
// Defaults // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #3)
ordered := true // Some variables defined explicitly despite their implicit zero values to
priority := RTCPriorityTypeLow // allow better readability to understand what is happening. Additionally,
negotiated := false // 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 := RTCDataChannel{
// 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: RTCPriorityTypeLow,
// https://w3c.github.io/webrtc-pc/#dfn-create-an-rtcdatachannel (Step #2)
ReadyState: RTCDataChannelStateConnecting,
// https://w3c.github.io/webrtc-pc/#dfn-create-an-rtcdatachannel (Step #3)
BufferedAmount: 0,
}
if options != nil { if options != nil {
ordered = options.Ordered // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #7)
priority = options.Priority if options.MaxPacketLifeTime != nil {
negotiated = options.Negotiated 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-data-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
}
} }
// 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 #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 #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)
// FIXME - Where sctp transport is going to go
// if pc.SctpTransport == nil {
// pc.SctpTransport = &RTCSctpTransport{
//
// }
// }
var id uint16 var id uint16
if negotiated { if !channel.Negotiated {
id = options.ID
} else {
var err error var err error
id, err = pc.generateDataChannelID(true) // TODO: base on DTLS role id, err = pc.generateDataChannelID(true) // TODO: base on DTLS role
if err != nil { if err != nil {
@@ -585,30 +659,46 @@ func (pc *RTCPeerConnection) CreateDataChannel(label string, options *RTCDataCha
} }
} }
if id > 65534 { // // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #18)
return nil, &rtcerr.TypeError{Err: ErrInvalidValue} if *channel.ID > 65534 {
return nil, &rtcerr.TypeError{Err: ErrMaxDataChannelID}
} }
if pc.sctp.State == RTCSctpTransportStateConnected && if pc.SctpTransport.State == RTCSctpTransportStateConnected &&
id >= pc.sctp.MaxChannels { id >= *pc.SctpTransport.MaxChannels {
return nil, &rtcerr.OperationError{Err: ErrMaxDataChannels} return nil, &rtcerr.OperationError{Err: ErrMaxDataChannelID}
} }
_ = ordered // TODO // _ = ordered // TODO
_ = priority // TODO // _ = priority // TODO
res := &RTCDataChannel{ // res := &RTCDataChannel{
Label: label, // Label: label,
ID: id, // ID: id,
rtcPeerConnection: pc, // rtcPeerConnection: pc,
} // }
// Remember datachannel // Remember datachannel
pc.dataChannels[id] = res pc.dataChannels[id] = &channel
// Send opening message // Send opening message
// pc.networkManager.SendOpenChannelMessage(id, label) // pc.networkManager.SendOpenChannelMessage(id, label)
return res, nil return &channel, nil
}
func (pc *RTCPeerConnection) generateDataChannelID(client bool) (uint16, error) {
var id uint16
if !client {
id++
}
for ; id < *pc.SctpTransport.MaxChannels-1; id += 2 {
_, ok := pc.dataChannels[id]
if !ok {
return id, nil
}
}
return 0, &rtcerr.OperationError{Err: ErrMaxDataChannelID}
} }
// SetMediaEngine allows overwriting the default media engine used by the RTCPeerConnection // SetMediaEngine allows overwriting the default media engine used by the RTCPeerConnection
@@ -649,7 +739,7 @@ func (pc *RTCPeerConnection) Close() error {
/* Everything below is private */ /* Everything below is private */
func (pc *RTCPeerConnection) generateChannel(ssrc uint32, payloadType uint8) (buffers chan<- *rtp.Packet) { func (pc *RTCPeerConnection) generateChannel(ssrc uint32, payloadType uint8) (buffers chan<- *rtp.Packet) {
if pc.Ontrack == nil { if pc.OnTrack == nil {
return nil return nil
} }
@@ -698,7 +788,8 @@ func (pc *RTCPeerConnection) dataChannelEventHandler(e network.DataChannelEvent)
switch event := e.(type) { switch event := e.(type) {
case *network.DataChannelCreated: case *network.DataChannelCreated:
newDataChannel := &RTCDataChannel{ID: event.StreamIdentifier(), Label: event.Label, rtcPeerConnection: pc} id := event.StreamIdentifier()
newDataChannel := &RTCDataChannel{ID: &id, Label: event.Label, rtcPeerConnection: pc}
pc.dataChannels[e.StreamIdentifier()] = newDataChannel pc.dataChannels[e.StreamIdentifier()] = newDataChannel
if pc.OnDataChannel != nil { if pc.OnDataChannel != nil {
go pc.OnDataChannel(newDataChannel) go pc.OnDataChannel(newDataChannel)
@@ -710,10 +801,10 @@ func (pc *RTCPeerConnection) dataChannelEventHandler(e network.DataChannelEvent)
datachannel.RLock() datachannel.RLock()
defer datachannel.RUnlock() defer datachannel.RUnlock()
if datachannel.Onmessage != nil { if datachannel.OnMessage != nil {
go datachannel.Onmessage(event.Payload) go datachannel.OnMessage(event.Payload)
} else { } else {
fmt.Printf("Onmessage has not been set for Datachannel %s %d \n", datachannel.Label, e.StreamIdentifier()) fmt.Printf("OnMessage has not been set for Datachannel %s %d \n", datachannel.Label, e.StreamIdentifier())
} }
} else { } else {
fmt.Printf("No datachannel found for streamIdentifier %d \n", e.StreamIdentifier()) fmt.Printf("No datachannel found for streamIdentifier %d \n", e.StreamIdentifier())
@@ -815,21 +906,6 @@ func (pc *RTCPeerConnection) addDataMediaSection(d *sdp.SessionDescription, midV
d.WithMedia(media) d.WithMedia(media)
} }
func (pc *RTCPeerConnection) generateDataChannelID(client bool) (uint16, error) {
var id uint16
if !client {
id++
}
for ; id < pc.sctp.MaxChannels-1; id += 2 {
_, ok := pc.dataChannels[id]
if !ok {
return id, nil
}
}
return 0, &rtcerr.OperationError{Err: ErrMaxDataChannels}
}
// NewRTCTrack is used to create a new RTCTrack // NewRTCTrack is used to create a new RTCTrack
func (pc *RTCPeerConnection) NewRTCTrack(payloadType uint8, id, label string) (*RTCTrack, error) { func (pc *RTCPeerConnection) NewRTCTrack(payloadType uint8, id, label string) (*RTCTrack, error) {
codec, err := pc.mediaEngine.getCodec(payloadType) codec, err := pc.mediaEngine.getCodec(payloadType)

View File

@@ -251,6 +251,17 @@ func TestRTCPeerConnection_GetConfiguration(t *testing.T) {
assert.Equal(t, expected.IceCandidatePoolSize, actual.IceCandidatePoolSize) assert.Equal(t, expected.IceCandidatePoolSize, actual.IceCandidatePoolSize)
} }
// TODO - This unittest needs to be completed when CreateDataChannel is complete
// func TestRTCPeerConnection_CreateDataChannel(t *testing.T) {
// pc, err := New(RTCConfiguration{})
// assert.Nil(t, err)
//
// _, err = pc.CreateDataChannel("data", &RTCDataChannelInit{
//
// })
// assert.Nil(t, err)
// }
// TODO Fix this test // TODO Fix this test
const minimalOffer = `v=0 const minimalOffer = `v=0
o=- 7193157174393298413 2 IN IP4 127.0.0.1 o=- 7193157174393298413 2 IN IP4 127.0.0.1

View File

@@ -1,14 +1,27 @@
package webrtc package webrtc
import "math" import (
"math"
)
// RTCSctpTransport provides details about the SCTP transport. // RTCSctpTransport provides details about the SCTP transport.
type RTCSctpTransport struct { type RTCSctpTransport struct {
State RTCSctpTransportState // TODO: Set RTCSctpTransportState // Transport represents the transport over which all SCTP packets for data
// transport *RTCDtlsTransport // TODO: DTLS introspection API // channels will be sent and received.
Transport RTCDtlsTransport
// State represents the current state of the SCTP transport.
State RTCSctpTransportState
// MaxMessageSize represents the maximum size of data that can be passed to
// RTCDataChannel's send() method.
MaxMessageSize float64 MaxMessageSize float64
MaxChannels uint16
// onstatechange func() // MaxChannels represents the maximum amount of RTCDataChannel's that can
// be used simultaneously.
MaxChannels *uint16
// OnStateChange func()
} }
func newRTCSctpTransport() *RTCSctpTransport { func newRTCSctpTransport() *RTCSctpTransport {
@@ -50,5 +63,6 @@ func (r *RTCSctpTransport) calcMessageSize(remoteMaxMessageSize, canSendSize flo
} }
func (r *RTCSctpTransport) updateMaxChannels() { func (r *RTCSctpTransport) updateMaxChannels() {
r.MaxChannels = 65535 // TODO: Get from implementation val := uint16(65535)
r.MaxChannels = &val // TODO: Get from implementation
} }