1// +build !js
2
3// Package webrtc implements the WebRTC 1.0 as defined in W3C WebRTC specification document.
4package webrtc
5
6import (
7	"crypto/ecdsa"
8	"crypto/elliptic"
9	"crypto/rand"
10	"fmt"
11	mathRand "math/rand"
12	"regexp"
13	"strconv"
14	"strings"
15	"sync"
16	"time"
17
18	"github.com/pion/logging"
19	"github.com/pion/rtcp"
20	"github.com/pion/sdp/v2"
21
22	"github.com/pion/webrtc/v2/internal/util"
23	"github.com/pion/webrtc/v2/pkg/rtcerr"
24)
25
26// PeerConnection represents a WebRTC connection that establishes a
27// peer-to-peer communications with another PeerConnection instance in a
28// browser, or to another endpoint implementing the required protocols.
29type PeerConnection struct {
30	statsID string
31	mu      sync.RWMutex
32
33	configuration Configuration
34
35	currentLocalDescription  *SessionDescription
36	pendingLocalDescription  *SessionDescription
37	currentRemoteDescription *SessionDescription
38	pendingRemoteDescription *SessionDescription
39	signalingState           SignalingState
40	iceConnectionState       ICEConnectionState
41	connectionState          PeerConnectionState
42
43	idpLoginURL *string
44
45	isClosed          *atomicBool
46	negotiationNeeded bool
47
48	lastOffer  string
49	lastAnswer string
50
51	rtpTransceivers []*RTPTransceiver
52
53	onSignalingStateChangeHandler     func(SignalingState)
54	onICEConnectionStateChangeHandler func(ICEConnectionState)
55	onConnectionStateChangeHandler    func(PeerConnectionState)
56	onTrackHandler                    func(*Track, *RTPReceiver)
57	onDataChannelHandler              func(*DataChannel)
58
59	iceGatherer   *ICEGatherer
60	iceTransport  *ICETransport
61	dtlsTransport *DTLSTransport
62	sctpTransport *SCTPTransport
63
64	// A reference to the associated API state used by this connection
65	api *API
66	log logging.LeveledLogger
67}
68
69// NewPeerConnection creates a peerconnection with the default
70// codecs. See API.NewRTCPeerConnection for details.
71func NewPeerConnection(configuration Configuration) (*PeerConnection, error) {
72	m := MediaEngine{}
73	m.RegisterDefaultCodecs()
74	api := NewAPI(WithMediaEngine(m))
75	return api.NewPeerConnection(configuration)
76}
77
78// NewPeerConnection creates a new PeerConnection with the provided configuration against the received API object
79func (api *API) NewPeerConnection(configuration Configuration) (*PeerConnection, error) {
80	// https://w3c.github.io/webrtc-pc/#constructor (Step #2)
81	// Some variables defined explicitly despite their implicit zero values to
82	// allow better readability to understand what is happening.
83	pc := &PeerConnection{
84		statsID: fmt.Sprintf("PeerConnection-%d", time.Now().UnixNano()),
85		configuration: Configuration{
86			ICEServers:           []ICEServer{},
87			ICETransportPolicy:   ICETransportPolicyAll,
88			BundlePolicy:         BundlePolicyBalanced,
89			RTCPMuxPolicy:        RTCPMuxPolicyRequire,
90			Certificates:         []Certificate{},
91			ICECandidatePoolSize: 0,
92		},
93		isClosed:           &atomicBool{},
94		negotiationNeeded:  false,
95		lastOffer:          "",
96		lastAnswer:         "",
97		signalingState:     SignalingStateStable,
98		iceConnectionState: ICEConnectionStateNew,
99		connectionState:    PeerConnectionStateNew,
100
101		api: api,
102		log: api.settingEngine.LoggerFactory.NewLogger("pc"),
103	}
104
105	var err error
106	if err = pc.initConfiguration(configuration); err != nil {
107		return nil, err
108	}
109
110	pc.iceGatherer, err = pc.createICEGatherer()
111	if err != nil {
112		return nil, err
113	}
114
115	if !pc.api.settingEngine.candidates.ICETrickle {
116		if err = pc.iceGatherer.Gather(); err != nil {
117			return nil, err
118		}
119	}
120
121	// Create the ice transport
122	iceTransport := pc.createICETransport()
123	pc.iceTransport = iceTransport
124
125	// Create the DTLS transport
126	dtlsTransport, err := pc.api.NewDTLSTransport(pc.iceTransport, pc.configuration.Certificates)
127	if err != nil {
128		return nil, err
129	}
130	pc.dtlsTransport = dtlsTransport
131
132	// Create the SCTP transport
133	pc.sctpTransport = pc.api.NewSCTPTransport(pc.dtlsTransport)
134
135	// Wire up the on datachannel handler
136	pc.sctpTransport.OnDataChannel(func(d *DataChannel) {
137		pc.mu.RLock()
138		hdlr := pc.onDataChannelHandler
139		pc.mu.RUnlock()
140		if hdlr != nil {
141			hdlr(d)
142		}
143	})
144
145	return pc, nil
146}
147
148// initConfiguration defines validation of the specified Configuration and
149// its assignment to the internal configuration variable. This function differs
150// from its SetConfiguration counterpart because most of the checks do not
151// include verification statements related to the existing state. Thus the
152// function describes only minor verification of some the struct variables.
153func (pc *PeerConnection) initConfiguration(configuration Configuration) error {
154	if configuration.PeerIdentity != "" {
155		pc.configuration.PeerIdentity = configuration.PeerIdentity
156	}
157
158	// https://www.w3.org/TR/webrtc/#constructor (step #3)
159	if len(configuration.Certificates) > 0 {
160		now := time.Now()
161		for _, x509Cert := range configuration.Certificates {
162			if !x509Cert.Expires().IsZero() && now.After(x509Cert.Expires()) {
163				return &rtcerr.InvalidAccessError{Err: ErrCertificateExpired}
164			}
165			pc.configuration.Certificates = append(pc.configuration.Certificates, x509Cert)
166		}
167	} else {
168		sk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
169		if err != nil {
170			return &rtcerr.UnknownError{Err: err}
171		}
172		certificate, err := GenerateCertificate(sk)
173		if err != nil {
174			return err
175		}
176		pc.configuration.Certificates = []Certificate{*certificate}
177	}
178
179	if configuration.BundlePolicy != BundlePolicy(Unknown) {
180		pc.configuration.BundlePolicy = configuration.BundlePolicy
181	}
182
183	if configuration.RTCPMuxPolicy != RTCPMuxPolicy(Unknown) {
184		pc.configuration.RTCPMuxPolicy = configuration.RTCPMuxPolicy
185	}
186
187	if configuration.ICECandidatePoolSize != 0 {
188		pc.configuration.ICECandidatePoolSize = configuration.ICECandidatePoolSize
189	}
190
191	if configuration.ICETransportPolicy != ICETransportPolicy(Unknown) {
192		pc.configuration.ICETransportPolicy = configuration.ICETransportPolicy
193	}
194
195	if configuration.SDPSemantics != SDPSemantics(Unknown) {
196		pc.configuration.SDPSemantics = configuration.SDPSemantics
197	}
198
199	sanitizedICEServers := configuration.getICEServers()
200	if len(sanitizedICEServers) > 0 {
201		for _, server := range sanitizedICEServers {
202			if err := server.validate(); err != nil {
203				return err
204			}
205		}
206		pc.configuration.ICEServers = sanitizedICEServers
207	}
208
209	return nil
210}
211
212// OnSignalingStateChange sets an event handler which is invoked when the
213// peer connection's signaling state changes
214func (pc *PeerConnection) OnSignalingStateChange(f func(SignalingState)) {
215	pc.mu.Lock()
216	defer pc.mu.Unlock()
217	pc.onSignalingStateChangeHandler = f
218}
219
220func (pc *PeerConnection) onSignalingStateChange(newState SignalingState) {
221	pc.mu.RLock()
222	hdlr := pc.onSignalingStateChangeHandler
223	pc.mu.RUnlock()
224
225	pc.log.Infof("signaling state changed to %s", newState)
226	if hdlr != nil {
227		go hdlr(newState)
228	}
229}
230
231// OnDataChannel sets an event handler which is invoked when a data
232// channel message arrives from a remote peer.
233func (pc *PeerConnection) OnDataChannel(f func(*DataChannel)) {
234	pc.mu.Lock()
235	defer pc.mu.Unlock()
236	pc.onDataChannelHandler = f
237}
238
239// OnICECandidate sets an event handler which is invoked when a new ICE
240// candidate is found.
241func (pc *PeerConnection) OnICECandidate(f func(*ICECandidate)) {
242	pc.iceGatherer.OnLocalCandidate(f)
243}
244
245// OnICEGatheringStateChange sets an event handler which is invoked when the
246// ICE candidate gathering state has changed.
247func (pc *PeerConnection) OnICEGatheringStateChange(f func(ICEGathererState)) {
248	pc.iceGatherer.OnStateChange(f)
249}
250
251// OnTrack sets an event handler which is called when remote track
252// arrives from a remote peer.
253func (pc *PeerConnection) OnTrack(f func(*Track, *RTPReceiver)) {
254	pc.mu.Lock()
255	defer pc.mu.Unlock()
256	pc.onTrackHandler = f
257}
258
259func (pc *PeerConnection) onTrack(t *Track, r *RTPReceiver) {
260	pc.mu.RLock()
261	hdlr := pc.onTrackHandler
262	pc.mu.RUnlock()
263
264	pc.log.Debugf("got new track: %+v", t)
265	if hdlr != nil && t != nil {
266		go hdlr(t, r)
267	}
268}
269
270// OnICEConnectionStateChange sets an event handler which is called
271// when an ICE connection state is changed.
272func (pc *PeerConnection) OnICEConnectionStateChange(f func(ICEConnectionState)) {
273	pc.mu.Lock()
274	defer pc.mu.Unlock()
275	pc.onICEConnectionStateChangeHandler = f
276}
277
278func (pc *PeerConnection) onICEConnectionStateChange(cs ICEConnectionState) {
279	pc.mu.Lock()
280	pc.iceConnectionState = cs
281	hdlr := pc.onICEConnectionStateChangeHandler
282	pc.mu.Unlock()
283
284	pc.log.Infof("ICE connection state changed: %s", cs)
285	if hdlr != nil {
286		go hdlr(cs)
287	}
288}
289
290// OnConnectionStateChange sets an event handler which is called
291// when the PeerConnectionState has changed
292func (pc *PeerConnection) OnConnectionStateChange(f func(PeerConnectionState)) {
293	pc.mu.Lock()
294	defer pc.mu.Unlock()
295	pc.onConnectionStateChangeHandler = f
296}
297
298// SetConfiguration updates the configuration of this PeerConnection object.
299func (pc *PeerConnection) SetConfiguration(configuration Configuration) error {
300	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-setconfiguration (step #2)
301	if pc.isClosed.get() {
302		return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
303	}
304
305	// https://www.w3.org/TR/webrtc/#set-the-configuration (step #3)
306	if configuration.PeerIdentity != "" {
307		if configuration.PeerIdentity != pc.configuration.PeerIdentity {
308			return &rtcerr.InvalidModificationError{Err: ErrModifyingPeerIdentity}
309		}
310		pc.configuration.PeerIdentity = configuration.PeerIdentity
311	}
312
313	// https://www.w3.org/TR/webrtc/#set-the-configuration (step #4)
314	if len(configuration.Certificates) > 0 {
315		if len(configuration.Certificates) != len(pc.configuration.Certificates) {
316			return &rtcerr.InvalidModificationError{Err: ErrModifyingCertificates}
317		}
318
319		for i, certificate := range configuration.Certificates {
320			if !pc.configuration.Certificates[i].Equals(certificate) {
321				return &rtcerr.InvalidModificationError{Err: ErrModifyingCertificates}
322			}
323		}
324		pc.configuration.Certificates = configuration.Certificates
325	}
326
327	// https://www.w3.org/TR/webrtc/#set-the-configuration (step #5)
328	if configuration.BundlePolicy != BundlePolicy(Unknown) {
329		if configuration.BundlePolicy != pc.configuration.BundlePolicy {
330			return &rtcerr.InvalidModificationError{Err: ErrModifyingBundlePolicy}
331		}
332		pc.configuration.BundlePolicy = configuration.BundlePolicy
333	}
334
335	// https://www.w3.org/TR/webrtc/#set-the-configuration (step #6)
336	if configuration.RTCPMuxPolicy != RTCPMuxPolicy(Unknown) {
337		if configuration.RTCPMuxPolicy != pc.configuration.RTCPMuxPolicy {
338			return &rtcerr.InvalidModificationError{Err: ErrModifyingRTCPMuxPolicy}
339		}
340		pc.configuration.RTCPMuxPolicy = configuration.RTCPMuxPolicy
341	}
342
343	// https://www.w3.org/TR/webrtc/#set-the-configuration (step #7)
344	if configuration.ICECandidatePoolSize != 0 {
345		if pc.configuration.ICECandidatePoolSize != configuration.ICECandidatePoolSize &&
346			pc.LocalDescription() != nil {
347			return &rtcerr.InvalidModificationError{Err: ErrModifyingICECandidatePoolSize}
348		}
349		pc.configuration.ICECandidatePoolSize = configuration.ICECandidatePoolSize
350	}
351
352	// https://www.w3.org/TR/webrtc/#set-the-configuration (step #8)
353	if configuration.ICETransportPolicy != ICETransportPolicy(Unknown) {
354		pc.configuration.ICETransportPolicy = configuration.ICETransportPolicy
355	}
356
357	// https://www.w3.org/TR/webrtc/#set-the-configuration (step #11)
358	if len(configuration.ICEServers) > 0 {
359		// https://www.w3.org/TR/webrtc/#set-the-configuration (step #11.3)
360		for _, server := range configuration.ICEServers {
361			if err := server.validate(); err != nil {
362				return err
363			}
364		}
365		pc.configuration.ICEServers = configuration.ICEServers
366	}
367	return nil
368}
369
370// GetConfiguration returns a Configuration object representing the current
371// configuration of this PeerConnection object. The returned object is a
372// copy and direct mutation on it will not take affect until SetConfiguration
373// has been called with Configuration passed as its only argument.
374// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-getconfiguration
375func (pc *PeerConnection) GetConfiguration() Configuration {
376	return pc.configuration
377}
378
379func (pc *PeerConnection) getStatsID() string {
380	pc.mu.RLock()
381	defer pc.mu.RUnlock()
382	return pc.statsID
383}
384
385// CreateOffer starts the PeerConnection and generates the localDescription
386func (pc *PeerConnection) CreateOffer(options *OfferOptions) (SessionDescription, error) {
387	useIdentity := pc.idpLoginURL != nil
388	switch {
389	case options != nil:
390		return SessionDescription{}, fmt.Errorf("TODO handle options")
391	case useIdentity:
392		return SessionDescription{}, fmt.Errorf("TODO handle identity provider")
393	case pc.isClosed.get():
394		return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
395	}
396
397	d := sdp.NewJSEPSessionDescription(useIdentity)
398	if err := pc.addFingerprint(d); err != nil {
399		return SessionDescription{}, err
400	}
401
402	iceParams, err := pc.iceGatherer.GetLocalParameters()
403	if err != nil {
404		return SessionDescription{}, err
405	}
406
407	candidates, err := pc.iceGatherer.GetLocalCandidates()
408	if err != nil {
409		return SessionDescription{}, err
410	}
411
412	bundleValue := "BUNDLE"
413	bundleCount := 0
414	appendBundle := func(midValue string) {
415		bundleValue += " " + midValue
416		bundleCount++
417	}
418
419	if pc.configuration.SDPSemantics == SDPSemanticsPlanB {
420		video := make([]*RTPTransceiver, 0)
421		audio := make([]*RTPTransceiver, 0)
422		for _, t := range pc.GetTransceivers() {
423			switch t.kind {
424			case RTPCodecTypeVideo:
425				video = append(video, t)
426			case RTPCodecTypeAudio:
427				audio = append(audio, t)
428			}
429		}
430
431		if len(video) > 0 {
432			if _, err = pc.addTransceiverSDP(d, "video", iceParams, candidates, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), video...); err != nil {
433				return SessionDescription{}, err
434			}
435			appendBundle("video")
436		}
437		if len(audio) > 0 {
438			if _, err = pc.addTransceiverSDP(d, "audio", iceParams, candidates, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), audio...); err != nil {
439				return SessionDescription{}, err
440			}
441			appendBundle("audio")
442		}
443	} else {
444		for _, t := range pc.GetTransceivers() {
445			midValue := strconv.Itoa(bundleCount)
446			if _, err = pc.addTransceiverSDP(d, midValue, iceParams, candidates, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), t); err != nil {
447				return SessionDescription{}, err
448			}
449			appendBundle(midValue)
450		}
451	}
452
453	if pc.api.settingEngine.candidates.ICELite {
454		// RFC 5245 S15.3
455		d = d.WithValueAttribute(sdp.AttrKeyICELite, sdp.AttrKeyICELite)
456	}
457
458	midValue := strconv.Itoa(bundleCount)
459	if pc.configuration.SDPSemantics == SDPSemanticsPlanB {
460		midValue = "data"
461	}
462	pc.addDataMediaSection(d, midValue, iceParams, candidates, connectionRoleFromDtlsRole(defaultDtlsRoleOffer))
463	appendBundle(midValue)
464
465	d = d.WithValueAttribute(sdp.AttrKeyGroup, bundleValue)
466
467	sdpBytes, err := d.Marshal()
468	if err != nil {
469		return SessionDescription{}, err
470	}
471
472	desc := SessionDescription{
473		Type:   SDPTypeOffer,
474		SDP:    string(sdpBytes),
475		parsed: d,
476	}
477	pc.lastOffer = desc.SDP
478	return desc, nil
479}
480
481func (pc *PeerConnection) createICEGatherer() (*ICEGatherer, error) {
482	g, err := pc.api.NewICEGatherer(ICEGatherOptions{
483		ICEServers:      pc.configuration.getICEServers(),
484		ICEGatherPolicy: pc.configuration.ICETransportPolicy,
485	})
486	if err != nil {
487		return nil, err
488	}
489
490	return g, nil
491}
492
493// Update the PeerConnectionState given the state of relevant transports
494// https://www.w3.org/TR/webrtc/#rtcpeerconnectionstate-enum
495func (pc *PeerConnection) updateConnectionState(iceConnectionState ICEConnectionState, dtlsTransportState DTLSTransportState) {
496	pc.mu.Lock()
497	defer pc.mu.Unlock()
498
499	connectionState := PeerConnectionStateNew
500	switch {
501	// The RTCPeerConnection object's [[IsClosed]] slot is true.
502	case pc.isClosed.get():
503		connectionState = PeerConnectionStateClosed
504
505	// Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
506	case iceConnectionState == ICEConnectionStateFailed || dtlsTransportState == DTLSTransportStateFailed:
507		connectionState = PeerConnectionStateFailed
508
509	// Any of the RTCIceTransports or RTCDtlsTransports are in the "disconnected"
510	// state and none of them are in the "failed" or "connecting" or "checking" state.  */
511	case iceConnectionState == ICEConnectionStateDisconnected:
512		connectionState = PeerConnectionStateDisconnected
513
514	// All RTCIceTransports and RTCDtlsTransports are in the "connected", "completed" or "closed"
515	// state and at least one of them is in the "connected" or "completed" state.
516	case iceConnectionState == ICEConnectionStateConnected && dtlsTransportState == DTLSTransportStateConnected:
517		connectionState = PeerConnectionStateConnected
518
519	//  Any of the RTCIceTransports or RTCDtlsTransports are in the "connecting" or
520	// "checking" state and none of them is in the "failed" state.
521	case iceConnectionState == ICEConnectionStateChecking && dtlsTransportState == DTLSTransportStateConnecting:
522		connectionState = PeerConnectionStateConnecting
523	}
524
525	if pc.connectionState == connectionState {
526		return
527	}
528
529	pc.log.Infof("peer connection state changed: %s", connectionState)
530	pc.connectionState = connectionState
531	hdlr := pc.onConnectionStateChangeHandler
532	if hdlr != nil {
533		go hdlr(connectionState)
534	}
535}
536
537func (pc *PeerConnection) createICETransport() *ICETransport {
538	t := pc.api.NewICETransport(pc.iceGatherer)
539	t.OnConnectionStateChange(func(state ICETransportState) {
540		var cs ICEConnectionState
541		switch state {
542		case ICETransportStateNew:
543			cs = ICEConnectionStateNew
544		case ICETransportStateChecking:
545			cs = ICEConnectionStateChecking
546		case ICETransportStateConnected:
547			cs = ICEConnectionStateConnected
548		case ICETransportStateCompleted:
549			cs = ICEConnectionStateCompleted
550		case ICETransportStateFailed:
551			cs = ICEConnectionStateFailed
552		case ICETransportStateDisconnected:
553			cs = ICEConnectionStateDisconnected
554		case ICETransportStateClosed:
555			cs = ICEConnectionStateClosed
556		default:
557			pc.log.Warnf("OnConnectionStateChange: unhandled ICE state: %s", state)
558			return
559		}
560		pc.onICEConnectionStateChange(cs)
561		pc.updateConnectionState(cs, pc.dtlsTransport.State())
562	})
563
564	return t
565}
566
567func (pc *PeerConnection) getPeerDirection(media *sdp.MediaDescription) RTPTransceiverDirection {
568	for _, a := range media.Attributes {
569		if direction := NewRTPTransceiverDirection(a.Key); direction != RTPTransceiverDirection(Unknown) {
570			return direction
571		}
572	}
573	return RTPTransceiverDirection(Unknown)
574}
575
576func (pc *PeerConnection) getMidValue(media *sdp.MediaDescription) string {
577	for _, attr := range media.Attributes {
578		if attr.Key == "mid" {
579			return attr.Value
580		}
581	}
582	return ""
583}
584
585// Given a direction+type pluck a transceiver from the passed list
586// if no entry satisfies the requested type+direction return a inactive Transceiver
587func satisfyTypeAndDirection(remoteKind RTPCodecType, remoteDirection RTPTransceiverDirection, localTransceivers []*RTPTransceiver) (*RTPTransceiver, []*RTPTransceiver) {
588	// Get direction order from most preferred to least
589	getPreferredDirections := func() []RTPTransceiverDirection {
590		switch remoteDirection {
591		case RTPTransceiverDirectionSendrecv:
592			return []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendrecv}
593		case RTPTransceiverDirectionSendonly:
594			return []RTPTransceiverDirection{RTPTransceiverDirectionRecvonly, RTPTransceiverDirectionSendrecv}
595		case RTPTransceiverDirectionRecvonly:
596			return []RTPTransceiverDirection{RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv}
597		}
598		return []RTPTransceiverDirection{}
599	}
600
601	for _, possibleDirection := range getPreferredDirections() {
602		for i := range localTransceivers {
603			t := localTransceivers[i]
604			if t.kind != remoteKind || possibleDirection != t.Direction {
605				continue
606			}
607
608			return t, append(localTransceivers[:i], localTransceivers[i+1:]...)
609		}
610	}
611
612	return &RTPTransceiver{
613		kind:      remoteKind,
614		Direction: RTPTransceiverDirectionInactive,
615	}, localTransceivers
616}
617
618func (pc *PeerConnection) addAnswerMediaTransceivers(d *sdp.SessionDescription) (*sdp.SessionDescription, error) {
619	iceParams, err := pc.iceGatherer.GetLocalParameters()
620	if err != nil {
621		return nil, err
622	}
623
624	candidates, err := pc.iceGatherer.GetLocalCandidates()
625	if err != nil {
626		return nil, err
627	}
628
629	bundleValue := "BUNDLE"
630	appendBundle := func(midValue string) {
631		bundleValue += " " + midValue
632	}
633
634	connectionRole := connectionRoleFromDtlsRole(pc.api.settingEngine.answeringDTLSRole)
635	if connectionRole == sdp.ConnectionRole(0) {
636		connectionRole = connectionRoleFromDtlsRole(defaultDtlsRoleAnswer)
637	}
638
639	var t *RTPTransceiver
640	localTransceivers := append([]*RTPTransceiver{}, pc.GetTransceivers()...)
641	detectedPlanB := pc.descriptionIsPlanB(pc.RemoteDescription())
642
643	for _, media := range pc.RemoteDescription().parsed.MediaDescriptions {
644		midValue := pc.getMidValue(media)
645		if midValue == "" {
646			return nil, fmt.Errorf("RemoteDescription contained media section without mid value")
647		}
648
649		if media.MediaName.Media == "application" {
650			pc.addDataMediaSection(d, midValue, iceParams, candidates, connectionRole)
651			appendBundle(midValue)
652			continue
653		}
654
655		kind := NewRTPCodecType(media.MediaName.Media)
656		direction := pc.getPeerDirection(media)
657		if kind == 0 || direction == RTPTransceiverDirection(Unknown) {
658			continue
659		}
660
661		t, localTransceivers = satisfyTypeAndDirection(kind, direction, localTransceivers)
662		mediaTransceivers := []*RTPTransceiver{t}
663		switch pc.configuration.SDPSemantics {
664		case SDPSemanticsUnifiedPlanWithFallback:
665			// If no match, process as unified-plan
666			if !detectedPlanB {
667				break
668			}
669			// If there was a match, fall through to plan-b
670			fallthrough
671		case SDPSemanticsPlanB:
672			if !detectedPlanB {
673				return nil, &rtcerr.TypeError{Err: ErrIncorrectSDPSemantics}
674			}
675			// If we're responding to a plan-b offer, then we should try to fill up this
676			// media entry with all matching local transceivers
677			for {
678				// keep going until we can't get any more
679				t, localTransceivers = satisfyTypeAndDirection(kind, direction, localTransceivers)
680				if t.Direction == RTPTransceiverDirectionInactive {
681					break
682				}
683				mediaTransceivers = append(mediaTransceivers, t)
684			}
685		case SDPSemanticsUnifiedPlan:
686			if detectedPlanB {
687				return nil, &rtcerr.TypeError{Err: ErrIncorrectSDPSemantics}
688			}
689		}
690		if accepted, err := pc.addTransceiverSDP(d, midValue, iceParams, candidates, connectionRole, mediaTransceivers...); err != nil {
691			return nil, err
692		} else if accepted {
693			appendBundle(midValue)
694		}
695	}
696
697	if pc.configuration.SDPSemantics == SDPSemanticsUnifiedPlanWithFallback && detectedPlanB {
698		pc.log.Info("Plan-B Offer detected; responding with Plan-B Answer")
699	}
700
701	return d.WithValueAttribute(sdp.AttrKeyGroup, bundleValue), nil
702}
703
704// CreateAnswer starts the PeerConnection and generates the localDescription
705func (pc *PeerConnection) CreateAnswer(options *AnswerOptions) (SessionDescription, error) {
706	useIdentity := pc.idpLoginURL != nil
707	switch {
708	case options != nil:
709		return SessionDescription{}, fmt.Errorf("TODO handle options")
710	case pc.RemoteDescription() == nil:
711		return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrNoRemoteDescription}
712	case useIdentity:
713		return SessionDescription{}, fmt.Errorf("TODO handle identity provider")
714	case pc.isClosed.get():
715		return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
716	}
717
718	d := sdp.NewJSEPSessionDescription(useIdentity)
719	if err := pc.addFingerprint(d); err != nil {
720		return SessionDescription{}, err
721	}
722
723	d, err := pc.addAnswerMediaTransceivers(d)
724	if err != nil {
725		return SessionDescription{}, err
726	}
727
728	sdpBytes, err := d.Marshal()
729	if err != nil {
730		return SessionDescription{}, err
731	}
732
733	desc := SessionDescription{
734		Type:   SDPTypeAnswer,
735		SDP:    string(sdpBytes),
736		parsed: d,
737	}
738	pc.lastAnswer = desc.SDP
739	return desc, nil
740}
741
742// 4.4.1.6 Set the SessionDescription
743func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeOp) error {
744	if pc.isClosed.get() {
745		return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
746	}
747
748	cur := pc.signalingState
749	setLocal := stateChangeOpSetLocal
750	setRemote := stateChangeOpSetRemote
751	newSDPDoesNotMatchOffer := &rtcerr.InvalidModificationError{Err: fmt.Errorf("new sdp does not match previous offer")}
752	newSDPDoesNotMatchAnswer := &rtcerr.InvalidModificationError{Err: fmt.Errorf("new sdp does not match previous answer")}
753
754	var nextState SignalingState
755	var err error
756	switch op {
757	case setLocal:
758		switch sd.Type {
759		// stable->SetLocal(offer)->have-local-offer
760		case SDPTypeOffer:
761			if sd.SDP != pc.lastOffer {
762				return newSDPDoesNotMatchOffer
763			}
764			nextState, err = checkNextSignalingState(cur, SignalingStateHaveLocalOffer, setLocal, sd.Type)
765			if err == nil {
766				pc.pendingLocalDescription = sd
767			}
768		// have-remote-offer->SetLocal(answer)->stable
769		// have-local-pranswer->SetLocal(answer)->stable
770		case SDPTypeAnswer:
771			if sd.SDP != pc.lastAnswer {
772				return newSDPDoesNotMatchAnswer
773			}
774			nextState, err = checkNextSignalingState(cur, SignalingStateStable, setLocal, sd.Type)
775			if err == nil {
776				pc.currentLocalDescription = sd
777				pc.currentRemoteDescription = pc.pendingRemoteDescription
778				pc.pendingRemoteDescription = nil
779				pc.pendingLocalDescription = nil
780			}
781		case SDPTypeRollback:
782			nextState, err = checkNextSignalingState(cur, SignalingStateStable, setLocal, sd.Type)
783			if err == nil {
784				pc.pendingLocalDescription = nil
785			}
786		// have-remote-offer->SetLocal(pranswer)->have-local-pranswer
787		case SDPTypePranswer:
788			if sd.SDP != pc.lastAnswer {
789				return newSDPDoesNotMatchAnswer
790			}
791			nextState, err = checkNextSignalingState(cur, SignalingStateHaveLocalPranswer, setLocal, sd.Type)
792			if err == nil {
793				pc.pendingLocalDescription = sd
794			}
795		default:
796			return &rtcerr.OperationError{Err: fmt.Errorf("invalid state change op: %s(%s)", op, sd.Type)}
797		}
798	case setRemote:
799		switch sd.Type {
800		// stable->SetRemote(offer)->have-remote-offer
801		case SDPTypeOffer:
802			nextState, err = checkNextSignalingState(cur, SignalingStateHaveRemoteOffer, setRemote, sd.Type)
803			if err == nil {
804				pc.pendingRemoteDescription = sd
805			}
806		// have-local-offer->SetRemote(answer)->stable
807		// have-remote-pranswer->SetRemote(answer)->stable
808		case SDPTypeAnswer:
809			nextState, err = checkNextSignalingState(cur, SignalingStateStable, setRemote, sd.Type)
810			if err == nil {
811				pc.currentRemoteDescription = sd
812				pc.currentLocalDescription = pc.pendingLocalDescription
813				pc.pendingRemoteDescription = nil
814				pc.pendingLocalDescription = nil
815			}
816		case SDPTypeRollback:
817			nextState, err = checkNextSignalingState(cur, SignalingStateStable, setRemote, sd.Type)
818			if err == nil {
819				pc.pendingRemoteDescription = nil
820			}
821		// have-local-offer->SetRemote(pranswer)->have-remote-pranswer
822		case SDPTypePranswer:
823			nextState, err = checkNextSignalingState(cur, SignalingStateHaveRemotePranswer, setRemote, sd.Type)
824			if err == nil {
825				pc.pendingRemoteDescription = sd
826			}
827		default:
828			return &rtcerr.OperationError{Err: fmt.Errorf("invalid state change op: %s(%s)", op, sd.Type)}
829		}
830	default:
831		return &rtcerr.OperationError{Err: fmt.Errorf("unhandled state change op: %q", op)}
832	}
833
834	if err == nil {
835		pc.signalingState = nextState
836		pc.onSignalingStateChange(nextState)
837	}
838	return err
839}
840
841// SetLocalDescription sets the SessionDescription of the local peer
842func (pc *PeerConnection) SetLocalDescription(desc SessionDescription) error {
843	if pc.isClosed.get() {
844		return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
845	}
846
847	// JSEP 5.4
848	if desc.SDP == "" {
849		switch desc.Type {
850		case SDPTypeAnswer, SDPTypePranswer:
851			desc.SDP = pc.lastAnswer
852		case SDPTypeOffer:
853			desc.SDP = pc.lastOffer
854		default:
855			return &rtcerr.InvalidModificationError{
856				Err: fmt.Errorf("invalid SDP type supplied to SetLocalDescription(): %s", desc.Type),
857			}
858		}
859	}
860
861	desc.parsed = &sdp.SessionDescription{}
862	if err := desc.parsed.Unmarshal([]byte(desc.SDP)); err != nil {
863		return err
864	}
865	if err := pc.setDescription(&desc, stateChangeOpSetLocal); err != nil {
866		return err
867	}
868
869	// To support all unittests which are following the future trickle=true
870	// setup while also support the old trickle=false synchronous gathering
871	// process this is necessary to avoid calling Gather() in multiple
872	// places; which causes race conditions. (issue-707)
873	if !pc.api.settingEngine.candidates.ICETrickle {
874		if err := pc.iceGatherer.SignalCandidates(); err != nil {
875			return err
876		}
877		return nil
878	}
879
880	return pc.iceGatherer.Gather()
881}
882
883// LocalDescription returns pendingLocalDescription if it is not null and
884// otherwise it returns currentLocalDescription. This property is used to
885// determine if setLocalDescription has already been called.
886// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-localdescription
887func (pc *PeerConnection) LocalDescription() *SessionDescription {
888	if localDescription := pc.PendingLocalDescription(); localDescription != nil {
889		return localDescription
890	}
891	return pc.currentLocalDescription
892}
893
894// SetRemoteDescription sets the SessionDescription of the remote peer
895func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
896	if pc.currentRemoteDescription != nil { // pion/webrtc#207
897		return fmt.Errorf("remoteDescription is already defined, SetRemoteDescription can only be called once")
898	}
899	if pc.isClosed.get() {
900		return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
901	}
902
903	desc.parsed = &sdp.SessionDescription{}
904	if err := desc.parsed.Unmarshal([]byte(desc.SDP)); err != nil {
905		return err
906	}
907	if err := pc.setDescription(&desc, stateChangeOpSetRemote); err != nil {
908		return err
909	}
910
911	weOffer := true
912	remoteUfrag := ""
913	remotePwd := ""
914	if desc.Type == SDPTypeOffer {
915		weOffer = false
916	}
917	remoteIsLite := false
918	if liteValue, haveRemoteIs := desc.parsed.Attribute(sdp.AttrKeyICELite); haveRemoteIs && liteValue == sdp.AttrKeyICELite {
919		remoteIsLite = true
920	}
921
922	fingerprint, haveFingerprint := desc.parsed.Attribute("fingerprint")
923	for _, m := range pc.RemoteDescription().parsed.MediaDescriptions {
924		if !haveFingerprint {
925			fingerprint, haveFingerprint = m.Attribute("fingerprint")
926		}
927
928		for _, a := range m.Attributes {
929			switch {
930			case a.IsICECandidate():
931				sdpCandidate, err := a.ToICECandidate()
932				if err != nil {
933					return err
934				}
935
936				candidate, err := newICECandidateFromSDP(sdpCandidate)
937				if err != nil {
938					return err
939				}
940
941				if err = pc.iceTransport.AddRemoteCandidate(candidate); err != nil {
942					return err
943				}
944			case strings.HasPrefix(*a.String(), "ice-ufrag"):
945				remoteUfrag = (*a.String())[len("ice-ufrag:"):]
946			case strings.HasPrefix(*a.String(), "ice-pwd"):
947				remotePwd = (*a.String())[len("ice-pwd:"):]
948			}
949		}
950	}
951
952	if !haveFingerprint {
953		return fmt.Errorf("could not find fingerprint")
954	}
955
956	parts := strings.Split(fingerprint, " ")
957	if len(parts) != 2 {
958		return fmt.Errorf("invalid fingerprint")
959	}
960	fingerprint = parts[1]
961	fingerprintHash := parts[0]
962
963	iceRole := ICERoleControlled
964	// If one of the agents is lite and the other one is not, the lite agent must be the controlling agent.
965	// If both or neither agents are lite the offering agent is controlling.
966	// RFC 8445 S6.1.1
967	if (weOffer && remoteIsLite == pc.api.settingEngine.candidates.ICELite) || (remoteIsLite && !pc.api.settingEngine.candidates.ICELite) {
968		iceRole = ICERoleControlling
969	}
970
971	// Start the networking in a new routine since it will block until
972	// the connection is actually established.
973	go pc.startTransports(iceRole, dtlsRoleFromRemoteSDP(desc.parsed), remoteUfrag, remotePwd, fingerprint, fingerprintHash)
974
975	return nil
976}
977
978func (pc *PeerConnection) descriptionIsPlanB(desc *SessionDescription) bool {
979	if desc == nil || desc.parsed == nil {
980		return false
981	}
982
983	detectionRegex := regexp.MustCompile(`(?i)^(audio|video|data)$`)
984	for _, media := range desc.parsed.MediaDescriptions {
985		if len(detectionRegex.FindStringSubmatch(pc.getMidValue(media))) == 2 {
986			return true
987		}
988	}
989	return false
990}
991
992type incomingTrack struct {
993	kind  RTPCodecType
994	label string
995	id    string
996	ssrc  uint32
997}
998
999func (pc *PeerConnection) startReceiver(incoming incomingTrack, receiver *RTPReceiver) {
1000	err := receiver.Receive(RTPReceiveParameters{
1001		Encodings: RTPDecodingParameters{
1002			RTPCodingParameters{SSRC: incoming.ssrc},
1003		}})
1004	if err != nil {
1005		pc.log.Warnf("RTPReceiver Receive failed %s", err)
1006		return
1007	}
1008
1009	if err = receiver.Track().determinePayloadType(); err != nil {
1010		pc.log.Warnf("Could not determine PayloadType for SSRC %d", receiver.Track().SSRC())
1011		return
1012	}
1013
1014	pc.mu.RLock()
1015	defer pc.mu.RUnlock()
1016
1017	if pc.currentLocalDescription == nil {
1018		pc.log.Warnf("SetLocalDescription not called, unable to handle incoming media streams")
1019		return
1020	}
1021
1022	sdpCodec, err := pc.currentLocalDescription.parsed.GetCodecForPayloadType(receiver.Track().PayloadType())
1023	if err != nil {
1024		pc.log.Warnf("no codec could be found in RemoteDescription for payloadType %d", receiver.Track().PayloadType())
1025		return
1026	}
1027
1028	codec, err := pc.api.mediaEngine.getCodecSDP(sdpCodec)
1029	if err != nil {
1030		pc.log.Warnf("codec %s in not registered", sdpCodec)
1031		return
1032	}
1033
1034	receiver.Track().mu.Lock()
1035	receiver.Track().id = incoming.id
1036	receiver.Track().label = incoming.label
1037	receiver.Track().kind = codec.Type
1038	receiver.Track().codec = codec
1039	receiver.Track().mu.Unlock()
1040
1041	if pc.onTrackHandler != nil {
1042		pc.onTrack(receiver.Track(), receiver)
1043	} else {
1044		pc.log.Warnf("OnTrack unset, unable to handle incoming media streams")
1045	}
1046
1047}
1048
1049// openSRTP opens knows inbound SRTP streams from the RemoteDescription
1050func (pc *PeerConnection) openSRTP() {
1051	incomingTracks := map[uint32]incomingTrack{}
1052
1053	remoteIsPlanB := false
1054	switch pc.configuration.SDPSemantics {
1055	case SDPSemanticsPlanB:
1056		remoteIsPlanB = true
1057	case SDPSemanticsUnifiedPlanWithFallback:
1058		remoteIsPlanB = pc.descriptionIsPlanB(pc.RemoteDescription())
1059	}
1060
1061	for _, media := range pc.RemoteDescription().parsed.MediaDescriptions {
1062		for _, attr := range media.Attributes {
1063			codecType := NewRTPCodecType(media.MediaName.Media)
1064			if codecType == 0 {
1065				continue
1066			}
1067
1068			if attr.Key == sdp.AttrKeySSRC {
1069				split := strings.Split(attr.Value, " ")
1070				ssrc, err := strconv.ParseUint(split[0], 10, 32)
1071				if err != nil {
1072					pc.log.Warnf("Failed to parse SSRC: %v", err)
1073					continue
1074				}
1075
1076				trackID := ""
1077				trackLabel := ""
1078				if len(split) == 3 && strings.HasPrefix(split[1], "msid:") {
1079					trackLabel = split[1][len("msid:"):]
1080					trackID = split[2]
1081				}
1082
1083				incomingTracks[uint32(ssrc)] = incomingTrack{codecType, trackLabel, trackID, uint32(ssrc)}
1084				if trackID != "" && trackLabel != "" {
1085					break // Remote provided Label+ID, we have all the information we need
1086				}
1087			}
1088		}
1089	}
1090
1091	localTransceivers := append([]*RTPTransceiver{}, pc.GetTransceivers()...)
1092	for ssrc, incoming := range incomingTracks {
1093		for i := range localTransceivers {
1094			t := localTransceivers[i]
1095			switch {
1096			case incomingTracks[ssrc].kind != t.kind:
1097				continue
1098			case t.Direction != RTPTransceiverDirectionRecvonly && t.Direction != RTPTransceiverDirectionSendrecv:
1099				continue
1100			case t.Receiver == nil:
1101				continue
1102			}
1103
1104			delete(incomingTracks, ssrc)
1105			localTransceivers = append(localTransceivers[:i], localTransceivers[i+1:]...)
1106			go pc.startReceiver(incoming, t.Receiver)
1107			break
1108		}
1109	}
1110
1111	if remoteIsPlanB {
1112		for ssrc, incoming := range incomingTracks {
1113			t, err := pc.AddTransceiver(incoming.kind, RtpTransceiverInit{
1114				Direction: RTPTransceiverDirectionSendrecv,
1115			})
1116			if err != nil {
1117				pc.log.Warnf("Could not add transceiver for remote SSRC %d: %s", ssrc, err)
1118				continue
1119			}
1120			go pc.startReceiver(incoming, t.Receiver)
1121		}
1122	}
1123}
1124
1125func (pc *PeerConnection) handleUndeclaredSSRC(ssrc uint32) bool {
1126	if remoteDescription := pc.RemoteDescription(); remoteDescription != nil {
1127		if len(remoteDescription.parsed.MediaDescriptions) == 1 {
1128			onlyMediaSection := remoteDescription.parsed.MediaDescriptions[0]
1129			for _, a := range onlyMediaSection.Attributes {
1130				if a.Key == ssrcStr {
1131					return false
1132				}
1133			}
1134
1135			incoming := incomingTrack{
1136				ssrc: ssrc,
1137				kind: RTPCodecTypeVideo,
1138			}
1139			if onlyMediaSection.MediaName.Media == RTPCodecTypeAudio.String() {
1140				incoming.kind = RTPCodecTypeAudio
1141			}
1142
1143			t, err := pc.AddTransceiver(incoming.kind, RtpTransceiverInit{
1144				Direction: RTPTransceiverDirectionSendrecv,
1145			})
1146			if err != nil {
1147				pc.log.Warnf("Could not add transceiver for remote SSRC %d: %s", ssrc, err)
1148				return false
1149			}
1150			go pc.startReceiver(incoming, t.Receiver)
1151			return true
1152		}
1153	}
1154
1155	return false
1156}
1157
1158// drainSRTP pulls and discards RTP/RTCP packets that don't match any a:ssrc lines
1159// If the remote SDP was only one media section the ssrc doesn't have to be explicitly declared
1160func (pc *PeerConnection) drainSRTP() {
1161	go func() {
1162		for {
1163			srtpSession, err := pc.dtlsTransport.getSRTPSession()
1164			if err != nil {
1165				pc.log.Warnf("drainSRTP failed to open SrtpSession: %v", err)
1166				return
1167			}
1168
1169			_, ssrc, err := srtpSession.AcceptStream()
1170			if err != nil {
1171				pc.log.Warnf("Failed to accept RTP %v \n", err)
1172				return
1173			}
1174
1175			if !pc.handleUndeclaredSSRC(ssrc) {
1176				pc.log.Errorf("Incoming unhandled RTP ssrc(%d)", ssrc)
1177			}
1178
1179		}
1180	}()
1181
1182	for {
1183		srtcpSession, err := pc.dtlsTransport.getSRTCPSession()
1184		if err != nil {
1185			pc.log.Warnf("drainSRTP failed to open SrtcpSession: %v", err)
1186			return
1187		}
1188
1189		_, ssrc, err := srtcpSession.AcceptStream()
1190		if err != nil {
1191			pc.log.Warnf("Failed to accept RTCP %v \n", err)
1192			return
1193		}
1194		pc.log.Errorf("Incoming unhandled RTCP ssrc(%d)", ssrc)
1195	}
1196}
1197
1198// RemoteDescription returns pendingRemoteDescription if it is not null and
1199// otherwise it returns currentRemoteDescription. This property is used to
1200// determine if setRemoteDescription has already been called.
1201// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-remotedescription
1202func (pc *PeerConnection) RemoteDescription() *SessionDescription {
1203	if pc.pendingRemoteDescription != nil {
1204		return pc.pendingRemoteDescription
1205	}
1206	return pc.currentRemoteDescription
1207}
1208
1209// AddICECandidate accepts an ICE candidate string and adds it
1210// to the existing set of candidates
1211func (pc *PeerConnection) AddICECandidate(candidate ICECandidateInit) error {
1212	if pc.RemoteDescription() == nil {
1213		return &rtcerr.InvalidStateError{Err: ErrNoRemoteDescription}
1214	}
1215
1216	candidateValue := strings.TrimPrefix(candidate.Candidate, "candidate:")
1217	attribute := sdp.NewAttribute("candidate", candidateValue)
1218	sdpCandidate, err := attribute.ToICECandidate()
1219	if err != nil {
1220		return err
1221	}
1222
1223	iceCandidate, err := newICECandidateFromSDP(sdpCandidate)
1224	if err != nil {
1225		return err
1226	}
1227
1228	return pc.iceTransport.AddRemoteCandidate(iceCandidate)
1229}
1230
1231// ICEConnectionState returns the ICE connection state of the
1232// PeerConnection instance.
1233func (pc *PeerConnection) ICEConnectionState() ICEConnectionState {
1234	pc.mu.RLock()
1235	defer pc.mu.RUnlock()
1236
1237	return pc.iceConnectionState
1238}
1239
1240// GetSenders returns the RTPSender that are currently attached to this PeerConnection
1241func (pc *PeerConnection) GetSenders() []*RTPSender {
1242	pc.mu.Lock()
1243	defer pc.mu.Unlock()
1244
1245	result := []*RTPSender{}
1246	for _, tranceiver := range pc.rtpTransceivers {
1247		if tranceiver.Sender != nil {
1248			result = append(result, tranceiver.Sender)
1249		}
1250	}
1251	return result
1252}
1253
1254// GetReceivers returns the RTPReceivers that are currently attached to this RTCPeerConnection
1255func (pc *PeerConnection) GetReceivers() []*RTPReceiver {
1256	pc.mu.Lock()
1257	defer pc.mu.Unlock()
1258
1259	result := []*RTPReceiver{}
1260	for _, tranceiver := range pc.rtpTransceivers {
1261		if tranceiver.Receiver != nil {
1262			result = append(result, tranceiver.Receiver)
1263		}
1264	}
1265	return result
1266}
1267
1268// GetTransceivers returns the RTCRtpTransceiver that are currently attached to this RTCPeerConnection
1269func (pc *PeerConnection) GetTransceivers() []*RTPTransceiver {
1270	pc.mu.Lock()
1271	defer pc.mu.Unlock()
1272
1273	return pc.rtpTransceivers
1274}
1275
1276// AddTrack adds a Track to the PeerConnection
1277func (pc *PeerConnection) AddTrack(track *Track) (*RTPSender, error) {
1278	if pc.isClosed.get() {
1279		return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
1280	}
1281	var transceiver *RTPTransceiver
1282	for _, t := range pc.GetTransceivers() {
1283		if !t.stopped &&
1284			t.Sender != nil &&
1285			!t.Sender.hasSent() &&
1286			t.Receiver != nil &&
1287			t.Receiver.Track() != nil &&
1288			t.Receiver.Track().Kind() == track.Kind() {
1289			transceiver = t
1290			break
1291		}
1292	}
1293	if transceiver != nil {
1294		if err := transceiver.setSendingTrack(track); err != nil {
1295			return nil, err
1296		}
1297	} else {
1298		receiver, err := pc.api.NewRTPReceiver(track.Kind(), pc.dtlsTransport)
1299		if err != nil {
1300			return nil, err
1301		}
1302
1303		sender, err := pc.api.NewRTPSender(track, pc.dtlsTransport)
1304		if err != nil {
1305			return nil, err
1306		}
1307		transceiver = pc.newRTPTransceiver(
1308			receiver,
1309			sender,
1310			RTPTransceiverDirectionSendrecv,
1311			track.Kind(),
1312		)
1313	}
1314
1315	return transceiver.Sender, nil
1316}
1317
1318// AddTransceiver Create a new RTCRtpTransceiver and add it to the set of transceivers.
1319// Deprecated: Use AddTrack, AddTransceiverFromKind or AddTransceiverFromTrack
1320func (pc *PeerConnection) AddTransceiver(trackOrKind RTPCodecType, init ...RtpTransceiverInit) (*RTPTransceiver, error) {
1321	return pc.AddTransceiverFromKind(trackOrKind, init...)
1322}
1323
1324// AddTransceiverFromKind Create a new RTCRtpTransceiver(SendRecv or RecvOnly) and add it to the set of transceivers.
1325func (pc *PeerConnection) AddTransceiverFromKind(kind RTPCodecType, init ...RtpTransceiverInit) (*RTPTransceiver, error) {
1326	direction := RTPTransceiverDirectionSendrecv
1327	if len(init) > 1 {
1328		return nil, fmt.Errorf("AddTransceiverFromKind only accepts one RtpTransceiverInit")
1329	} else if len(init) == 1 {
1330		direction = init[0].Direction
1331	}
1332
1333	switch direction {
1334	case RTPTransceiverDirectionSendrecv:
1335		receiver, err := pc.api.NewRTPReceiver(kind, pc.dtlsTransport)
1336		if err != nil {
1337			return nil, err
1338		}
1339
1340		codecs := pc.api.mediaEngine.GetCodecsByKind(kind)
1341		if len(codecs) == 0 {
1342			return nil, fmt.Errorf("no %s codecs found", kind.String())
1343		}
1344
1345		track, err := pc.NewTrack(codecs[0].PayloadType, mathRand.Uint32(), util.RandSeq(trackDefaultIDLength), util.RandSeq(trackDefaultLabelLength))
1346		if err != nil {
1347			return nil, err
1348		}
1349
1350		sender, err := pc.api.NewRTPSender(track, pc.dtlsTransport)
1351		if err != nil {
1352			return nil, err
1353		}
1354
1355		return pc.newRTPTransceiver(
1356			receiver,
1357			sender,
1358			RTPTransceiverDirectionSendrecv,
1359			kind,
1360		), nil
1361
1362	case RTPTransceiverDirectionRecvonly:
1363		receiver, err := pc.api.NewRTPReceiver(kind, pc.dtlsTransport)
1364		if err != nil {
1365			return nil, err
1366		}
1367
1368		return pc.newRTPTransceiver(
1369			receiver,
1370			nil,
1371			RTPTransceiverDirectionRecvonly,
1372			kind,
1373		), nil
1374	default:
1375		return nil, fmt.Errorf("AddTransceiverFromKind currently only supports recvonly and sendrecv")
1376	}
1377}
1378
1379// AddTransceiverFromTrack Creates a new send only transceiver and add it to the set of
1380func (pc *PeerConnection) AddTransceiverFromTrack(track *Track, init ...RtpTransceiverInit) (*RTPTransceiver, error) {
1381	direction := RTPTransceiverDirectionSendrecv
1382	if len(init) > 1 {
1383		return nil, fmt.Errorf("AddTransceiverFromTrack only accepts one RtpTransceiverInit")
1384	} else if len(init) == 1 {
1385		direction = init[0].Direction
1386	}
1387
1388	switch direction {
1389	case RTPTransceiverDirectionSendrecv:
1390		receiver, err := pc.api.NewRTPReceiver(track.Kind(), pc.dtlsTransport)
1391		if err != nil {
1392			return nil, err
1393		}
1394
1395		sender, err := pc.api.NewRTPSender(track, pc.dtlsTransport)
1396		if err != nil {
1397			return nil, err
1398		}
1399
1400		return pc.newRTPTransceiver(
1401			receiver,
1402			sender,
1403			RTPTransceiverDirectionSendrecv,
1404			track.Kind(),
1405		), nil
1406
1407	case RTPTransceiverDirectionSendonly:
1408		sender, err := pc.api.NewRTPSender(track, pc.dtlsTransport)
1409		if err != nil {
1410			return nil, err
1411		}
1412
1413		return pc.newRTPTransceiver(
1414			nil,
1415			sender,
1416			RTPTransceiverDirectionSendonly,
1417			track.Kind(),
1418		), nil
1419	default:
1420		return nil, fmt.Errorf("AddTransceiverFromTrack currently only supports sendonly and sendrecv")
1421	}
1422}
1423
1424// CreateDataChannel creates a new DataChannel object with the given label
1425// and optional DataChannelInit used to configure properties of the
1426// underlying channel such as data reliability.
1427func (pc *PeerConnection) CreateDataChannel(label string, options *DataChannelInit) (*DataChannel, error) {
1428	// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #2)
1429	if pc.isClosed.get() {
1430		return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
1431	}
1432
1433	params := &DataChannelParameters{
1434		Label:   label,
1435		Ordered: true,
1436	}
1437
1438	// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #19)
1439	if options != nil {
1440		params.ID = options.ID
1441	}
1442
1443	if options != nil {
1444		// Ordered indicates if data is allowed to be delivered out of order. The
1445		// default value of true, guarantees that data will be delivered in order.
1446		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #9)
1447		if options.Ordered != nil {
1448			params.Ordered = *options.Ordered
1449		}
1450
1451		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #7)
1452		if options.MaxPacketLifeTime != nil {
1453			params.MaxPacketLifeTime = options.MaxPacketLifeTime
1454		}
1455
1456		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #8)
1457		if options.MaxRetransmits != nil {
1458			params.MaxRetransmits = options.MaxRetransmits
1459		}
1460
1461		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #10)
1462		if options.Protocol != nil {
1463			params.Protocol = *options.Protocol
1464		}
1465
1466		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #11)
1467		if len(params.Protocol) > 65535 {
1468			return nil, &rtcerr.TypeError{Err: ErrProtocolTooLarge}
1469		}
1470
1471		// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #12)
1472		if options.Negotiated != nil {
1473			params.Negotiated = *options.Negotiated
1474		}
1475	}
1476
1477	d, err := pc.api.newDataChannel(params, pc.log)
1478	if err != nil {
1479		return nil, err
1480	}
1481
1482	// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #16)
1483	if d.maxPacketLifeTime != nil && d.maxRetransmits != nil {
1484		return nil, &rtcerr.TypeError{Err: ErrRetransmitsOrPacketLifeTime}
1485	}
1486
1487	pc.sctpTransport.lock.Lock()
1488	pc.sctpTransport.dataChannels = append(pc.sctpTransport.dataChannels, d)
1489	pc.sctpTransport.dataChannelsRequested++
1490	pc.sctpTransport.lock.Unlock()
1491
1492	// If SCTP already connected open all the channels
1493	if pc.sctpTransport.State() == SCTPTransportStateConnected {
1494		if err = d.open(pc.sctpTransport); err != nil {
1495			return nil, err
1496		}
1497	}
1498
1499	return d, nil
1500}
1501
1502// SetIdentityProvider is used to configure an identity provider to generate identity assertions
1503func (pc *PeerConnection) SetIdentityProvider(provider string) error {
1504	return fmt.Errorf("TODO SetIdentityProvider")
1505}
1506
1507// WriteRTCP sends a user provided RTCP packet to the connected peer
1508// If no peer is connected the packet is discarded
1509func (pc *PeerConnection) WriteRTCP(pkts []rtcp.Packet) error {
1510	raw, err := rtcp.Marshal(pkts)
1511	if err != nil {
1512		return err
1513	}
1514
1515	srtcpSession, err := pc.dtlsTransport.getSRTCPSession()
1516	if err != nil {
1517		return nil
1518	}
1519
1520	writeStream, err := srtcpSession.OpenWriteStream()
1521	if err != nil {
1522		return fmt.Errorf("WriteRTCP failed to open WriteStream: %v", err)
1523	}
1524
1525	if _, err := writeStream.Write(raw); err != nil {
1526		return err
1527	}
1528	return nil
1529}
1530
1531// Close ends the PeerConnection
1532func (pc *PeerConnection) Close() error {
1533	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #2)
1534	if pc.isClosed.get() {
1535		return nil
1536	}
1537
1538	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #3)
1539	pc.isClosed.set(true)
1540
1541	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #4)
1542	pc.signalingState = SignalingStateClosed
1543
1544	// Try closing everything and collect the errors
1545	// Shutdown strategy:
1546	// 1. All Conn close by closing their underlying Conn.
1547	// 2. A Mux stops this chain. It won't close the underlying
1548	//    Conn if one of the endpoints is closed down. To
1549	//    continue the chain the Mux has to be closed.
1550	var closeErrs []error
1551
1552	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #5)
1553	for _, t := range pc.rtpTransceivers {
1554		if err := t.Stop(); err != nil {
1555			closeErrs = append(closeErrs, err)
1556		}
1557	}
1558
1559	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #6)
1560	if pc.sctpTransport != nil {
1561		pc.sctpTransport.lock.Lock()
1562		for _, d := range pc.sctpTransport.dataChannels {
1563			d.setReadyState(DataChannelStateClosed)
1564		}
1565		pc.sctpTransport.lock.Unlock()
1566	}
1567
1568	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #7)
1569	if pc.sctpTransport != nil {
1570		if err := pc.sctpTransport.Stop(); err != nil {
1571			closeErrs = append(closeErrs, err)
1572		}
1573	}
1574
1575	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #8)
1576	if err := pc.dtlsTransport.Stop(); err != nil {
1577		closeErrs = append(closeErrs, err)
1578	}
1579
1580	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #9,#10,#11)
1581	if pc.iceTransport != nil {
1582		if err := pc.iceTransport.Stop(); err != nil {
1583			closeErrs = append(closeErrs, err)
1584		}
1585	}
1586
1587	// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #12)
1588	pc.updateConnectionState(pc.ICEConnectionState(), pc.dtlsTransport.State())
1589
1590	return util.FlattenErrs(closeErrs)
1591}
1592
1593func (pc *PeerConnection) addFingerprint(d *sdp.SessionDescription) error {
1594	// pion/webrtc#753
1595	fingerprints, err := pc.configuration.Certificates[0].GetFingerprints()
1596	if err != nil {
1597		return err
1598	}
1599	for _, fingerprint := range fingerprints {
1600		d.WithFingerprint(fingerprint.Algorithm, strings.ToUpper(fingerprint.Value))
1601	}
1602	return nil
1603}
1604
1605func (pc *PeerConnection) addTransceiverSDP(d *sdp.SessionDescription, midValue string, iceParams ICEParameters, candidates []ICECandidate, dtlsRole sdp.ConnectionRole, transceivers ...*RTPTransceiver) (bool, error) {
1606	if len(transceivers) < 1 {
1607		return false, fmt.Errorf("addTransceiverSDP() called with 0 transceivers")
1608	}
1609	// Use the first transceiver to generate the section attributes
1610	t := transceivers[0]
1611	media := sdp.NewJSEPMediaDescription(t.kind.String(), []string{}).
1612		WithValueAttribute(sdp.AttrKeyConnectionSetup, dtlsRole.String()).
1613		WithValueAttribute(sdp.AttrKeyMID, midValue).
1614		WithICECredentials(iceParams.UsernameFragment, iceParams.Password).
1615		WithPropertyAttribute(sdp.AttrKeyRTCPMux).
1616		WithPropertyAttribute(sdp.AttrKeyRTCPRsize)
1617
1618	codecs := pc.api.mediaEngine.GetCodecsByKind(t.kind)
1619	for _, codec := range codecs {
1620		media.WithCodec(codec.PayloadType, codec.Name, codec.ClockRate, codec.Channels, codec.SDPFmtpLine)
1621
1622		for _, feedback := range codec.RTPCodecCapability.RTCPFeedback {
1623			media.WithValueAttribute("rtcp-fb", fmt.Sprintf("%d %s %s", codec.PayloadType, feedback.Type, feedback.Parameter))
1624		}
1625	}
1626	if len(codecs) == 0 {
1627		// Explicitly reject track if we don't have the codec
1628		d.WithMedia(&sdp.MediaDescription{
1629			MediaName: sdp.MediaName{
1630				Media:   t.kind.String(),
1631				Port:    sdp.RangedPort{Value: 0},
1632				Protos:  []string{"UDP", "TLS", "RTP", "SAVPF"},
1633				Formats: []string{"0"},
1634			},
1635		})
1636		return false, nil
1637	}
1638
1639	for _, mt := range transceivers {
1640		if mt.Sender != nil && mt.Sender.track != nil {
1641			track := mt.Sender.track
1642			media = media.WithMediaSource(track.SSRC(), track.Label() /* cname */, track.Label() /* streamLabel */, track.ID())
1643			if pc.configuration.SDPSemantics == SDPSemanticsUnifiedPlan {
1644				media = media.WithPropertyAttribute("msid:" + track.Label() + " " + track.ID())
1645				break
1646			}
1647		}
1648	}
1649
1650	media = media.WithPropertyAttribute(t.Direction.String())
1651
1652	addCandidatesToMediaDescriptions(candidates, media)
1653	d.WithMedia(media)
1654
1655	return true, nil
1656}
1657
1658func (pc *PeerConnection) addDataMediaSection(d *sdp.SessionDescription, midValue string, iceParams ICEParameters, candidates []ICECandidate, dtlsRole sdp.ConnectionRole) {
1659	media := (&sdp.MediaDescription{
1660		MediaName: sdp.MediaName{
1661			Media:   "application",
1662			Port:    sdp.RangedPort{Value: 9},
1663			Protos:  []string{"DTLS", "SCTP"},
1664			Formats: []string{"5000"},
1665		},
1666		ConnectionInformation: &sdp.ConnectionInformation{
1667			NetworkType: "IN",
1668			AddressType: "IP4",
1669			Address: &sdp.Address{
1670				Address: "0.0.0.0",
1671			},
1672		},
1673	}).
1674		WithValueAttribute(sdp.AttrKeyConnectionSetup, dtlsRole.String()).
1675		WithValueAttribute(sdp.AttrKeyMID, midValue).
1676		WithPropertyAttribute(RTPTransceiverDirectionSendrecv.String()).
1677		WithPropertyAttribute("sctpmap:5000 webrtc-datachannel 1024").
1678		WithICECredentials(iceParams.UsernameFragment, iceParams.Password)
1679
1680	addCandidatesToMediaDescriptions(candidates, media)
1681	d.WithMedia(media)
1682}
1683
1684// NewTrack Creates a new Track
1685func (pc *PeerConnection) NewTrack(payloadType uint8, ssrc uint32, id, label string) (*Track, error) {
1686	codec, err := pc.api.mediaEngine.getCodec(payloadType)
1687	if err != nil {
1688		return nil, err
1689	} else if codec.Payloader == nil {
1690		return nil, fmt.Errorf("codec payloader not set")
1691	}
1692
1693	return NewTrack(payloadType, ssrc, id, label, codec)
1694}
1695
1696func (pc *PeerConnection) newRTPTransceiver(
1697	receiver *RTPReceiver,
1698	sender *RTPSender,
1699	direction RTPTransceiverDirection,
1700	kind RTPCodecType,
1701) *RTPTransceiver {
1702	t := &RTPTransceiver{
1703		Receiver:  receiver,
1704		Sender:    sender,
1705		Direction: direction,
1706		kind:      kind,
1707	}
1708	pc.mu.Lock()
1709	defer pc.mu.Unlock()
1710	pc.rtpTransceivers = append(pc.rtpTransceivers, t)
1711	return t
1712}
1713
1714func (pc *PeerConnection) populateLocalCandidates(orig *SessionDescription) *SessionDescription {
1715	if orig == nil {
1716		return nil
1717	} else if pc.iceGatherer == nil {
1718		return orig
1719	}
1720
1721	candidates, err := pc.iceGatherer.GetLocalCandidates()
1722	if err != nil {
1723		return orig
1724	}
1725
1726	parsed := pc.pendingLocalDescription.parsed
1727	for _, m := range parsed.MediaDescriptions {
1728		addCandidatesToMediaDescriptions(candidates, m)
1729	}
1730	sdp, err := parsed.Marshal()
1731	if err != nil {
1732		return orig
1733	}
1734
1735	return &SessionDescription{
1736		SDP:  string(sdp),
1737		Type: pc.pendingLocalDescription.Type,
1738	}
1739}
1740
1741// CurrentLocalDescription represents the local description that was
1742// successfully negotiated the last time the PeerConnection transitioned
1743// into the stable state plus any local candidates that have been generated
1744// by the ICEAgent since the offer or answer was created.
1745func (pc *PeerConnection) CurrentLocalDescription() *SessionDescription {
1746	return pc.populateLocalCandidates(pc.currentLocalDescription)
1747}
1748
1749// PendingLocalDescription represents a local description that is in the
1750// process of being negotiated plus any local candidates that have been
1751// generated by the ICEAgent since the offer or answer was created. If the
1752// PeerConnection is in the stable state, the value is null.
1753func (pc *PeerConnection) PendingLocalDescription() *SessionDescription {
1754	return pc.populateLocalCandidates(pc.pendingLocalDescription)
1755}
1756
1757// CurrentRemoteDescription represents the last remote description that was
1758// successfully negotiated the last time the PeerConnection transitioned
1759// into the stable state plus any remote candidates that have been supplied
1760// via AddICECandidate() since the offer or answer was created.
1761func (pc *PeerConnection) CurrentRemoteDescription() *SessionDescription {
1762	return pc.currentRemoteDescription
1763}
1764
1765// PendingRemoteDescription represents a remote description that is in the
1766// process of being negotiated, complete with any remote candidates that
1767// have been supplied via AddICECandidate() since the offer or answer was
1768// created. If the PeerConnection is in the stable state, the value is
1769// null.
1770func (pc *PeerConnection) PendingRemoteDescription() *SessionDescription {
1771	return pc.pendingRemoteDescription
1772}
1773
1774// SignalingState attribute returns the signaling state of the
1775// PeerConnection instance.
1776func (pc *PeerConnection) SignalingState() SignalingState {
1777	return pc.signalingState
1778}
1779
1780// ICEGatheringState attribute returns the ICE gathering state of the
1781// PeerConnection instance.
1782func (pc *PeerConnection) ICEGatheringState() ICEGatheringState {
1783	switch pc.iceGatherer.State() {
1784	case ICEGathererStateNew:
1785		return ICEGatheringStateNew
1786	case ICEGathererStateGathering:
1787		return ICEGatheringStateGathering
1788	default:
1789		return ICEGatheringStateComplete
1790	}
1791}
1792
1793// ConnectionState attribute returns the connection state of the
1794// PeerConnection instance.
1795func (pc *PeerConnection) ConnectionState() PeerConnectionState {
1796	return pc.connectionState
1797}
1798
1799// GetStats return data providing statistics about the overall connection
1800func (pc *PeerConnection) GetStats() StatsReport {
1801	var (
1802		dataChannelsAccepted  uint32
1803		dataChannelsClosed    uint32
1804		dataChannelsOpened    uint32
1805		dataChannelsRequested uint32
1806	)
1807	statsCollector := newStatsReportCollector()
1808	statsCollector.Collecting()
1809
1810	pc.mu.Lock()
1811	if pc.iceGatherer != nil {
1812		pc.iceGatherer.collectStats(statsCollector)
1813	}
1814	if pc.iceTransport != nil {
1815		pc.iceTransport.collectStats(statsCollector)
1816	}
1817
1818	if pc.sctpTransport != nil {
1819		pc.sctpTransport.lock.Lock()
1820		dataChannels := append([]*DataChannel{}, pc.sctpTransport.dataChannels...)
1821		dataChannelsAccepted = pc.sctpTransport.dataChannelsAccepted
1822		dataChannelsOpened = pc.sctpTransport.dataChannelsOpened
1823		dataChannelsRequested = pc.sctpTransport.dataChannelsRequested
1824		pc.sctpTransport.lock.Unlock()
1825
1826		for _, d := range dataChannels {
1827			state := d.ReadyState()
1828			if state != DataChannelStateConnecting && state != DataChannelStateOpen {
1829				dataChannelsClosed++
1830			}
1831
1832			d.collectStats(statsCollector)
1833		}
1834		pc.sctpTransport.collectStats(statsCollector)
1835	}
1836
1837	stats := PeerConnectionStats{
1838		Timestamp:             statsTimestampNow(),
1839		Type:                  StatsTypePeerConnection,
1840		ID:                    pc.statsID,
1841		DataChannelsAccepted:  dataChannelsAccepted,
1842		DataChannelsClosed:    dataChannelsClosed,
1843		DataChannelsOpened:    dataChannelsOpened,
1844		DataChannelsRequested: dataChannelsRequested,
1845	}
1846	pc.mu.Unlock()
1847
1848	statsCollector.Collect(stats.ID, stats)
1849	return statsCollector.Ready()
1850}
1851
1852// Start all transports. PeerConnection now has enough state
1853func (pc *PeerConnection) startTransports(iceRole ICERole, dtlsRole DTLSRole, remoteUfrag, remotePwd, fingerprint, fingerprintHash string) {
1854	// Start the ice transport
1855	err := pc.iceTransport.Start(
1856		pc.iceGatherer,
1857		ICEParameters{
1858			UsernameFragment: remoteUfrag,
1859			Password:         remotePwd,
1860			ICELite:          false,
1861		},
1862		&iceRole,
1863	)
1864	if err != nil {
1865		pc.log.Warnf("Failed to start manager: %s", err)
1866		return
1867	}
1868
1869	// Start the dtls transport
1870	err = pc.dtlsTransport.Start(DTLSParameters{
1871		Role:         dtlsRole,
1872		Fingerprints: []DTLSFingerprint{{Algorithm: fingerprintHash, Value: fingerprint}},
1873	})
1874	pc.updateConnectionState(pc.ICEConnectionState(), pc.dtlsTransport.State())
1875	if err != nil {
1876		pc.log.Warnf("Failed to start manager: %s", err)
1877		return
1878	}
1879
1880	pc.openSRTP()
1881
1882	for _, tranceiver := range pc.GetTransceivers() {
1883		if tranceiver.Sender != nil {
1884			err = tranceiver.Sender.Send(RTPSendParameters{
1885				Encodings: RTPEncodingParameters{
1886					RTPCodingParameters{
1887						SSRC:        tranceiver.Sender.track.SSRC(),
1888						PayloadType: tranceiver.Sender.track.PayloadType(),
1889					},
1890				}})
1891			if err != nil {
1892				pc.log.Warnf("Failed to start Sender: %s", err)
1893			}
1894		}
1895	}
1896
1897	go pc.drainSRTP()
1898
1899	// Start sctp
1900	if err = pc.sctpTransport.Start(SCTPCapabilities{
1901		MaxMessageSize: 0,
1902	}); err != nil {
1903		pc.log.Warnf("Failed to start SCTP: %s", err)
1904		if err = pc.sctpTransport.Stop(); err != nil {
1905			pc.log.Warnf("Failed to stop SCTPTransport: %s", err)
1906		}
1907
1908		return
1909	}
1910
1911	// DataChannels that need to be opened now that SCTP is available
1912	// make a copy we may have incoming DataChannels mutating this while we open
1913	pc.sctpTransport.lock.RLock()
1914	dataChannels := append([]*DataChannel{}, pc.sctpTransport.dataChannels...)
1915	pc.sctpTransport.lock.RUnlock()
1916
1917	var openedDCCount uint32
1918	for _, d := range dataChannels {
1919		if d.ReadyState() == DataChannelStateConnecting {
1920			err := d.open(pc.sctpTransport)
1921			if err != nil {
1922				pc.log.Warnf("failed to open data channel: %s", err)
1923				continue
1924			}
1925			openedDCCount++
1926		}
1927	}
1928
1929	pc.sctpTransport.lock.Lock()
1930	pc.sctpTransport.dataChannelsOpened += openedDCCount
1931	pc.sctpTransport.lock.Unlock()
1932
1933}
1934
1935func addCandidatesToMediaDescriptions(candidates []ICECandidate, m *sdp.MediaDescription) {
1936	for _, c := range candidates {
1937		sdpCandidate := iceCandidateToSDP(c)
1938		sdpCandidate.ExtensionAttributes = append(sdpCandidate.ExtensionAttributes, sdp.ICECandidateAttribute{Key: "generation", Value: "0"})
1939		sdpCandidate.Component = 1
1940		m.WithICECandidate(sdpCandidate)
1941		sdpCandidate.Component = 2
1942		m.WithICECandidate(sdpCandidate)
1943	}
1944	if len(candidates) != 0 {
1945		m.WithPropertyAttribute("end-of-candidates")
1946	}
1947}
1948