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