github.com/pion/webrtc/v4@v4.0.1/peerconnection.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 //go:build !js 5 // +build !js 6 7 package webrtc 8 9 import ( 10 "crypto/ecdsa" 11 "crypto/elliptic" 12 "crypto/rand" 13 "errors" 14 "fmt" 15 "io" 16 "strconv" 17 "strings" 18 "sync" 19 "sync/atomic" 20 "time" 21 22 "github.com/pion/ice/v4" 23 "github.com/pion/interceptor" 24 "github.com/pion/logging" 25 "github.com/pion/rtcp" 26 "github.com/pion/sdp/v3" 27 "github.com/pion/srtp/v3" 28 "github.com/pion/webrtc/v4/internal/util" 29 "github.com/pion/webrtc/v4/pkg/rtcerr" 30 ) 31 32 // PeerConnection represents a WebRTC connection that establishes a 33 // peer-to-peer communications with another PeerConnection instance in a 34 // browser, or to another endpoint implementing the required protocols. 35 type PeerConnection struct { 36 statsID string 37 mu sync.RWMutex 38 39 sdpOrigin sdp.Origin 40 41 // ops is an operations queue which will ensure the enqueued actions are 42 // executed in order. It is used for asynchronously, but serially processing 43 // remote and local descriptions 44 ops *operations 45 46 configuration Configuration 47 48 currentLocalDescription *SessionDescription 49 pendingLocalDescription *SessionDescription 50 currentRemoteDescription *SessionDescription 51 pendingRemoteDescription *SessionDescription 52 signalingState SignalingState 53 iceConnectionState atomic.Value // ICEConnectionState 54 connectionState atomic.Value // PeerConnectionState 55 56 idpLoginURL *string 57 58 isClosed *atomicBool 59 isGracefullyClosingOrClosed bool 60 isCloseDone chan struct{} 61 isGracefulCloseDone chan struct{} 62 isNegotiationNeeded *atomicBool 63 updateNegotiationNeededFlagOnEmptyChain *atomicBool 64 65 lastOffer string 66 lastAnswer string 67 68 // a value containing the last known greater mid value 69 // we internally generate mids as numbers. Needed since JSEP 70 // requires that when reusing a media section a new unique mid 71 // should be defined (see JSEP 3.4.1). 72 greaterMid int 73 74 rtpTransceivers []*RTPTransceiver 75 nonMediaBandwidthProbe atomic.Value // RTPReceiver 76 77 onSignalingStateChangeHandler func(SignalingState) 78 onICEConnectionStateChangeHandler atomic.Value // func(ICEConnectionState) 79 onConnectionStateChangeHandler atomic.Value // func(PeerConnectionState) 80 onTrackHandler func(*TrackRemote, *RTPReceiver) 81 onDataChannelHandler func(*DataChannel) 82 onNegotiationNeededHandler atomic.Value // func() 83 84 iceGatherer *ICEGatherer 85 iceTransport *ICETransport 86 dtlsTransport *DTLSTransport 87 sctpTransport *SCTPTransport 88 89 // A reference to the associated API state used by this connection 90 api *API 91 log logging.LeveledLogger 92 93 interceptorRTCPWriter interceptor.RTCPWriter 94 } 95 96 // NewPeerConnection creates a PeerConnection with the default codecs and interceptors. 97 // 98 // If you wish to customize the set of available codecs and/or the set of active interceptors, 99 // create an API with a custom MediaEngine and/or interceptor.Registry, 100 // then call API.NewPeerConnection() instead of this function. 101 func NewPeerConnection(configuration Configuration) (*PeerConnection, error) { 102 api := NewAPI() 103 return api.NewPeerConnection(configuration) 104 } 105 106 // NewPeerConnection creates a new PeerConnection with the provided configuration against the received API object 107 func (api *API) NewPeerConnection(configuration Configuration) (*PeerConnection, error) { 108 // https://w3c.github.io/webrtc-pc/#constructor (Step #2) 109 // Some variables defined explicitly despite their implicit zero values to 110 // allow better readability to understand what is happening. 111 112 pc := &PeerConnection{ 113 statsID: fmt.Sprintf("PeerConnection-%d", time.Now().UnixNano()), 114 configuration: Configuration{ 115 ICEServers: []ICEServer{}, 116 ICETransportPolicy: ICETransportPolicyAll, 117 BundlePolicy: BundlePolicyBalanced, 118 RTCPMuxPolicy: RTCPMuxPolicyRequire, 119 Certificates: []Certificate{}, 120 ICECandidatePoolSize: 0, 121 }, 122 isClosed: &atomicBool{}, 123 isCloseDone: make(chan struct{}), 124 isGracefulCloseDone: make(chan struct{}), 125 isNegotiationNeeded: &atomicBool{}, 126 updateNegotiationNeededFlagOnEmptyChain: &atomicBool{}, 127 lastOffer: "", 128 lastAnswer: "", 129 greaterMid: -1, 130 signalingState: SignalingStateStable, 131 132 api: api, 133 log: api.settingEngine.LoggerFactory.NewLogger("pc"), 134 } 135 pc.ops = newOperations(pc.updateNegotiationNeededFlagOnEmptyChain, pc.onNegotiationNeeded) 136 137 pc.iceConnectionState.Store(ICEConnectionStateNew) 138 pc.connectionState.Store(PeerConnectionStateNew) 139 140 i, err := api.interceptorRegistry.Build("") 141 if err != nil { 142 return nil, err 143 } 144 145 pc.api = &API{ 146 settingEngine: api.settingEngine, 147 interceptor: i, 148 } 149 150 if api.settingEngine.disableMediaEngineCopy { 151 pc.api.mediaEngine = api.mediaEngine 152 } else { 153 pc.api.mediaEngine = api.mediaEngine.copy() 154 } 155 156 if err = pc.initConfiguration(configuration); err != nil { 157 return nil, err 158 } 159 160 pc.iceGatherer, err = pc.createICEGatherer() 161 if err != nil { 162 return nil, err 163 } 164 165 // Create the ice transport 166 iceTransport := pc.createICETransport() 167 pc.iceTransport = iceTransport 168 169 // Create the DTLS transport 170 dtlsTransport, err := pc.api.NewDTLSTransport(pc.iceTransport, pc.configuration.Certificates) 171 if err != nil { 172 return nil, err 173 } 174 pc.dtlsTransport = dtlsTransport 175 176 // Create the SCTP transport 177 pc.sctpTransport = pc.api.NewSCTPTransport(pc.dtlsTransport) 178 179 // Wire up the on datachannel handler 180 pc.sctpTransport.OnDataChannel(func(d *DataChannel) { 181 pc.mu.RLock() 182 handler := pc.onDataChannelHandler 183 pc.mu.RUnlock() 184 if handler != nil { 185 handler(d) 186 } 187 }) 188 189 pc.interceptorRTCPWriter = pc.api.interceptor.BindRTCPWriter(interceptor.RTCPWriterFunc(pc.writeRTCP)) 190 191 return pc, nil 192 } 193 194 // initConfiguration defines validation of the specified Configuration and 195 // its assignment to the internal configuration variable. This function differs 196 // from its SetConfiguration counterpart because most of the checks do not 197 // include verification statements related to the existing state. Thus the 198 // function describes only minor verification of some the struct variables. 199 func (pc *PeerConnection) initConfiguration(configuration Configuration) error { 200 if configuration.PeerIdentity != "" { 201 pc.configuration.PeerIdentity = configuration.PeerIdentity 202 } 203 204 // https://www.w3.org/TR/webrtc/#constructor (step #3) 205 if len(configuration.Certificates) > 0 { 206 now := time.Now() 207 for _, x509Cert := range configuration.Certificates { 208 if !x509Cert.Expires().IsZero() && now.After(x509Cert.Expires()) { 209 return &rtcerr.InvalidAccessError{Err: ErrCertificateExpired} 210 } 211 pc.configuration.Certificates = append(pc.configuration.Certificates, x509Cert) 212 } 213 } else { 214 sk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 215 if err != nil { 216 return &rtcerr.UnknownError{Err: err} 217 } 218 certificate, err := GenerateCertificate(sk) 219 if err != nil { 220 return err 221 } 222 pc.configuration.Certificates = []Certificate{*certificate} 223 } 224 225 if configuration.BundlePolicy != BundlePolicyUnknown { 226 pc.configuration.BundlePolicy = configuration.BundlePolicy 227 } 228 229 if configuration.RTCPMuxPolicy != RTCPMuxPolicyUnknown { 230 pc.configuration.RTCPMuxPolicy = configuration.RTCPMuxPolicy 231 } 232 233 if configuration.ICECandidatePoolSize != 0 { 234 pc.configuration.ICECandidatePoolSize = configuration.ICECandidatePoolSize 235 } 236 237 pc.configuration.ICETransportPolicy = configuration.ICETransportPolicy 238 pc.configuration.SDPSemantics = configuration.SDPSemantics 239 240 sanitizedICEServers := configuration.getICEServers() 241 if len(sanitizedICEServers) > 0 { 242 for _, server := range sanitizedICEServers { 243 if err := server.validate(); err != nil { 244 return err 245 } 246 } 247 pc.configuration.ICEServers = sanitizedICEServers 248 } 249 250 return nil 251 } 252 253 // OnSignalingStateChange sets an event handler which is invoked when the 254 // peer connection's signaling state changes 255 func (pc *PeerConnection) OnSignalingStateChange(f func(SignalingState)) { 256 pc.mu.Lock() 257 defer pc.mu.Unlock() 258 pc.onSignalingStateChangeHandler = f 259 } 260 261 func (pc *PeerConnection) onSignalingStateChange(newState SignalingState) { 262 pc.mu.RLock() 263 handler := pc.onSignalingStateChangeHandler 264 pc.mu.RUnlock() 265 266 pc.log.Infof("signaling state changed to %s", newState) 267 if handler != nil { 268 go handler(newState) 269 } 270 } 271 272 // OnDataChannel sets an event handler which is invoked when a data 273 // channel message arrives from a remote peer. 274 func (pc *PeerConnection) OnDataChannel(f func(*DataChannel)) { 275 pc.mu.Lock() 276 defer pc.mu.Unlock() 277 pc.onDataChannelHandler = f 278 } 279 280 // OnNegotiationNeeded sets an event handler which is invoked when 281 // a change has occurred which requires session negotiation 282 func (pc *PeerConnection) OnNegotiationNeeded(f func()) { 283 pc.onNegotiationNeededHandler.Store(f) 284 } 285 286 // onNegotiationNeeded enqueues negotiationNeededOp if necessary 287 // caller of this method should hold `pc.mu` lock 288 // https://www.w3.org/TR/webrtc/#dfn-update-the-negotiation-needed-flag 289 func (pc *PeerConnection) onNegotiationNeeded() { 290 // 4.7.3.1 If the length of connection.[[Operations]] is not 0, then set 291 // connection.[[UpdateNegotiationNeededFlagOnEmptyChain]] to true, and abort these steps. 292 if !pc.ops.IsEmpty() { 293 pc.updateNegotiationNeededFlagOnEmptyChain.set(true) 294 return 295 } 296 pc.ops.Enqueue(pc.negotiationNeededOp) 297 } 298 299 // https://www.w3.org/TR/webrtc/#dfn-update-the-negotiation-needed-flag 300 func (pc *PeerConnection) negotiationNeededOp() { 301 // 4.7.3.2.1 If connection.[[IsClosed]] is true, abort these steps. 302 if pc.isClosed.get() { 303 return 304 } 305 306 // 4.7.3.2.2 If the length of connection.[[Operations]] is not 0, 307 // then set connection.[[UpdateNegotiationNeededFlagOnEmptyChain]] to 308 // true, and abort these steps. 309 if !pc.ops.IsEmpty() { 310 pc.updateNegotiationNeededFlagOnEmptyChain.set(true) 311 return 312 } 313 314 // 4.7.3.2.3 If connection's signaling state is not "stable", abort these steps. 315 if pc.SignalingState() != SignalingStateStable { 316 return 317 } 318 319 // 4.7.3.2.4 If the result of checking if negotiation is needed is false, 320 // clear the negotiation-needed flag by setting connection.[[NegotiationNeeded]] 321 // to false, and abort these steps. 322 if !pc.checkNegotiationNeeded() { 323 pc.isNegotiationNeeded.set(false) 324 return 325 } 326 327 // 4.7.3.2.5 If connection.[[NegotiationNeeded]] is already true, abort these steps. 328 if pc.isNegotiationNeeded.get() { 329 return 330 } 331 332 // 4.7.3.2.6 Set connection.[[NegotiationNeeded]] to true. 333 pc.isNegotiationNeeded.set(true) 334 335 // 4.7.3.2.7 Fire an event named negotiationneeded at connection. 336 if handler, ok := pc.onNegotiationNeededHandler.Load().(func()); ok && handler != nil { 337 handler() 338 } 339 } 340 341 func (pc *PeerConnection) checkNegotiationNeeded() bool { //nolint:gocognit 342 // To check if negotiation is needed for connection, perform the following checks: 343 // Skip 1, 2 steps 344 // Step 3 345 pc.mu.Lock() 346 defer pc.mu.Unlock() 347 348 localDesc := pc.currentLocalDescription 349 remoteDesc := pc.currentRemoteDescription 350 351 if localDesc == nil { 352 return true 353 } 354 355 pc.sctpTransport.lock.Lock() 356 lenDataChannel := len(pc.sctpTransport.dataChannels) 357 pc.sctpTransport.lock.Unlock() 358 359 if lenDataChannel != 0 && haveDataChannel(localDesc) == nil { 360 return true 361 } 362 363 for _, t := range pc.rtpTransceivers { 364 // https://www.w3.org/TR/webrtc/#dfn-update-the-negotiation-needed-flag 365 // Step 5.1 366 // if t.stopping && !t.stopped { 367 // return true 368 // } 369 m := getByMid(t.Mid(), localDesc) 370 // Step 5.2 371 if !t.stopped && m == nil { 372 return true 373 } 374 if !t.stopped && m != nil { 375 // Step 5.3.1 376 if t.Direction() == RTPTransceiverDirectionSendrecv || t.Direction() == RTPTransceiverDirectionSendonly { 377 descMsid, okMsid := m.Attribute(sdp.AttrKeyMsid) 378 sender := t.Sender() 379 if sender == nil { 380 return true 381 } 382 track := sender.Track() 383 if track == nil { 384 // Situation when sender's track is nil could happen when 385 // a) replaceTrack(nil) is called 386 // b) removeTrack() is called, changing the transceiver's direction to inactive 387 // As t.Direction() in this branch is either sendrecv or sendonly, we believe (a) option is the case 388 // As calling replaceTrack does not require renegotiation, we skip check for this transceiver 389 continue 390 } 391 if !okMsid || descMsid != track.StreamID()+" "+track.ID() { 392 return true 393 } 394 } 395 switch localDesc.Type { 396 case SDPTypeOffer: 397 // Step 5.3.2 398 rm := getByMid(t.Mid(), remoteDesc) 399 if rm == nil { 400 return true 401 } 402 403 if getPeerDirection(m) != t.Direction() && getPeerDirection(rm) != t.Direction().Revers() { 404 return true 405 } 406 case SDPTypeAnswer: 407 // Step 5.3.3 408 if _, ok := m.Attribute(t.Direction().String()); !ok { 409 return true 410 } 411 default: 412 } 413 } 414 // Step 5.4 415 if t.stopped && t.Mid() != "" { 416 if getByMid(t.Mid(), localDesc) != nil || getByMid(t.Mid(), remoteDesc) != nil { 417 return true 418 } 419 } 420 } 421 // Step 6 422 return false 423 } 424 425 // OnICECandidate sets an event handler which is invoked when a new ICE 426 // candidate is found. 427 // ICE candidate gathering only begins when SetLocalDescription or 428 // SetRemoteDescription is called. 429 // Take note that the handler will be called with a nil pointer when 430 // gathering is finished. 431 func (pc *PeerConnection) OnICECandidate(f func(*ICECandidate)) { 432 pc.iceGatherer.OnLocalCandidate(f) 433 } 434 435 // OnICEGatheringStateChange sets an event handler which is invoked when the 436 // ICE candidate gathering state has changed. 437 func (pc *PeerConnection) OnICEGatheringStateChange(f func(ICEGatheringState)) { 438 pc.iceGatherer.OnStateChange( 439 func(gathererState ICEGathererState) { 440 switch gathererState { 441 case ICEGathererStateGathering: 442 f(ICEGatheringStateGathering) 443 case ICEGathererStateComplete: 444 f(ICEGatheringStateComplete) 445 default: 446 // Other states ignored 447 } 448 }) 449 } 450 451 // OnTrack sets an event handler which is called when remote track 452 // arrives from a remote peer. 453 func (pc *PeerConnection) OnTrack(f func(*TrackRemote, *RTPReceiver)) { 454 pc.mu.Lock() 455 defer pc.mu.Unlock() 456 pc.onTrackHandler = f 457 } 458 459 func (pc *PeerConnection) onTrack(t *TrackRemote, r *RTPReceiver) { 460 pc.mu.RLock() 461 handler := pc.onTrackHandler 462 pc.mu.RUnlock() 463 464 pc.log.Debugf("got new track: %+v", t) 465 if t != nil { 466 if handler != nil { 467 go handler(t, r) 468 } else { 469 pc.log.Warnf("OnTrack unset, unable to handle incoming media streams") 470 } 471 } 472 } 473 474 // OnICEConnectionStateChange sets an event handler which is called 475 // when an ICE connection state is changed. 476 func (pc *PeerConnection) OnICEConnectionStateChange(f func(ICEConnectionState)) { 477 pc.onICEConnectionStateChangeHandler.Store(f) 478 } 479 480 func (pc *PeerConnection) onICEConnectionStateChange(cs ICEConnectionState) { 481 pc.iceConnectionState.Store(cs) 482 pc.log.Infof("ICE connection state changed: %s", cs) 483 if handler, ok := pc.onICEConnectionStateChangeHandler.Load().(func(ICEConnectionState)); ok && handler != nil { 484 handler(cs) 485 } 486 } 487 488 // OnConnectionStateChange sets an event handler which is called 489 // when the PeerConnectionState has changed 490 func (pc *PeerConnection) OnConnectionStateChange(f func(PeerConnectionState)) { 491 pc.onConnectionStateChangeHandler.Store(f) 492 } 493 494 func (pc *PeerConnection) onConnectionStateChange(cs PeerConnectionState) { 495 pc.connectionState.Store(cs) 496 pc.log.Infof("peer connection state changed: %s", cs) 497 if handler, ok := pc.onConnectionStateChangeHandler.Load().(func(PeerConnectionState)); ok && handler != nil { 498 go handler(cs) 499 } 500 } 501 502 // SetConfiguration updates the configuration of this PeerConnection object. 503 func (pc *PeerConnection) SetConfiguration(configuration Configuration) error { //nolint:gocognit 504 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-setconfiguration (step #2) 505 if pc.isClosed.get() { 506 return &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 507 } 508 509 // https://www.w3.org/TR/webrtc/#set-the-configuration (step #3) 510 if configuration.PeerIdentity != "" { 511 if configuration.PeerIdentity != pc.configuration.PeerIdentity { 512 return &rtcerr.InvalidModificationError{Err: ErrModifyingPeerIdentity} 513 } 514 pc.configuration.PeerIdentity = configuration.PeerIdentity 515 } 516 517 // https://www.w3.org/TR/webrtc/#set-the-configuration (step #4) 518 if len(configuration.Certificates) > 0 { 519 if len(configuration.Certificates) != len(pc.configuration.Certificates) { 520 return &rtcerr.InvalidModificationError{Err: ErrModifyingCertificates} 521 } 522 523 for i, certificate := range configuration.Certificates { 524 if !pc.configuration.Certificates[i].Equals(certificate) { 525 return &rtcerr.InvalidModificationError{Err: ErrModifyingCertificates} 526 } 527 } 528 pc.configuration.Certificates = configuration.Certificates 529 } 530 531 // https://www.w3.org/TR/webrtc/#set-the-configuration (step #5) 532 if configuration.BundlePolicy != BundlePolicyUnknown { 533 if configuration.BundlePolicy != pc.configuration.BundlePolicy { 534 return &rtcerr.InvalidModificationError{Err: ErrModifyingBundlePolicy} 535 } 536 pc.configuration.BundlePolicy = configuration.BundlePolicy 537 } 538 539 // https://www.w3.org/TR/webrtc/#set-the-configuration (step #6) 540 if configuration.RTCPMuxPolicy != RTCPMuxPolicyUnknown { 541 if configuration.RTCPMuxPolicy != pc.configuration.RTCPMuxPolicy { 542 return &rtcerr.InvalidModificationError{Err: ErrModifyingRTCPMuxPolicy} 543 } 544 pc.configuration.RTCPMuxPolicy = configuration.RTCPMuxPolicy 545 } 546 547 // https://www.w3.org/TR/webrtc/#set-the-configuration (step #7) 548 if configuration.ICECandidatePoolSize != 0 { 549 if pc.configuration.ICECandidatePoolSize != configuration.ICECandidatePoolSize && 550 pc.LocalDescription() != nil { 551 return &rtcerr.InvalidModificationError{Err: ErrModifyingICECandidatePoolSize} 552 } 553 pc.configuration.ICECandidatePoolSize = configuration.ICECandidatePoolSize 554 } 555 556 // https://www.w3.org/TR/webrtc/#set-the-configuration (step #8) 557 pc.configuration.ICETransportPolicy = configuration.ICETransportPolicy 558 559 // https://www.w3.org/TR/webrtc/#set-the-configuration (step #11) 560 if len(configuration.ICEServers) > 0 { 561 // https://www.w3.org/TR/webrtc/#set-the-configuration (step #11.3) 562 for _, server := range configuration.ICEServers { 563 if err := server.validate(); err != nil { 564 return err 565 } 566 } 567 pc.configuration.ICEServers = configuration.ICEServers 568 } 569 return nil 570 } 571 572 // GetConfiguration returns a Configuration object representing the current 573 // configuration of this PeerConnection object. The returned object is a 574 // copy and direct mutation on it will not take affect until SetConfiguration 575 // has been called with Configuration passed as its only argument. 576 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-getconfiguration 577 func (pc *PeerConnection) GetConfiguration() Configuration { 578 return pc.configuration 579 } 580 581 func (pc *PeerConnection) getStatsID() string { 582 pc.mu.RLock() 583 defer pc.mu.RUnlock() 584 return pc.statsID 585 } 586 587 // hasLocalDescriptionChanged returns whether local media (rtpTransceivers) has changed 588 // caller of this method should hold `pc.mu` lock 589 func (pc *PeerConnection) hasLocalDescriptionChanged(desc *SessionDescription) bool { 590 for _, t := range pc.rtpTransceivers { 591 m := getByMid(t.Mid(), desc) 592 if m == nil { 593 return true 594 } 595 596 if getPeerDirection(m) != t.Direction() { 597 return true 598 } 599 } 600 return false 601 } 602 603 // CreateOffer starts the PeerConnection and generates the localDescription 604 // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-createoffer 605 func (pc *PeerConnection) CreateOffer(options *OfferOptions) (SessionDescription, error) { //nolint:gocognit 606 useIdentity := pc.idpLoginURL != nil 607 switch { 608 case useIdentity: 609 return SessionDescription{}, errIdentityProviderNotImplemented 610 case pc.isClosed.get(): 611 return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 612 } 613 614 if options != nil && options.ICERestart { 615 if err := pc.iceTransport.restart(); err != nil { 616 return SessionDescription{}, err 617 } 618 } 619 620 var ( 621 d *sdp.SessionDescription 622 offer SessionDescription 623 err error 624 ) 625 626 // This may be necessary to recompute if, for example, createOffer was called when only an 627 // audio RTCRtpTransceiver was added to connection, but while performing the in-parallel 628 // steps to create an offer, a video RTCRtpTransceiver was added, requiring additional 629 // inspection of video system resources. 630 count := 0 631 pc.mu.Lock() 632 defer pc.mu.Unlock() 633 for { 634 // We cache current transceivers to ensure they aren't 635 // mutated during offer generation. We later check if they have 636 // been mutated and recompute the offer if necessary. 637 currentTransceivers := pc.rtpTransceivers 638 639 // in-parallel steps to create an offer 640 // https://w3c.github.io/webrtc-pc/#dfn-in-parallel-steps-to-create-an-offer 641 isPlanB := pc.configuration.SDPSemantics == SDPSemanticsPlanB 642 if pc.currentRemoteDescription != nil && isPlanB { 643 isPlanB = descriptionPossiblyPlanB(pc.currentRemoteDescription) 644 } 645 646 // include unmatched local transceivers 647 if !isPlanB { 648 // update the greater mid if the remote description provides a greater one 649 if pc.currentRemoteDescription != nil { 650 var numericMid int 651 for _, media := range pc.currentRemoteDescription.parsed.MediaDescriptions { 652 mid := getMidValue(media) 653 if mid == "" { 654 continue 655 } 656 numericMid, err = strconv.Atoi(mid) 657 if err != nil { 658 continue 659 } 660 if numericMid > pc.greaterMid { 661 pc.greaterMid = numericMid 662 } 663 } 664 } 665 for _, t := range currentTransceivers { 666 if mid := t.Mid(); mid != "" { 667 numericMid, errMid := strconv.Atoi(mid) 668 if errMid == nil { 669 if numericMid > pc.greaterMid { 670 pc.greaterMid = numericMid 671 } 672 } 673 continue 674 } 675 pc.greaterMid++ 676 err = t.SetMid(strconv.Itoa(pc.greaterMid)) 677 if err != nil { 678 return SessionDescription{}, err 679 } 680 } 681 } 682 683 if pc.currentRemoteDescription == nil { 684 d, err = pc.generateUnmatchedSDP(currentTransceivers, useIdentity) 685 } else { 686 d, err = pc.generateMatchedSDP(currentTransceivers, useIdentity, true /*includeUnmatched */, connectionRoleFromDtlsRole(defaultDtlsRoleOffer)) 687 } 688 689 if err != nil { 690 return SessionDescription{}, err 691 } 692 693 updateSDPOrigin(&pc.sdpOrigin, d) 694 sdpBytes, err := d.Marshal() 695 if err != nil { 696 return SessionDescription{}, err 697 } 698 699 offer = SessionDescription{ 700 Type: SDPTypeOffer, 701 SDP: string(sdpBytes), 702 parsed: d, 703 } 704 705 // Verify local media hasn't changed during offer 706 // generation. Recompute if necessary 707 if isPlanB || !pc.hasLocalDescriptionChanged(&offer) { 708 break 709 } 710 count++ 711 if count >= 128 { 712 return SessionDescription{}, errExcessiveRetries 713 } 714 } 715 716 pc.lastOffer = offer.SDP 717 return offer, nil 718 } 719 720 func (pc *PeerConnection) createICEGatherer() (*ICEGatherer, error) { 721 g, err := pc.api.NewICEGatherer(ICEGatherOptions{ 722 ICEServers: pc.configuration.getICEServers(), 723 ICEGatherPolicy: pc.configuration.ICETransportPolicy, 724 }) 725 if err != nil { 726 return nil, err 727 } 728 729 return g, nil 730 } 731 732 // Update the PeerConnectionState given the state of relevant transports 733 // https://www.w3.org/TR/webrtc/#rtcpeerconnectionstate-enum 734 func (pc *PeerConnection) updateConnectionState(iceConnectionState ICEConnectionState, dtlsTransportState DTLSTransportState) { 735 connectionState := PeerConnectionStateNew 736 switch { 737 // The RTCPeerConnection object's [[IsClosed]] slot is true. 738 case pc.isClosed.get(): 739 connectionState = PeerConnectionStateClosed 740 741 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state. 742 case iceConnectionState == ICEConnectionStateFailed || dtlsTransportState == DTLSTransportStateFailed: 743 connectionState = PeerConnectionStateFailed 744 745 // Any of the RTCIceTransports or RTCDtlsTransports are in the "disconnected" 746 // state and none of them are in the "failed" or "connecting" or "checking" state. */ 747 case iceConnectionState == ICEConnectionStateDisconnected: 748 connectionState = PeerConnectionStateDisconnected 749 750 // None of the previous states apply and all RTCIceTransports are in the "new" or "closed" state, 751 // and all RTCDtlsTransports are in the "new" or "closed" state, or there are no transports. 752 case (iceConnectionState == ICEConnectionStateNew || iceConnectionState == ICEConnectionStateClosed) && 753 (dtlsTransportState == DTLSTransportStateNew || dtlsTransportState == DTLSTransportStateClosed): 754 connectionState = PeerConnectionStateNew 755 756 // None of the previous states apply and any RTCIceTransport is in the "new" or "checking" state or 757 // any RTCDtlsTransport is in the "new" or "connecting" state. 758 case (iceConnectionState == ICEConnectionStateNew || iceConnectionState == ICEConnectionStateChecking) || 759 (dtlsTransportState == DTLSTransportStateNew || dtlsTransportState == DTLSTransportStateConnecting): 760 connectionState = PeerConnectionStateConnecting 761 762 // All RTCIceTransports and RTCDtlsTransports are in the "connected", "completed" or "closed" 763 // state and all RTCDtlsTransports are in the "connected" or "closed" state. 764 case (iceConnectionState == ICEConnectionStateConnected || iceConnectionState == ICEConnectionStateCompleted || iceConnectionState == ICEConnectionStateClosed) && 765 (dtlsTransportState == DTLSTransportStateConnected || dtlsTransportState == DTLSTransportStateClosed): 766 connectionState = PeerConnectionStateConnected 767 } 768 769 if pc.connectionState.Load() == connectionState { 770 return 771 } 772 773 pc.onConnectionStateChange(connectionState) 774 } 775 776 func (pc *PeerConnection) createICETransport() *ICETransport { 777 t := pc.api.NewICETransport(pc.iceGatherer) 778 t.internalOnConnectionStateChangeHandler.Store(func(state ICETransportState) { 779 var cs ICEConnectionState 780 switch state { 781 case ICETransportStateNew: 782 cs = ICEConnectionStateNew 783 case ICETransportStateChecking: 784 cs = ICEConnectionStateChecking 785 case ICETransportStateConnected: 786 cs = ICEConnectionStateConnected 787 case ICETransportStateCompleted: 788 cs = ICEConnectionStateCompleted 789 case ICETransportStateFailed: 790 cs = ICEConnectionStateFailed 791 case ICETransportStateDisconnected: 792 cs = ICEConnectionStateDisconnected 793 case ICETransportStateClosed: 794 cs = ICEConnectionStateClosed 795 default: 796 pc.log.Warnf("OnConnectionStateChange: unhandled ICE state: %s", state) 797 return 798 } 799 pc.onICEConnectionStateChange(cs) 800 pc.updateConnectionState(cs, pc.dtlsTransport.State()) 801 }) 802 803 return t 804 } 805 806 // CreateAnswer starts the PeerConnection and generates the localDescription 807 func (pc *PeerConnection) CreateAnswer(*AnswerOptions) (SessionDescription, error) { 808 useIdentity := pc.idpLoginURL != nil 809 remoteDesc := pc.RemoteDescription() 810 switch { 811 case remoteDesc == nil: 812 return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrNoRemoteDescription} 813 case useIdentity: 814 return SessionDescription{}, errIdentityProviderNotImplemented 815 case pc.isClosed.get(): 816 return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 817 case pc.signalingState.Get() != SignalingStateHaveRemoteOffer && pc.signalingState.Get() != SignalingStateHaveLocalPranswer: 818 return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrIncorrectSignalingState} 819 } 820 821 connectionRole := connectionRoleFromDtlsRole(pc.api.settingEngine.answeringDTLSRole) 822 if connectionRole == sdp.ConnectionRole(0) { 823 connectionRole = connectionRoleFromDtlsRole(defaultDtlsRoleAnswer) 824 825 // If one of the agents is lite and the other one is not, the lite agent must be the controlled agent. 826 // If both or neither agents are lite the offering agent is controlling. 827 // RFC 8445 S6.1.1 828 if isIceLiteSet(remoteDesc.parsed) && !pc.api.settingEngine.candidates.ICELite { 829 connectionRole = connectionRoleFromDtlsRole(DTLSRoleServer) 830 } 831 } 832 pc.mu.Lock() 833 defer pc.mu.Unlock() 834 835 d, err := pc.generateMatchedSDP(pc.rtpTransceivers, useIdentity, false /*includeUnmatched */, connectionRole) 836 if err != nil { 837 return SessionDescription{}, err 838 } 839 840 updateSDPOrigin(&pc.sdpOrigin, d) 841 sdpBytes, err := d.Marshal() 842 if err != nil { 843 return SessionDescription{}, err 844 } 845 846 desc := SessionDescription{ 847 Type: SDPTypeAnswer, 848 SDP: string(sdpBytes), 849 parsed: d, 850 } 851 pc.lastAnswer = desc.SDP 852 return desc, nil 853 } 854 855 // 4.4.1.6 Set the SessionDescription 856 func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeOp) error { //nolint:gocognit 857 switch { 858 case pc.isClosed.get(): 859 return &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 860 case NewSDPType(sd.Type.String()) == SDPTypeUnknown: 861 return &rtcerr.TypeError{Err: fmt.Errorf("%w: '%d' is not a valid enum value of type SDPType", errPeerConnSDPTypeInvalidValue, sd.Type)} 862 } 863 864 nextState, err := func() (SignalingState, error) { 865 pc.mu.Lock() 866 defer pc.mu.Unlock() 867 868 cur := pc.SignalingState() 869 setLocal := stateChangeOpSetLocal 870 setRemote := stateChangeOpSetRemote 871 newSDPDoesNotMatchOffer := &rtcerr.InvalidModificationError{Err: errSDPDoesNotMatchOffer} 872 newSDPDoesNotMatchAnswer := &rtcerr.InvalidModificationError{Err: errSDPDoesNotMatchAnswer} 873 874 var nextState SignalingState 875 var err error 876 switch op { 877 case setLocal: 878 switch sd.Type { 879 // stable->SetLocal(offer)->have-local-offer 880 case SDPTypeOffer: 881 if sd.SDP != pc.lastOffer { 882 return nextState, newSDPDoesNotMatchOffer 883 } 884 nextState, err = checkNextSignalingState(cur, SignalingStateHaveLocalOffer, setLocal, sd.Type) 885 if err == nil { 886 pc.pendingLocalDescription = sd 887 } 888 // have-remote-offer->SetLocal(answer)->stable 889 // have-local-pranswer->SetLocal(answer)->stable 890 case SDPTypeAnswer: 891 if sd.SDP != pc.lastAnswer { 892 return nextState, newSDPDoesNotMatchAnswer 893 } 894 nextState, err = checkNextSignalingState(cur, SignalingStateStable, setLocal, sd.Type) 895 if err == nil { 896 pc.currentLocalDescription = sd 897 pc.currentRemoteDescription = pc.pendingRemoteDescription 898 pc.pendingRemoteDescription = nil 899 pc.pendingLocalDescription = nil 900 } 901 case SDPTypeRollback: 902 nextState, err = checkNextSignalingState(cur, SignalingStateStable, setLocal, sd.Type) 903 if err == nil { 904 pc.pendingLocalDescription = nil 905 } 906 // have-remote-offer->SetLocal(pranswer)->have-local-pranswer 907 case SDPTypePranswer: 908 if sd.SDP != pc.lastAnswer { 909 return nextState, newSDPDoesNotMatchAnswer 910 } 911 nextState, err = checkNextSignalingState(cur, SignalingStateHaveLocalPranswer, setLocal, sd.Type) 912 if err == nil { 913 pc.pendingLocalDescription = sd 914 } 915 default: 916 return nextState, &rtcerr.OperationError{Err: fmt.Errorf("%w: %s(%s)", errPeerConnStateChangeInvalid, op, sd.Type)} 917 } 918 case setRemote: 919 switch sd.Type { 920 // stable->SetRemote(offer)->have-remote-offer 921 case SDPTypeOffer: 922 nextState, err = checkNextSignalingState(cur, SignalingStateHaveRemoteOffer, setRemote, sd.Type) 923 if err == nil { 924 pc.pendingRemoteDescription = sd 925 } 926 // have-local-offer->SetRemote(answer)->stable 927 // have-remote-pranswer->SetRemote(answer)->stable 928 case SDPTypeAnswer: 929 nextState, err = checkNextSignalingState(cur, SignalingStateStable, setRemote, sd.Type) 930 if err == nil { 931 pc.currentRemoteDescription = sd 932 pc.currentLocalDescription = pc.pendingLocalDescription 933 pc.pendingRemoteDescription = nil 934 pc.pendingLocalDescription = nil 935 } 936 case SDPTypeRollback: 937 nextState, err = checkNextSignalingState(cur, SignalingStateStable, setRemote, sd.Type) 938 if err == nil { 939 pc.pendingRemoteDescription = nil 940 } 941 // have-local-offer->SetRemote(pranswer)->have-remote-pranswer 942 case SDPTypePranswer: 943 nextState, err = checkNextSignalingState(cur, SignalingStateHaveRemotePranswer, setRemote, sd.Type) 944 if err == nil { 945 pc.pendingRemoteDescription = sd 946 } 947 default: 948 return nextState, &rtcerr.OperationError{Err: fmt.Errorf("%w: %s(%s)", errPeerConnStateChangeInvalid, op, sd.Type)} 949 } 950 default: 951 return nextState, &rtcerr.OperationError{Err: fmt.Errorf("%w: %q", errPeerConnStateChangeUnhandled, op)} 952 } 953 954 return nextState, err 955 }() 956 957 if err == nil { 958 pc.signalingState.Set(nextState) 959 if pc.signalingState.Get() == SignalingStateStable { 960 pc.isNegotiationNeeded.set(false) 961 pc.mu.Lock() 962 pc.onNegotiationNeeded() 963 pc.mu.Unlock() 964 } 965 pc.onSignalingStateChange(nextState) 966 } 967 return err 968 } 969 970 // SetLocalDescription sets the SessionDescription of the local peer 971 func (pc *PeerConnection) SetLocalDescription(desc SessionDescription) error { 972 if pc.isClosed.get() { 973 return &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 974 } 975 976 haveLocalDescription := pc.currentLocalDescription != nil 977 978 // JSEP 5.4 979 if desc.SDP == "" { 980 switch desc.Type { 981 case SDPTypeAnswer, SDPTypePranswer: 982 desc.SDP = pc.lastAnswer 983 case SDPTypeOffer: 984 desc.SDP = pc.lastOffer 985 default: 986 return &rtcerr.InvalidModificationError{ 987 Err: fmt.Errorf("%w: %s", errPeerConnSDPTypeInvalidValueSetLocalDescription, desc.Type), 988 } 989 } 990 } 991 992 desc.parsed = &sdp.SessionDescription{} 993 if err := desc.parsed.UnmarshalString(desc.SDP); err != nil { 994 return err 995 } 996 if err := pc.setDescription(&desc, stateChangeOpSetLocal); err != nil { 997 return err 998 } 999 1000 currentTransceivers := append([]*RTPTransceiver{}, pc.GetTransceivers()...) 1001 1002 weAnswer := desc.Type == SDPTypeAnswer 1003 remoteDesc := pc.RemoteDescription() 1004 if weAnswer && remoteDesc != nil { 1005 _ = setRTPTransceiverCurrentDirection(&desc, currentTransceivers, false) 1006 if err := pc.startRTPSenders(currentTransceivers); err != nil { 1007 return err 1008 } 1009 pc.configureRTPReceivers(haveLocalDescription, remoteDesc, currentTransceivers) 1010 pc.ops.Enqueue(func() { 1011 pc.startRTP(haveLocalDescription, remoteDesc, currentTransceivers) 1012 }) 1013 } 1014 1015 if pc.iceGatherer.State() == ICEGathererStateNew { 1016 return pc.iceGatherer.Gather() 1017 } 1018 return nil 1019 } 1020 1021 // LocalDescription returns PendingLocalDescription if it is not null and 1022 // otherwise it returns CurrentLocalDescription. This property is used to 1023 // determine if SetLocalDescription has already been called. 1024 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-localdescription 1025 func (pc *PeerConnection) LocalDescription() *SessionDescription { 1026 if pendingLocalDescription := pc.PendingLocalDescription(); pendingLocalDescription != nil { 1027 return pendingLocalDescription 1028 } 1029 return pc.CurrentLocalDescription() 1030 } 1031 1032 // SetRemoteDescription sets the SessionDescription of the remote peer 1033 func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error { //nolint:gocognit,gocyclo 1034 if pc.isClosed.get() { 1035 return &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 1036 } 1037 1038 isRenegotiation := pc.currentRemoteDescription != nil 1039 1040 if _, err := desc.Unmarshal(); err != nil { 1041 return err 1042 } 1043 if err := pc.setDescription(&desc, stateChangeOpSetRemote); err != nil { 1044 return err 1045 } 1046 1047 if err := pc.api.mediaEngine.updateFromRemoteDescription(*desc.parsed); err != nil { 1048 return err 1049 } 1050 1051 // Disable RTX/FEC on RTPSenders if the remote didn't support it 1052 for _, sender := range pc.GetSenders() { 1053 sender.configureRTXAndFEC() 1054 } 1055 1056 var t *RTPTransceiver 1057 localTransceivers := append([]*RTPTransceiver{}, pc.GetTransceivers()...) 1058 detectedPlanB := descriptionIsPlanB(pc.RemoteDescription(), pc.log) 1059 if pc.configuration.SDPSemantics != SDPSemanticsUnifiedPlan { 1060 detectedPlanB = descriptionPossiblyPlanB(pc.RemoteDescription()) 1061 } 1062 1063 weOffer := desc.Type == SDPTypeAnswer 1064 1065 if !weOffer && !detectedPlanB { 1066 for _, media := range pc.RemoteDescription().parsed.MediaDescriptions { 1067 midValue := getMidValue(media) 1068 if midValue == "" { 1069 return errPeerConnRemoteDescriptionWithoutMidValue 1070 } 1071 1072 if media.MediaName.Media == mediaSectionApplication { 1073 continue 1074 } 1075 1076 kind := NewRTPCodecType(media.MediaName.Media) 1077 direction := getPeerDirection(media) 1078 if kind == 0 || direction == RTPTransceiverDirectionUnknown { 1079 continue 1080 } 1081 1082 t, localTransceivers = findByMid(midValue, localTransceivers) 1083 if t == nil { 1084 t, localTransceivers = satisfyTypeAndDirection(kind, direction, localTransceivers) 1085 } else if direction == RTPTransceiverDirectionInactive { 1086 if err := t.Stop(); err != nil { 1087 return err 1088 } 1089 } 1090 1091 switch { 1092 case t == nil: 1093 receiver, err := pc.api.NewRTPReceiver(kind, pc.dtlsTransport) 1094 if err != nil { 1095 return err 1096 } 1097 1098 localDirection := RTPTransceiverDirectionRecvonly 1099 if direction == RTPTransceiverDirectionRecvonly { 1100 localDirection = RTPTransceiverDirectionSendonly 1101 } else if direction == RTPTransceiverDirectionInactive { 1102 localDirection = RTPTransceiverDirectionInactive 1103 } 1104 1105 t = newRTPTransceiver(receiver, nil, localDirection, kind, pc.api) 1106 pc.mu.Lock() 1107 pc.addRTPTransceiver(t) 1108 pc.mu.Unlock() 1109 1110 // if transceiver is create by remote sdp, set prefer codec same as remote peer 1111 if codecs, err := codecsFromMediaDescription(media); err == nil { 1112 filteredCodecs := []RTPCodecParameters{} 1113 for _, codec := range codecs { 1114 if c, matchType := codecParametersFuzzySearch(codec, pc.api.mediaEngine.getCodecsByKind(kind)); matchType == codecMatchExact { 1115 // if codec match exact, use payloadtype register to mediaengine 1116 codec.PayloadType = c.PayloadType 1117 filteredCodecs = append(filteredCodecs, codec) 1118 } 1119 } 1120 _ = t.SetCodecPreferences(filteredCodecs) 1121 } 1122 1123 case direction == RTPTransceiverDirectionRecvonly: 1124 if t.Direction() == RTPTransceiverDirectionSendrecv { 1125 t.setDirection(RTPTransceiverDirectionSendonly) 1126 } else if t.Direction() == RTPTransceiverDirectionRecvonly { 1127 t.setDirection(RTPTransceiverDirectionInactive) 1128 } 1129 case direction == RTPTransceiverDirectionSendrecv: 1130 if t.Direction() == RTPTransceiverDirectionSendonly { 1131 t.setDirection(RTPTransceiverDirectionSendrecv) 1132 } else if t.Direction() == RTPTransceiverDirectionInactive { 1133 t.setDirection(RTPTransceiverDirectionRecvonly) 1134 } 1135 case direction == RTPTransceiverDirectionSendonly: 1136 if t.Direction() == RTPTransceiverDirectionInactive { 1137 t.setDirection(RTPTransceiverDirectionRecvonly) 1138 } 1139 } 1140 1141 if t.Mid() == "" { 1142 if err := t.SetMid(midValue); err != nil { 1143 return err 1144 } 1145 } 1146 } 1147 } 1148 1149 remoteUfrag, remotePwd, candidates, err := extractICEDetails(desc.parsed, pc.log) 1150 if err != nil { 1151 return err 1152 } 1153 1154 if isRenegotiation && pc.iceTransport.haveRemoteCredentialsChange(remoteUfrag, remotePwd) { 1155 // An ICE Restart only happens implicitly for a SetRemoteDescription of type offer 1156 if !weOffer { 1157 if err = pc.iceTransport.restart(); err != nil { 1158 return err 1159 } 1160 } 1161 1162 if err = pc.iceTransport.setRemoteCredentials(remoteUfrag, remotePwd); err != nil { 1163 return err 1164 } 1165 } 1166 1167 for i := range candidates { 1168 if err = pc.iceTransport.AddRemoteCandidate(&candidates[i]); err != nil { 1169 return err 1170 } 1171 } 1172 1173 currentTransceivers := append([]*RTPTransceiver{}, pc.GetTransceivers()...) 1174 1175 if isRenegotiation { 1176 if weOffer { 1177 _ = setRTPTransceiverCurrentDirection(&desc, currentTransceivers, true) 1178 if err = pc.startRTPSenders(currentTransceivers); err != nil { 1179 return err 1180 } 1181 pc.configureRTPReceivers(true, &desc, currentTransceivers) 1182 pc.ops.Enqueue(func() { 1183 pc.startRTP(true, &desc, currentTransceivers) 1184 }) 1185 } 1186 return nil 1187 } 1188 1189 remoteIsLite := isIceLiteSet(desc.parsed) 1190 1191 fingerprint, fingerprintHash, err := extractFingerprint(desc.parsed) 1192 if err != nil { 1193 return err 1194 } 1195 1196 iceRole := ICERoleControlled 1197 // If one of the agents is lite and the other one is not, the lite agent must be the controlled agent. 1198 // If both or neither agents are lite the offering agent is controlling. 1199 // RFC 8445 S6.1.1 1200 if (weOffer && remoteIsLite == pc.api.settingEngine.candidates.ICELite) || (remoteIsLite && !pc.api.settingEngine.candidates.ICELite) { 1201 iceRole = ICERoleControlling 1202 } 1203 1204 // Start the networking in a new routine since it will block until 1205 // the connection is actually established. 1206 if weOffer { 1207 _ = setRTPTransceiverCurrentDirection(&desc, currentTransceivers, true) 1208 if err := pc.startRTPSenders(currentTransceivers); err != nil { 1209 return err 1210 } 1211 1212 pc.configureRTPReceivers(false, &desc, currentTransceivers) 1213 } 1214 1215 pc.ops.Enqueue(func() { 1216 pc.startTransports(iceRole, dtlsRoleFromRemoteSDP(desc.parsed), remoteUfrag, remotePwd, fingerprint, fingerprintHash) 1217 if weOffer { 1218 pc.startRTP(false, &desc, currentTransceivers) 1219 } 1220 }) 1221 return nil 1222 } 1223 1224 func (pc *PeerConnection) configureReceiver(incoming trackDetails, receiver *RTPReceiver) { 1225 receiver.configureReceive(trackDetailsToRTPReceiveParameters(&incoming)) 1226 1227 // set track id and label early so they can be set as new track information 1228 // is received from the SDP. 1229 for i := range receiver.tracks { 1230 receiver.tracks[i].track.mu.Lock() 1231 receiver.tracks[i].track.id = incoming.id 1232 receiver.tracks[i].track.streamID = incoming.streamID 1233 receiver.tracks[i].track.mu.Unlock() 1234 } 1235 } 1236 1237 func (pc *PeerConnection) startReceiver(incoming trackDetails, receiver *RTPReceiver) { 1238 if err := receiver.startReceive(trackDetailsToRTPReceiveParameters(&incoming)); err != nil { 1239 pc.log.Warnf("RTPReceiver Receive failed %s", err) 1240 return 1241 } 1242 1243 for _, t := range receiver.Tracks() { 1244 if t.SSRC() == 0 || t.RID() != "" { 1245 return 1246 } 1247 1248 if pc.api.settingEngine.fireOnTrackBeforeFirstRTP { 1249 pc.onTrack(t, receiver) 1250 return 1251 } 1252 go func(track *TrackRemote) { 1253 b := make([]byte, pc.api.settingEngine.getReceiveMTU()) 1254 n, _, err := track.peek(b) 1255 if err != nil { 1256 pc.log.Warnf("Could not determine PayloadType for SSRC %d (%s)", track.SSRC(), err) 1257 return 1258 } 1259 1260 if err = track.checkAndUpdateTrack(b[:n]); err != nil { 1261 pc.log.Warnf("Failed to set codec settings for track SSRC %d (%s)", track.SSRC(), err) 1262 return 1263 } 1264 1265 pc.onTrack(track, receiver) 1266 }(t) 1267 } 1268 } 1269 1270 func setRTPTransceiverCurrentDirection(answer *SessionDescription, currentTransceivers []*RTPTransceiver, weOffer bool) error { 1271 currentTransceivers = append([]*RTPTransceiver{}, currentTransceivers...) 1272 for _, media := range answer.parsed.MediaDescriptions { 1273 midValue := getMidValue(media) 1274 if midValue == "" { 1275 return errPeerConnRemoteDescriptionWithoutMidValue 1276 } 1277 1278 if media.MediaName.Media == mediaSectionApplication { 1279 continue 1280 } 1281 1282 var t *RTPTransceiver 1283 t, currentTransceivers = findByMid(midValue, currentTransceivers) 1284 1285 if t == nil { 1286 return fmt.Errorf("%w: %q", errPeerConnTranscieverMidNil, midValue) 1287 } 1288 1289 direction := getPeerDirection(media) 1290 if direction == RTPTransceiverDirectionUnknown { 1291 continue 1292 } 1293 1294 // reverse direction if it was a remote answer 1295 if weOffer { 1296 switch direction { 1297 case RTPTransceiverDirectionSendonly: 1298 direction = RTPTransceiverDirectionRecvonly 1299 case RTPTransceiverDirectionRecvonly: 1300 direction = RTPTransceiverDirectionSendonly 1301 default: 1302 } 1303 } 1304 1305 // If a transceiver is created by applying a remote description that has recvonly transceiver, 1306 // it will have no sender. In this case, the transceiver's current direction is set to inactive so 1307 // that the transceiver can be reused by next AddTrack. 1308 if !weOffer && direction == RTPTransceiverDirectionSendonly && t.Sender() == nil { 1309 direction = RTPTransceiverDirectionInactive 1310 } 1311 1312 t.setCurrentDirection(direction) 1313 } 1314 return nil 1315 } 1316 1317 func runIfNewReceiver( 1318 incomingTrack trackDetails, 1319 transceivers []*RTPTransceiver, 1320 f func(incomingTrack trackDetails, receiver *RTPReceiver), 1321 ) bool { 1322 for _, t := range transceivers { 1323 if t.Mid() != incomingTrack.mid { 1324 continue 1325 } 1326 1327 receiver := t.Receiver() 1328 if (incomingTrack.kind != t.Kind()) || 1329 (t.Direction() != RTPTransceiverDirectionRecvonly && t.Direction() != RTPTransceiverDirectionSendrecv) || 1330 receiver == nil || 1331 (receiver.haveReceived()) { 1332 continue 1333 } 1334 1335 f(incomingTrack, receiver) 1336 return true 1337 } 1338 1339 return false 1340 } 1341 1342 // configureRTPReceivers opens knows inbound SRTP streams from the RemoteDescription 1343 func (pc *PeerConnection) configureRTPReceivers(isRenegotiation bool, remoteDesc *SessionDescription, currentTransceivers []*RTPTransceiver) { //nolint:gocognit 1344 incomingTracks := trackDetailsFromSDP(pc.log, remoteDesc.parsed) 1345 1346 if isRenegotiation { 1347 for _, t := range currentTransceivers { 1348 receiver := t.Receiver() 1349 if receiver == nil { 1350 continue 1351 } 1352 1353 tracks := t.Receiver().Tracks() 1354 if len(tracks) == 0 { 1355 continue 1356 } 1357 1358 mid := t.Mid() 1359 receiverNeedsStopped := false 1360 for _, track := range tracks { 1361 func(t *TrackRemote) { 1362 t.mu.Lock() 1363 defer t.mu.Unlock() 1364 1365 if t.rid != "" { 1366 if details := trackDetailsForRID(incomingTracks, mid, t.rid); details != nil { 1367 t.id = details.id 1368 t.streamID = details.streamID 1369 return 1370 } 1371 } else if t.ssrc != 0 { 1372 if details := trackDetailsForSSRC(incomingTracks, t.ssrc); details != nil { 1373 t.id = details.id 1374 t.streamID = details.streamID 1375 return 1376 } 1377 } 1378 1379 receiverNeedsStopped = true 1380 }(track) 1381 } 1382 1383 if !receiverNeedsStopped { 1384 continue 1385 } 1386 1387 if err := receiver.Stop(); err != nil { 1388 pc.log.Warnf("Failed to stop RtpReceiver: %s", err) 1389 continue 1390 } 1391 1392 receiver, err := pc.api.NewRTPReceiver(receiver.kind, pc.dtlsTransport) 1393 if err != nil { 1394 pc.log.Warnf("Failed to create new RtpReceiver: %s", err) 1395 continue 1396 } 1397 t.setReceiver(receiver) 1398 } 1399 } 1400 1401 localTransceivers := append([]*RTPTransceiver{}, currentTransceivers...) 1402 1403 // Ensure we haven't already started a transceiver for this ssrc 1404 filteredTracks := append([]trackDetails{}, incomingTracks...) 1405 for _, incomingTrack := range incomingTracks { 1406 // If we already have a TrackRemote for a given SSRC don't handle it again 1407 for _, t := range localTransceivers { 1408 if receiver := t.Receiver(); receiver != nil { 1409 for _, track := range receiver.Tracks() { 1410 for _, ssrc := range incomingTrack.ssrcs { 1411 if ssrc == track.SSRC() { 1412 filteredTracks = filterTrackWithSSRC(filteredTracks, track.SSRC()) 1413 } 1414 } 1415 } 1416 } 1417 } 1418 } 1419 1420 for _, incomingTrack := range filteredTracks { 1421 _ = runIfNewReceiver(incomingTrack, localTransceivers, pc.configureReceiver) 1422 } 1423 } 1424 1425 // startRTPReceivers opens knows inbound SRTP streams from the RemoteDescription 1426 func (pc *PeerConnection) startRTPReceivers(remoteDesc *SessionDescription, currentTransceivers []*RTPTransceiver) { 1427 incomingTracks := trackDetailsFromSDP(pc.log, remoteDesc.parsed) 1428 if len(incomingTracks) == 0 { 1429 return 1430 } 1431 1432 localTransceivers := append([]*RTPTransceiver{}, currentTransceivers...) 1433 1434 unhandledTracks := incomingTracks[:0] 1435 for _, incomingTrack := range incomingTracks { 1436 trackHandled := runIfNewReceiver(incomingTrack, localTransceivers, pc.startReceiver) 1437 if !trackHandled { 1438 unhandledTracks = append(unhandledTracks, incomingTrack) 1439 } 1440 } 1441 1442 remoteIsPlanB := false 1443 switch pc.configuration.SDPSemantics { 1444 case SDPSemanticsPlanB: 1445 remoteIsPlanB = true 1446 case SDPSemanticsUnifiedPlanWithFallback: 1447 remoteIsPlanB = descriptionPossiblyPlanB(pc.RemoteDescription()) 1448 default: 1449 // none 1450 } 1451 1452 if remoteIsPlanB { 1453 for _, incomingTrack := range unhandledTracks { 1454 t, err := pc.AddTransceiverFromKind(incomingTrack.kind, RTPTransceiverInit{ 1455 Direction: RTPTransceiverDirectionSendrecv, 1456 }) 1457 if err != nil { 1458 pc.log.Warnf("Could not add transceiver for remote SSRC %d: %s", incomingTrack.ssrcs[0], err) 1459 continue 1460 } 1461 pc.configureReceiver(incomingTrack, t.Receiver()) 1462 pc.startReceiver(incomingTrack, t.Receiver()) 1463 } 1464 } 1465 } 1466 1467 // startRTPSenders starts all outbound RTP streams 1468 func (pc *PeerConnection) startRTPSenders(currentTransceivers []*RTPTransceiver) error { 1469 for _, transceiver := range currentTransceivers { 1470 if sender := transceiver.Sender(); sender != nil && sender.isNegotiated() && !sender.hasSent() { 1471 err := sender.Send(sender.GetParameters()) 1472 if err != nil { 1473 return err 1474 } 1475 } 1476 } 1477 1478 return nil 1479 } 1480 1481 // Start SCTP subsystem 1482 func (pc *PeerConnection) startSCTP() { 1483 // Start sctp 1484 if err := pc.sctpTransport.Start(SCTPCapabilities{ 1485 MaxMessageSize: 0, 1486 }); err != nil { 1487 pc.log.Warnf("Failed to start SCTP: %s", err) 1488 if err = pc.sctpTransport.Stop(); err != nil { 1489 pc.log.Warnf("Failed to stop SCTPTransport: %s", err) 1490 } 1491 1492 return 1493 } 1494 } 1495 1496 func (pc *PeerConnection) handleUndeclaredSSRC(ssrc SSRC, remoteDescription *SessionDescription) (handled bool, err error) { 1497 if len(remoteDescription.parsed.MediaDescriptions) != 1 { 1498 return false, nil 1499 } 1500 1501 onlyMediaSection := remoteDescription.parsed.MediaDescriptions[0] 1502 streamID := "" 1503 id := "" 1504 hasRidAttribute := false 1505 hasSSRCAttribute := false 1506 1507 for _, a := range onlyMediaSection.Attributes { 1508 switch a.Key { 1509 case sdp.AttrKeyMsid: 1510 if split := strings.Split(a.Value, " "); len(split) == 2 { 1511 streamID = split[0] 1512 id = split[1] 1513 } 1514 case sdp.AttrKeySSRC: 1515 hasSSRCAttribute = true 1516 case sdpAttributeRid: 1517 hasRidAttribute = true 1518 } 1519 } 1520 1521 if hasRidAttribute { 1522 return false, nil 1523 } else if hasSSRCAttribute { 1524 return false, errPeerConnSingleMediaSectionHasExplicitSSRC 1525 } 1526 1527 incoming := trackDetails{ 1528 ssrcs: []SSRC{ssrc}, 1529 kind: RTPCodecTypeVideo, 1530 streamID: streamID, 1531 id: id, 1532 } 1533 if onlyMediaSection.MediaName.Media == RTPCodecTypeAudio.String() { 1534 incoming.kind = RTPCodecTypeAudio 1535 } 1536 1537 t, err := pc.AddTransceiverFromKind(incoming.kind, RTPTransceiverInit{ 1538 Direction: RTPTransceiverDirectionSendrecv, 1539 }) 1540 if err != nil { 1541 // nolint 1542 return false, fmt.Errorf("%w: %d: %s", errPeerConnRemoteSSRCAddTransceiver, ssrc, err) 1543 } 1544 1545 pc.configureReceiver(incoming, t.Receiver()) 1546 pc.startReceiver(incoming, t.Receiver()) 1547 return true, nil 1548 } 1549 1550 // Chrome sends probing traffic on SSRC 0. This reads the packets to ensure that we properly 1551 // generate TWCC reports for it. Since this isn't actually media we don't pass this to the user 1552 func (pc *PeerConnection) handleNonMediaBandwidthProbe() { 1553 nonMediaBandwidthProbe, err := pc.api.NewRTPReceiver(RTPCodecTypeVideo, pc.dtlsTransport) 1554 if err != nil { 1555 pc.log.Errorf("handleNonMediaBandwidthProbe failed to create RTPReceiver: %v", err) 1556 return 1557 } 1558 1559 if err = nonMediaBandwidthProbe.Receive(RTPReceiveParameters{ 1560 Encodings: []RTPDecodingParameters{{RTPCodingParameters: RTPCodingParameters{}}}, 1561 }); err != nil { 1562 pc.log.Errorf("handleNonMediaBandwidthProbe failed to start RTPReceiver: %v", err) 1563 return 1564 } 1565 1566 pc.nonMediaBandwidthProbe.Store(nonMediaBandwidthProbe) 1567 b := make([]byte, pc.api.settingEngine.getReceiveMTU()) 1568 for { 1569 if _, _, err = nonMediaBandwidthProbe.readRTP(b, nonMediaBandwidthProbe.Track()); err != nil { 1570 pc.log.Tracef("handleNonMediaBandwidthProbe read exiting: %v", err) 1571 return 1572 } 1573 } 1574 } 1575 1576 func (pc *PeerConnection) handleIncomingSSRC(rtpStream io.Reader, ssrc SSRC) error { //nolint:gocognit 1577 remoteDescription := pc.RemoteDescription() 1578 if remoteDescription == nil { 1579 return errPeerConnRemoteDescriptionNil 1580 } 1581 1582 // If a SSRC already exists in the RemoteDescription don't perform heuristics upon it 1583 for _, track := range trackDetailsFromSDP(pc.log, remoteDescription.parsed) { 1584 if track.repairSsrc != nil && ssrc == *track.repairSsrc { 1585 return nil 1586 } 1587 for _, trackSsrc := range track.ssrcs { 1588 if ssrc == trackSsrc { 1589 return nil 1590 } 1591 } 1592 } 1593 1594 // If the remote SDP was only one media section the ssrc doesn't have to be explicitly declared 1595 if handled, err := pc.handleUndeclaredSSRC(ssrc, remoteDescription); handled || err != nil { 1596 return err 1597 } 1598 1599 midExtensionID, audioSupported, videoSupported := pc.api.mediaEngine.getHeaderExtensionID(RTPHeaderExtensionCapability{sdp.SDESMidURI}) 1600 if !audioSupported && !videoSupported { 1601 return errPeerConnSimulcastMidRTPExtensionRequired 1602 } 1603 1604 streamIDExtensionID, audioSupported, videoSupported := pc.api.mediaEngine.getHeaderExtensionID(RTPHeaderExtensionCapability{sdp.SDESRTPStreamIDURI}) 1605 if !audioSupported && !videoSupported { 1606 return errPeerConnSimulcastStreamIDRTPExtensionRequired 1607 } 1608 1609 repairStreamIDExtensionID, _, _ := pc.api.mediaEngine.getHeaderExtensionID(RTPHeaderExtensionCapability{sdesRepairRTPStreamIDURI}) 1610 1611 b := make([]byte, pc.api.settingEngine.getReceiveMTU()) 1612 1613 i, err := rtpStream.Read(b) 1614 if err != nil { 1615 return err 1616 } 1617 1618 if i < 4 { 1619 return errRTPTooShort 1620 } 1621 1622 payloadType := PayloadType(b[1] & 0x7f) 1623 params, err := pc.api.mediaEngine.getRTPParametersByPayloadType(payloadType) 1624 if err != nil { 1625 return err 1626 } 1627 1628 streamInfo := createStreamInfo("", ssrc, 0, 0, params.Codecs[0].PayloadType, 0, 0, params.Codecs[0].RTPCodecCapability, params.HeaderExtensions) 1629 readStream, interceptor, rtcpReadStream, rtcpInterceptor, err := pc.dtlsTransport.streamsForSSRC(ssrc, *streamInfo) 1630 if err != nil { 1631 return err 1632 } 1633 1634 var mid, rid, rsid string 1635 var paddingOnly bool 1636 for readCount := 0; readCount <= simulcastProbeCount; readCount++ { 1637 if mid == "" || (rid == "" && rsid == "") { 1638 // skip padding only packets for probing 1639 if paddingOnly { 1640 readCount-- 1641 } 1642 1643 i, _, err := interceptor.Read(b, nil) 1644 if err != nil { 1645 return err 1646 } 1647 1648 if _, paddingOnly, err = handleUnknownRTPPacket(b[:i], uint8(midExtensionID), uint8(streamIDExtensionID), uint8(repairStreamIDExtensionID), &mid, &rid, &rsid); err != nil { 1649 return err 1650 } 1651 1652 continue 1653 } 1654 1655 for _, t := range pc.GetTransceivers() { 1656 receiver := t.Receiver() 1657 if t.Mid() != mid || receiver == nil { 1658 continue 1659 } 1660 1661 if rsid != "" { 1662 receiver.mu.Lock() 1663 defer receiver.mu.Unlock() 1664 return receiver.receiveForRtx(SSRC(0), rsid, streamInfo, readStream, interceptor, rtcpReadStream, rtcpInterceptor) 1665 } 1666 1667 track, err := receiver.receiveForRid(rid, params, streamInfo, readStream, interceptor, rtcpReadStream, rtcpInterceptor) 1668 if err != nil { 1669 return err 1670 } 1671 pc.onTrack(track, receiver) 1672 return nil 1673 } 1674 } 1675 1676 pc.api.interceptor.UnbindRemoteStream(streamInfo) 1677 return errPeerConnSimulcastIncomingSSRCFailed 1678 } 1679 1680 // undeclaredMediaProcessor handles RTP/RTCP packets that don't match any a:ssrc lines 1681 func (pc *PeerConnection) undeclaredMediaProcessor() { 1682 go pc.undeclaredRTPMediaProcessor() 1683 go pc.undeclaredRTCPMediaProcessor() 1684 } 1685 1686 func (pc *PeerConnection) undeclaredRTPMediaProcessor() { 1687 var simulcastRoutineCount uint64 1688 for { 1689 srtpSession, err := pc.dtlsTransport.getSRTPSession() 1690 if err != nil { 1691 pc.log.Warnf("undeclaredMediaProcessor failed to open SrtpSession: %v", err) 1692 return 1693 } 1694 1695 srtcpSession, err := pc.dtlsTransport.getSRTCPSession() 1696 if err != nil { 1697 pc.log.Warnf("undeclaredMediaProcessor failed to open SrtcpSession: %v", err) 1698 return 1699 } 1700 1701 srtpReadStream, ssrc, err := srtpSession.AcceptStream() 1702 if err != nil { 1703 pc.log.Warnf("Failed to accept RTP %v", err) 1704 return 1705 } 1706 1707 // open accompanying srtcp stream 1708 srtcpReadStream, err := srtcpSession.OpenReadStream(ssrc) 1709 if err != nil { 1710 pc.log.Warnf("Failed to open RTCP stream for %d: %v", ssrc, err) 1711 return 1712 } 1713 1714 if pc.isClosed.get() { 1715 if err = srtpReadStream.Close(); err != nil { 1716 pc.log.Warnf("Failed to close RTP stream %v", err) 1717 } 1718 if err = srtcpReadStream.Close(); err != nil { 1719 pc.log.Warnf("Failed to close RTCP stream %v", err) 1720 } 1721 continue 1722 } 1723 1724 pc.dtlsTransport.storeSimulcastStream(srtpReadStream, srtcpReadStream) 1725 1726 if ssrc == 0 { 1727 go pc.handleNonMediaBandwidthProbe() 1728 continue 1729 } 1730 1731 if atomic.AddUint64(&simulcastRoutineCount, 1) >= simulcastMaxProbeRoutines { 1732 atomic.AddUint64(&simulcastRoutineCount, ^uint64(0)) 1733 pc.log.Warn(ErrSimulcastProbeOverflow.Error()) 1734 continue 1735 } 1736 1737 go func(rtpStream io.Reader, ssrc SSRC) { 1738 if err := pc.handleIncomingSSRC(rtpStream, ssrc); err != nil { 1739 pc.log.Errorf(incomingUnhandledRTPSsrc, ssrc, err) 1740 } 1741 atomic.AddUint64(&simulcastRoutineCount, ^uint64(0)) 1742 }(srtpReadStream, SSRC(ssrc)) 1743 } 1744 } 1745 1746 func (pc *PeerConnection) undeclaredRTCPMediaProcessor() { 1747 var unhandledStreams []*srtp.ReadStreamSRTCP 1748 defer func() { 1749 for _, s := range unhandledStreams { 1750 _ = s.Close() 1751 } 1752 }() 1753 for { 1754 srtcpSession, err := pc.dtlsTransport.getSRTCPSession() 1755 if err != nil { 1756 pc.log.Warnf("undeclaredMediaProcessor failed to open SrtcpSession: %v", err) 1757 return 1758 } 1759 1760 stream, ssrc, err := srtcpSession.AcceptStream() 1761 if err != nil { 1762 pc.log.Warnf("Failed to accept RTCP %v", err) 1763 return 1764 } 1765 pc.log.Warnf("Incoming unhandled RTCP ssrc(%d), OnTrack will not be fired", ssrc) 1766 unhandledStreams = append(unhandledStreams, stream) 1767 } 1768 } 1769 1770 // RemoteDescription returns pendingRemoteDescription if it is not null and 1771 // otherwise it returns currentRemoteDescription. This property is used to 1772 // determine if setRemoteDescription has already been called. 1773 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-remotedescription 1774 func (pc *PeerConnection) RemoteDescription() *SessionDescription { 1775 pc.mu.RLock() 1776 defer pc.mu.RUnlock() 1777 1778 if pc.pendingRemoteDescription != nil { 1779 return pc.pendingRemoteDescription 1780 } 1781 return pc.currentRemoteDescription 1782 } 1783 1784 // AddICECandidate accepts an ICE candidate string and adds it 1785 // to the existing set of candidates. 1786 func (pc *PeerConnection) AddICECandidate(candidate ICECandidateInit) error { 1787 if pc.RemoteDescription() == nil { 1788 return &rtcerr.InvalidStateError{Err: ErrNoRemoteDescription} 1789 } 1790 1791 candidateValue := strings.TrimPrefix(candidate.Candidate, "candidate:") 1792 1793 var iceCandidate *ICECandidate 1794 if candidateValue != "" { 1795 candidate, err := ice.UnmarshalCandidate(candidateValue) 1796 if err != nil { 1797 if errors.Is(err, ice.ErrUnknownCandidateTyp) || errors.Is(err, ice.ErrDetermineNetworkType) { 1798 pc.log.Warnf("Discarding remote candidate: %s", err) 1799 return nil 1800 } 1801 return err 1802 } 1803 1804 c, err := newICECandidateFromICE(candidate) 1805 if err != nil { 1806 return err 1807 } 1808 iceCandidate = &c 1809 } 1810 1811 return pc.iceTransport.AddRemoteCandidate(iceCandidate) 1812 } 1813 1814 // ICEConnectionState returns the ICE connection state of the 1815 // PeerConnection instance. 1816 func (pc *PeerConnection) ICEConnectionState() ICEConnectionState { 1817 if state, ok := pc.iceConnectionState.Load().(ICEConnectionState); ok { 1818 return state 1819 } 1820 return ICEConnectionState(0) 1821 } 1822 1823 // GetSenders returns the RTPSender that are currently attached to this PeerConnection 1824 func (pc *PeerConnection) GetSenders() (result []*RTPSender) { 1825 pc.mu.Lock() 1826 defer pc.mu.Unlock() 1827 1828 for _, transceiver := range pc.rtpTransceivers { 1829 if sender := transceiver.Sender(); sender != nil { 1830 result = append(result, sender) 1831 } 1832 } 1833 return result 1834 } 1835 1836 // GetReceivers returns the RTPReceivers that are currently attached to this PeerConnection 1837 func (pc *PeerConnection) GetReceivers() (receivers []*RTPReceiver) { 1838 pc.mu.Lock() 1839 defer pc.mu.Unlock() 1840 1841 for _, transceiver := range pc.rtpTransceivers { 1842 if receiver := transceiver.Receiver(); receiver != nil { 1843 receivers = append(receivers, receiver) 1844 } 1845 } 1846 return 1847 } 1848 1849 // GetTransceivers returns the RtpTransceiver that are currently attached to this PeerConnection 1850 func (pc *PeerConnection) GetTransceivers() []*RTPTransceiver { 1851 pc.mu.Lock() 1852 defer pc.mu.Unlock() 1853 1854 return pc.rtpTransceivers 1855 } 1856 1857 // AddTrack adds a Track to the PeerConnection 1858 func (pc *PeerConnection) AddTrack(track TrackLocal) (*RTPSender, error) { 1859 if pc.isClosed.get() { 1860 return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 1861 } 1862 1863 pc.mu.Lock() 1864 defer pc.mu.Unlock() 1865 for _, t := range pc.rtpTransceivers { 1866 currentDirection := t.getCurrentDirection() 1867 // According to https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-addtrack, if the 1868 // transceiver can be reused only if it's currentDirection never be sendrecv or sendonly. 1869 // But that will cause sdp inflate. So we only check currentDirection's current value, 1870 // that's worked for all browsers. 1871 if !t.stopped && t.kind == track.Kind() && t.Sender() == nil && 1872 !(currentDirection == RTPTransceiverDirectionSendrecv || currentDirection == RTPTransceiverDirectionSendonly) { 1873 sender, err := pc.api.NewRTPSender(track, pc.dtlsTransport) 1874 if err == nil { 1875 err = t.SetSender(sender, track) 1876 if err != nil { 1877 _ = sender.Stop() 1878 t.setSender(nil) 1879 } 1880 } 1881 if err != nil { 1882 return nil, err 1883 } 1884 pc.onNegotiationNeeded() 1885 return sender, nil 1886 } 1887 } 1888 1889 transceiver, err := pc.newTransceiverFromTrack(RTPTransceiverDirectionSendrecv, track) 1890 if err != nil { 1891 return nil, err 1892 } 1893 pc.addRTPTransceiver(transceiver) 1894 return transceiver.Sender(), nil 1895 } 1896 1897 // RemoveTrack removes a Track from the PeerConnection 1898 func (pc *PeerConnection) RemoveTrack(sender *RTPSender) (err error) { 1899 if pc.isClosed.get() { 1900 return &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 1901 } 1902 1903 var transceiver *RTPTransceiver 1904 pc.mu.Lock() 1905 defer pc.mu.Unlock() 1906 for _, t := range pc.rtpTransceivers { 1907 if t.Sender() == sender { 1908 transceiver = t 1909 break 1910 } 1911 } 1912 if transceiver == nil { 1913 return &rtcerr.InvalidAccessError{Err: ErrSenderNotCreatedByConnection} 1914 } else if err = sender.Stop(); err == nil { 1915 err = transceiver.setSendingTrack(nil) 1916 if err == nil { 1917 pc.onNegotiationNeeded() 1918 } 1919 } 1920 return 1921 } 1922 1923 func (pc *PeerConnection) newTransceiverFromTrack(direction RTPTransceiverDirection, track TrackLocal, init ...RTPTransceiverInit) (t *RTPTransceiver, err error) { 1924 var ( 1925 r *RTPReceiver 1926 s *RTPSender 1927 ) 1928 switch direction { 1929 case RTPTransceiverDirectionSendrecv: 1930 r, err = pc.api.NewRTPReceiver(track.Kind(), pc.dtlsTransport) 1931 if err != nil { 1932 return 1933 } 1934 s, err = pc.api.NewRTPSender(track, pc.dtlsTransport) 1935 case RTPTransceiverDirectionSendonly: 1936 s, err = pc.api.NewRTPSender(track, pc.dtlsTransport) 1937 default: 1938 err = errPeerConnAddTransceiverFromTrackSupport 1939 } 1940 if err != nil { 1941 return 1942 } 1943 1944 // Allow RTPTransceiverInit to override SSRC 1945 if s != nil && len(s.trackEncodings) == 1 && 1946 len(init) == 1 && len(init[0].SendEncodings) == 1 && init[0].SendEncodings[0].SSRC != 0 { 1947 s.trackEncodings[0].ssrc = init[0].SendEncodings[0].SSRC 1948 } 1949 1950 return newRTPTransceiver(r, s, direction, track.Kind(), pc.api), nil 1951 } 1952 1953 // AddTransceiverFromKind Create a new RtpTransceiver and adds it to the set of transceivers. 1954 func (pc *PeerConnection) AddTransceiverFromKind(kind RTPCodecType, init ...RTPTransceiverInit) (t *RTPTransceiver, err error) { 1955 if pc.isClosed.get() { 1956 return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 1957 } 1958 1959 direction := RTPTransceiverDirectionSendrecv 1960 if len(init) > 1 { 1961 return nil, errPeerConnAddTransceiverFromKindOnlyAcceptsOne 1962 } else if len(init) == 1 { 1963 direction = init[0].Direction 1964 } 1965 switch direction { 1966 case RTPTransceiverDirectionSendonly, RTPTransceiverDirectionSendrecv: 1967 codecs := pc.api.mediaEngine.getCodecsByKind(kind) 1968 if len(codecs) == 0 { 1969 return nil, ErrNoCodecsAvailable 1970 } 1971 track, err := NewTrackLocalStaticSample(codecs[0].RTPCodecCapability, util.MathRandAlpha(16), util.MathRandAlpha(16)) 1972 if err != nil { 1973 return nil, err 1974 } 1975 t, err = pc.newTransceiverFromTrack(direction, track, init...) 1976 if err != nil { 1977 return nil, err 1978 } 1979 case RTPTransceiverDirectionRecvonly: 1980 receiver, err := pc.api.NewRTPReceiver(kind, pc.dtlsTransport) 1981 if err != nil { 1982 return nil, err 1983 } 1984 t = newRTPTransceiver(receiver, nil, RTPTransceiverDirectionRecvonly, kind, pc.api) 1985 default: 1986 return nil, errPeerConnAddTransceiverFromKindSupport 1987 } 1988 pc.mu.Lock() 1989 pc.addRTPTransceiver(t) 1990 pc.mu.Unlock() 1991 return t, nil 1992 } 1993 1994 // AddTransceiverFromTrack Create a new RtpTransceiver(SendRecv or SendOnly) and add it to the set of transceivers. 1995 func (pc *PeerConnection) AddTransceiverFromTrack(track TrackLocal, init ...RTPTransceiverInit) (t *RTPTransceiver, err error) { 1996 if pc.isClosed.get() { 1997 return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 1998 } 1999 2000 direction := RTPTransceiverDirectionSendrecv 2001 if len(init) > 1 { 2002 return nil, errPeerConnAddTransceiverFromTrackOnlyAcceptsOne 2003 } else if len(init) == 1 { 2004 direction = init[0].Direction 2005 } 2006 2007 t, err = pc.newTransceiverFromTrack(direction, track, init...) 2008 if err == nil { 2009 pc.mu.Lock() 2010 pc.addRTPTransceiver(t) 2011 pc.mu.Unlock() 2012 } 2013 return 2014 } 2015 2016 // CreateDataChannel creates a new DataChannel object with the given label 2017 // and optional DataChannelInit used to configure properties of the 2018 // underlying channel such as data reliability. 2019 func (pc *PeerConnection) CreateDataChannel(label string, options *DataChannelInit) (*DataChannel, error) { 2020 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #2) 2021 if pc.isClosed.get() { 2022 return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed} 2023 } 2024 2025 params := &DataChannelParameters{ 2026 Label: label, 2027 Ordered: true, 2028 } 2029 2030 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #19) 2031 if options != nil { 2032 params.ID = options.ID 2033 } 2034 2035 if options != nil { 2036 // Ordered indicates if data is allowed to be delivered out of order. The 2037 // default value of true, guarantees that data will be delivered in order. 2038 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #9) 2039 if options.Ordered != nil { 2040 params.Ordered = *options.Ordered 2041 } 2042 2043 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #7) 2044 if options.MaxPacketLifeTime != nil { 2045 params.MaxPacketLifeTime = options.MaxPacketLifeTime 2046 } 2047 2048 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #8) 2049 if options.MaxRetransmits != nil { 2050 params.MaxRetransmits = options.MaxRetransmits 2051 } 2052 2053 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #10) 2054 if options.Protocol != nil { 2055 params.Protocol = *options.Protocol 2056 } 2057 2058 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #11) 2059 if len(params.Protocol) > 65535 { 2060 return nil, &rtcerr.TypeError{Err: ErrProtocolTooLarge} 2061 } 2062 2063 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #12) 2064 if options.Negotiated != nil { 2065 params.Negotiated = *options.Negotiated 2066 } 2067 } 2068 2069 d, err := pc.api.newDataChannel(params, nil, pc.log) 2070 if err != nil { 2071 return nil, err 2072 } 2073 2074 // https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #16) 2075 if d.maxPacketLifeTime != nil && d.maxRetransmits != nil { 2076 return nil, &rtcerr.TypeError{Err: ErrRetransmitsOrPacketLifeTime} 2077 } 2078 2079 pc.sctpTransport.lock.Lock() 2080 pc.sctpTransport.dataChannels = append(pc.sctpTransport.dataChannels, d) 2081 if d.ID() != nil { 2082 pc.sctpTransport.dataChannelIDsUsed[*d.ID()] = struct{}{} 2083 } 2084 pc.sctpTransport.dataChannelsRequested++ 2085 pc.sctpTransport.lock.Unlock() 2086 2087 // If SCTP already connected open all the channels 2088 if pc.sctpTransport.State() == SCTPTransportStateConnected { 2089 if err = d.open(pc.sctpTransport); err != nil { 2090 return nil, err 2091 } 2092 } 2093 2094 pc.mu.Lock() 2095 pc.onNegotiationNeeded() 2096 pc.mu.Unlock() 2097 2098 return d, nil 2099 } 2100 2101 // SetIdentityProvider is used to configure an identity provider to generate identity assertions 2102 func (pc *PeerConnection) SetIdentityProvider(string) error { 2103 return errPeerConnSetIdentityProviderNotImplemented 2104 } 2105 2106 // WriteRTCP sends a user provided RTCP packet to the connected peer. If no peer is connected the 2107 // packet is discarded. It also runs any configured interceptors. 2108 func (pc *PeerConnection) WriteRTCP(pkts []rtcp.Packet) error { 2109 _, err := pc.interceptorRTCPWriter.Write(pkts, make(interceptor.Attributes)) 2110 return err 2111 } 2112 2113 func (pc *PeerConnection) writeRTCP(pkts []rtcp.Packet, _ interceptor.Attributes) (int, error) { 2114 return pc.dtlsTransport.WriteRTCP(pkts) 2115 } 2116 2117 // Close ends the PeerConnection. 2118 func (pc *PeerConnection) Close() error { 2119 return pc.close(false /* shouldGracefullyClose */) 2120 } 2121 2122 // GracefulClose ends the PeerConnection. It also waits 2123 // for any goroutines it started to complete. This is only safe to call outside of 2124 // PeerConnection callbacks or if in a callback, in its own goroutine. 2125 func (pc *PeerConnection) GracefulClose() error { 2126 return pc.close(true /* shouldGracefullyClose */) 2127 } 2128 2129 func (pc *PeerConnection) close(shouldGracefullyClose bool) error { 2130 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #1) 2131 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #2) 2132 2133 pc.mu.Lock() 2134 // A lock in this critical section is needed because pc.isClosed and 2135 // pc.isGracefullyClosingOrClosed are related to each other in that we 2136 // want to make graceful and normal closure one time operations in order 2137 // to avoid any double closure errors from cropping up. However, there are 2138 // some overlapping close cases when both normal and graceful close are used 2139 // that should be idempotent, but be cautioned when writing new close behavior 2140 // to preserve this property. 2141 isAlreadyClosingOrClosed := pc.isClosed.swap(true) 2142 isAlreadyGracefullyClosingOrClosed := pc.isGracefullyClosingOrClosed 2143 if shouldGracefullyClose && !isAlreadyGracefullyClosingOrClosed { 2144 pc.isGracefullyClosingOrClosed = true 2145 } 2146 pc.mu.Unlock() 2147 2148 if isAlreadyClosingOrClosed { 2149 if !shouldGracefullyClose { 2150 return nil 2151 } 2152 // Even if we're already closing, it may not be graceful: 2153 // If we are not the ones doing the closing, we just wait for the graceful close 2154 // to happen and then return. 2155 if isAlreadyGracefullyClosingOrClosed { 2156 <-pc.isGracefulCloseDone 2157 return nil 2158 } 2159 // Otherwise we need to go through the graceful closure flow once the 2160 // normal closure is done since there are extra steps to take with a 2161 // graceful close. 2162 <-pc.isCloseDone 2163 } else { 2164 defer close(pc.isCloseDone) 2165 } 2166 2167 if shouldGracefullyClose { 2168 defer close(pc.isGracefulCloseDone) 2169 } 2170 2171 // Try closing everything and collect the errors 2172 // Shutdown strategy: 2173 // 1. All Conn close by closing their underlying Conn. 2174 // 2. A Mux stops this chain. It won't close the underlying 2175 // Conn if one of the endpoints is closed down. To 2176 // continue the chain the Mux has to be closed. 2177 closeErrs := make([]error, 4) 2178 2179 doGracefulCloseOps := func() []error { 2180 if !shouldGracefullyClose { 2181 return nil 2182 } 2183 2184 // these are all non-canon steps 2185 var gracefulCloseErrors []error 2186 if pc.iceTransport != nil { 2187 gracefulCloseErrors = append(gracefulCloseErrors, pc.iceTransport.GracefulStop()) 2188 } 2189 2190 pc.ops.GracefulClose() 2191 2192 pc.sctpTransport.lock.Lock() 2193 for _, d := range pc.sctpTransport.dataChannels { 2194 gracefulCloseErrors = append(gracefulCloseErrors, d.GracefulClose()) 2195 } 2196 pc.sctpTransport.lock.Unlock() 2197 return gracefulCloseErrors 2198 } 2199 2200 if isAlreadyClosingOrClosed { 2201 return util.FlattenErrs(doGracefulCloseOps()) 2202 } 2203 2204 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #3) 2205 pc.signalingState.Set(SignalingStateClosed) 2206 2207 closeErrs = append(closeErrs, pc.api.interceptor.Close()) 2208 2209 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #4) 2210 pc.mu.Lock() 2211 for _, t := range pc.rtpTransceivers { 2212 if !t.stopped { 2213 closeErrs = append(closeErrs, t.Stop()) 2214 } 2215 } 2216 if nonMediaBandwidthProbe, ok := pc.nonMediaBandwidthProbe.Load().(*RTPReceiver); ok { 2217 closeErrs = append(closeErrs, nonMediaBandwidthProbe.Stop()) 2218 } 2219 pc.mu.Unlock() 2220 2221 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #5) 2222 pc.sctpTransport.lock.Lock() 2223 for _, d := range pc.sctpTransport.dataChannels { 2224 d.setReadyState(DataChannelStateClosed) 2225 } 2226 pc.sctpTransport.lock.Unlock() 2227 2228 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #6) 2229 if pc.sctpTransport != nil { 2230 closeErrs = append(closeErrs, pc.sctpTransport.Stop()) 2231 } 2232 2233 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #7) 2234 closeErrs = append(closeErrs, pc.dtlsTransport.Stop()) 2235 2236 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #8, #9, #10) 2237 if pc.iceTransport != nil && !shouldGracefullyClose { 2238 // we will stop gracefully in doGracefulCloseOps 2239 closeErrs = append(closeErrs, pc.iceTransport.Stop()) 2240 } 2241 2242 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-close (step #11) 2243 pc.updateConnectionState(pc.ICEConnectionState(), pc.dtlsTransport.State()) 2244 2245 closeErrs = append(closeErrs, doGracefulCloseOps()...) 2246 2247 return util.FlattenErrs(closeErrs) 2248 } 2249 2250 // addRTPTransceiver appends t into rtpTransceivers 2251 // and fires onNegotiationNeeded; 2252 // caller of this method should hold `pc.mu` lock 2253 func (pc *PeerConnection) addRTPTransceiver(t *RTPTransceiver) { 2254 pc.rtpTransceivers = append(pc.rtpTransceivers, t) 2255 pc.onNegotiationNeeded() 2256 } 2257 2258 // CurrentLocalDescription represents the local description that was 2259 // successfully negotiated the last time the PeerConnection transitioned 2260 // into the stable state plus any local candidates that have been generated 2261 // by the ICEAgent since the offer or answer was created. 2262 func (pc *PeerConnection) CurrentLocalDescription() *SessionDescription { 2263 pc.mu.Lock() 2264 defer pc.mu.Unlock() 2265 2266 localDescription := pc.currentLocalDescription 2267 iceGather := pc.iceGatherer 2268 iceGatheringState := pc.ICEGatheringState() 2269 return populateLocalCandidates(localDescription, iceGather, iceGatheringState) 2270 } 2271 2272 // PendingLocalDescription represents a local description that is in the 2273 // process of being negotiated plus any local candidates that have been 2274 // generated by the ICEAgent since the offer or answer was created. If the 2275 // PeerConnection is in the stable state, the value is null. 2276 func (pc *PeerConnection) PendingLocalDescription() *SessionDescription { 2277 pc.mu.Lock() 2278 defer pc.mu.Unlock() 2279 2280 localDescription := pc.pendingLocalDescription 2281 iceGather := pc.iceGatherer 2282 iceGatheringState := pc.ICEGatheringState() 2283 return populateLocalCandidates(localDescription, iceGather, iceGatheringState) 2284 } 2285 2286 // CurrentRemoteDescription represents the last remote description that was 2287 // successfully negotiated the last time the PeerConnection transitioned 2288 // into the stable state plus any remote candidates that have been supplied 2289 // via AddICECandidate() since the offer or answer was created. 2290 func (pc *PeerConnection) CurrentRemoteDescription() *SessionDescription { 2291 pc.mu.RLock() 2292 defer pc.mu.RUnlock() 2293 2294 return pc.currentRemoteDescription 2295 } 2296 2297 // PendingRemoteDescription represents a remote description that is in the 2298 // process of being negotiated, complete with any remote candidates that 2299 // have been supplied via AddICECandidate() since the offer or answer was 2300 // created. If the PeerConnection is in the stable state, the value is 2301 // null. 2302 func (pc *PeerConnection) PendingRemoteDescription() *SessionDescription { 2303 pc.mu.RLock() 2304 defer pc.mu.RUnlock() 2305 2306 return pc.pendingRemoteDescription 2307 } 2308 2309 // SignalingState attribute returns the signaling state of the 2310 // PeerConnection instance. 2311 func (pc *PeerConnection) SignalingState() SignalingState { 2312 return pc.signalingState.Get() 2313 } 2314 2315 // ICEGatheringState attribute returns the ICE gathering state of the 2316 // PeerConnection instance. 2317 func (pc *PeerConnection) ICEGatheringState() ICEGatheringState { 2318 if pc.iceGatherer == nil { 2319 return ICEGatheringStateNew 2320 } 2321 2322 switch pc.iceGatherer.State() { 2323 case ICEGathererStateNew: 2324 return ICEGatheringStateNew 2325 case ICEGathererStateGathering: 2326 return ICEGatheringStateGathering 2327 default: 2328 return ICEGatheringStateComplete 2329 } 2330 } 2331 2332 // ConnectionState attribute returns the connection state of the 2333 // PeerConnection instance. 2334 func (pc *PeerConnection) ConnectionState() PeerConnectionState { 2335 if state, ok := pc.connectionState.Load().(PeerConnectionState); ok { 2336 return state 2337 } 2338 return PeerConnectionState(0) 2339 } 2340 2341 // GetStats return data providing statistics about the overall connection 2342 func (pc *PeerConnection) GetStats() StatsReport { 2343 var ( 2344 dataChannelsAccepted uint32 2345 dataChannelsClosed uint32 2346 dataChannelsOpened uint32 2347 dataChannelsRequested uint32 2348 ) 2349 statsCollector := newStatsReportCollector() 2350 statsCollector.Collecting() 2351 2352 pc.mu.Lock() 2353 if pc.iceGatherer != nil { 2354 pc.iceGatherer.collectStats(statsCollector) 2355 } 2356 if pc.iceTransport != nil { 2357 pc.iceTransport.collectStats(statsCollector) 2358 } 2359 2360 pc.sctpTransport.lock.Lock() 2361 dataChannels := append([]*DataChannel{}, pc.sctpTransport.dataChannels...) 2362 dataChannelsAccepted = pc.sctpTransport.dataChannelsAccepted 2363 dataChannelsOpened = pc.sctpTransport.dataChannelsOpened 2364 dataChannelsRequested = pc.sctpTransport.dataChannelsRequested 2365 pc.sctpTransport.lock.Unlock() 2366 2367 for _, d := range dataChannels { 2368 state := d.ReadyState() 2369 if state != DataChannelStateConnecting && state != DataChannelStateOpen { 2370 dataChannelsClosed++ 2371 } 2372 2373 d.collectStats(statsCollector) 2374 } 2375 pc.sctpTransport.collectStats(statsCollector) 2376 2377 stats := PeerConnectionStats{ 2378 Timestamp: statsTimestampNow(), 2379 Type: StatsTypePeerConnection, 2380 ID: pc.statsID, 2381 DataChannelsAccepted: dataChannelsAccepted, 2382 DataChannelsClosed: dataChannelsClosed, 2383 DataChannelsOpened: dataChannelsOpened, 2384 DataChannelsRequested: dataChannelsRequested, 2385 } 2386 2387 statsCollector.Collect(stats.ID, stats) 2388 2389 certificates := pc.configuration.Certificates 2390 for _, certificate := range certificates { 2391 if err := certificate.collectStats(statsCollector); err != nil { 2392 continue 2393 } 2394 } 2395 pc.mu.Unlock() 2396 2397 pc.api.mediaEngine.collectStats(statsCollector) 2398 2399 return statsCollector.Ready() 2400 } 2401 2402 // Start all transports. PeerConnection now has enough state 2403 func (pc *PeerConnection) startTransports(iceRole ICERole, dtlsRole DTLSRole, remoteUfrag, remotePwd, fingerprint, fingerprintHash string) { 2404 // Start the ice transport 2405 err := pc.iceTransport.Start( 2406 pc.iceGatherer, 2407 ICEParameters{ 2408 UsernameFragment: remoteUfrag, 2409 Password: remotePwd, 2410 ICELite: false, 2411 }, 2412 &iceRole, 2413 ) 2414 if err != nil { 2415 pc.log.Warnf("Failed to start manager: %s", err) 2416 return 2417 } 2418 2419 pc.dtlsTransport.internalOnCloseHandler = func() { 2420 if pc.isClosed.get() { 2421 return 2422 } 2423 2424 pc.log.Info("Closing PeerConnection from DTLS CloseNotify") 2425 go func() { 2426 if pcClosErr := pc.Close(); pcClosErr != nil { 2427 pc.log.Warnf("Failed to close PeerConnection from DTLS CloseNotify: %s", pcClosErr) 2428 } 2429 }() 2430 } 2431 2432 // Start the dtls transport 2433 err = pc.dtlsTransport.Start(DTLSParameters{ 2434 Role: dtlsRole, 2435 Fingerprints: []DTLSFingerprint{{Algorithm: fingerprintHash, Value: fingerprint}}, 2436 }) 2437 pc.updateConnectionState(pc.ICEConnectionState(), pc.dtlsTransport.State()) 2438 if err != nil { 2439 pc.log.Warnf("Failed to start manager: %s", err) 2440 return 2441 } 2442 } 2443 2444 // nolint: gocognit 2445 func (pc *PeerConnection) startRTP(isRenegotiation bool, remoteDesc *SessionDescription, currentTransceivers []*RTPTransceiver) { 2446 if !isRenegotiation { 2447 pc.undeclaredMediaProcessor() 2448 } 2449 2450 pc.startRTPReceivers(remoteDesc, currentTransceivers) 2451 if haveApplicationMediaSection(remoteDesc.parsed) { 2452 pc.startSCTP() 2453 } 2454 } 2455 2456 // generateUnmatchedSDP generates an SDP that doesn't take remote state into account 2457 // This is used for the initial call for CreateOffer 2458 func (pc *PeerConnection) generateUnmatchedSDP(transceivers []*RTPTransceiver, useIdentity bool) (*sdp.SessionDescription, error) { 2459 d, err := sdp.NewJSEPSessionDescription(useIdentity) 2460 if err != nil { 2461 return nil, err 2462 } 2463 d.Attributes = append(d.Attributes, sdp.Attribute{Key: sdp.AttrKeyMsidSemantic, Value: "WMS*"}) 2464 2465 iceParams, err := pc.iceGatherer.GetLocalParameters() 2466 if err != nil { 2467 return nil, err 2468 } 2469 2470 candidates, err := pc.iceGatherer.GetLocalCandidates() 2471 if err != nil { 2472 return nil, err 2473 } 2474 2475 isPlanB := pc.configuration.SDPSemantics == SDPSemanticsPlanB 2476 mediaSections := []mediaSection{} 2477 2478 // Needed for pc.sctpTransport.dataChannelsRequested 2479 pc.sctpTransport.lock.Lock() 2480 defer pc.sctpTransport.lock.Unlock() 2481 2482 if isPlanB { 2483 video := make([]*RTPTransceiver, 0) 2484 audio := make([]*RTPTransceiver, 0) 2485 2486 for _, t := range transceivers { 2487 if t.kind == RTPCodecTypeVideo { 2488 video = append(video, t) 2489 } else if t.kind == RTPCodecTypeAudio { 2490 audio = append(audio, t) 2491 } 2492 if sender := t.Sender(); sender != nil { 2493 sender.setNegotiated() 2494 } 2495 } 2496 2497 if len(video) > 0 { 2498 mediaSections = append(mediaSections, mediaSection{id: "video", transceivers: video}) 2499 } 2500 if len(audio) > 0 { 2501 mediaSections = append(mediaSections, mediaSection{id: "audio", transceivers: audio}) 2502 } 2503 2504 if pc.sctpTransport.dataChannelsRequested != 0 { 2505 mediaSections = append(mediaSections, mediaSection{id: "data", data: true}) 2506 } 2507 } else { 2508 for _, t := range transceivers { 2509 if sender := t.Sender(); sender != nil { 2510 sender.setNegotiated() 2511 } 2512 mediaSections = append(mediaSections, mediaSection{id: t.Mid(), transceivers: []*RTPTransceiver{t}}) 2513 } 2514 2515 if pc.sctpTransport.dataChannelsRequested != 0 { 2516 mediaSections = append(mediaSections, mediaSection{id: strconv.Itoa(len(mediaSections)), data: true}) 2517 } 2518 } 2519 2520 dtlsFingerprints, err := pc.configuration.Certificates[0].GetFingerprints() 2521 if err != nil { 2522 return nil, err 2523 } 2524 2525 return populateSDP(d, isPlanB, dtlsFingerprints, pc.api.settingEngine.sdpMediaLevelFingerprints, pc.api.settingEngine.candidates.ICELite, true, pc.api.mediaEngine, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), candidates, iceParams, mediaSections, pc.ICEGatheringState(), nil) 2526 } 2527 2528 // generateMatchedSDP generates a SDP and takes the remote state into account 2529 // this is used everytime we have a RemoteDescription 2530 // nolint: gocyclo 2531 func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, useIdentity bool, includeUnmatched bool, connectionRole sdp.ConnectionRole) (*sdp.SessionDescription, error) { //nolint:gocognit 2532 d, err := sdp.NewJSEPSessionDescription(useIdentity) 2533 if err != nil { 2534 return nil, err 2535 } 2536 d.Attributes = append(d.Attributes, sdp.Attribute{Key: sdp.AttrKeyMsidSemantic, Value: "WMS*"}) 2537 2538 iceParams, err := pc.iceGatherer.GetLocalParameters() 2539 if err != nil { 2540 return nil, err 2541 } 2542 2543 candidates, err := pc.iceGatherer.GetLocalCandidates() 2544 if err != nil { 2545 return nil, err 2546 } 2547 2548 var t *RTPTransceiver 2549 remoteDescription := pc.currentRemoteDescription 2550 if pc.pendingRemoteDescription != nil { 2551 remoteDescription = pc.pendingRemoteDescription 2552 } 2553 isExtmapAllowMixed := isExtMapAllowMixedSet(remoteDescription.parsed) 2554 localTransceivers := append([]*RTPTransceiver{}, transceivers...) 2555 2556 detectedPlanB := descriptionIsPlanB(remoteDescription, pc.log) 2557 if pc.configuration.SDPSemantics != SDPSemanticsUnifiedPlan { 2558 detectedPlanB = descriptionPossiblyPlanB(remoteDescription) 2559 } 2560 2561 mediaSections := []mediaSection{} 2562 alreadyHaveApplicationMediaSection := false 2563 for _, media := range remoteDescription.parsed.MediaDescriptions { 2564 midValue := getMidValue(media) 2565 if midValue == "" { 2566 return nil, errPeerConnRemoteDescriptionWithoutMidValue 2567 } 2568 2569 if media.MediaName.Media == mediaSectionApplication { 2570 mediaSections = append(mediaSections, mediaSection{id: midValue, data: true}) 2571 alreadyHaveApplicationMediaSection = true 2572 continue 2573 } 2574 2575 kind := NewRTPCodecType(media.MediaName.Media) 2576 direction := getPeerDirection(media) 2577 if kind == 0 || direction == RTPTransceiverDirectionUnknown { 2578 continue 2579 } 2580 2581 sdpSemantics := pc.configuration.SDPSemantics 2582 2583 switch { 2584 case sdpSemantics == SDPSemanticsPlanB || sdpSemantics == SDPSemanticsUnifiedPlanWithFallback && detectedPlanB: 2585 if !detectedPlanB { 2586 return nil, &rtcerr.TypeError{Err: fmt.Errorf("%w: Expected PlanB, but RemoteDescription is UnifiedPlan", ErrIncorrectSDPSemantics)} 2587 } 2588 // If we're responding to a plan-b offer, then we should try to fill up this 2589 // media entry with all matching local transceivers 2590 mediaTransceivers := []*RTPTransceiver{} 2591 for { 2592 // keep going until we can't get any more 2593 t, localTransceivers = satisfyTypeAndDirection(kind, direction, localTransceivers) 2594 if t == nil { 2595 if len(mediaTransceivers) == 0 { 2596 t = &RTPTransceiver{kind: kind, api: pc.api, codecs: pc.api.mediaEngine.getCodecsByKind(kind)} 2597 t.setDirection(RTPTransceiverDirectionInactive) 2598 mediaTransceivers = append(mediaTransceivers, t) 2599 } 2600 break 2601 } 2602 if sender := t.Sender(); sender != nil { 2603 sender.setNegotiated() 2604 } 2605 mediaTransceivers = append(mediaTransceivers, t) 2606 } 2607 mediaSections = append(mediaSections, mediaSection{id: midValue, transceivers: mediaTransceivers}) 2608 case sdpSemantics == SDPSemanticsUnifiedPlan || sdpSemantics == SDPSemanticsUnifiedPlanWithFallback: 2609 if detectedPlanB { 2610 return nil, &rtcerr.TypeError{Err: fmt.Errorf("%w: Expected UnifiedPlan, but RemoteDescription is PlanB", ErrIncorrectSDPSemantics)} 2611 } 2612 t, localTransceivers = findByMid(midValue, localTransceivers) 2613 if t == nil { 2614 return nil, fmt.Errorf("%w: %q", errPeerConnTranscieverMidNil, midValue) 2615 } 2616 if sender := t.Sender(); sender != nil { 2617 sender.setNegotiated() 2618 } 2619 mediaTransceivers := []*RTPTransceiver{t} 2620 2621 extensions, _ := rtpExtensionsFromMediaDescription(media) 2622 mediaSections = append(mediaSections, mediaSection{id: midValue, transceivers: mediaTransceivers, matchExtensions: extensions, rids: getRids(media)}) 2623 } 2624 } 2625 2626 var bundleGroup *string 2627 // If we are offering also include unmatched local transceivers 2628 if includeUnmatched { 2629 if !detectedPlanB { 2630 for _, t := range localTransceivers { 2631 if sender := t.Sender(); sender != nil { 2632 sender.setNegotiated() 2633 } 2634 mediaSections = append(mediaSections, mediaSection{id: t.Mid(), transceivers: []*RTPTransceiver{t}}) 2635 } 2636 } 2637 2638 if pc.sctpTransport.dataChannelsRequested != 0 && !alreadyHaveApplicationMediaSection { 2639 if detectedPlanB { 2640 mediaSections = append(mediaSections, mediaSection{id: "data", data: true}) 2641 } else { 2642 mediaSections = append(mediaSections, mediaSection{id: strconv.Itoa(len(mediaSections)), data: true}) 2643 } 2644 } 2645 } else if remoteDescription != nil { 2646 groupValue, _ := remoteDescription.parsed.Attribute(sdp.AttrKeyGroup) 2647 groupValue = strings.TrimLeft(groupValue, "BUNDLE") 2648 bundleGroup = &groupValue 2649 } 2650 2651 if pc.configuration.SDPSemantics == SDPSemanticsUnifiedPlanWithFallback && detectedPlanB { 2652 pc.log.Info("Plan-B Offer detected; responding with Plan-B Answer") 2653 } 2654 2655 dtlsFingerprints, err := pc.configuration.Certificates[0].GetFingerprints() 2656 if err != nil { 2657 return nil, err 2658 } 2659 2660 return populateSDP(d, detectedPlanB, dtlsFingerprints, pc.api.settingEngine.sdpMediaLevelFingerprints, pc.api.settingEngine.candidates.ICELite, isExtmapAllowMixed, pc.api.mediaEngine, connectionRole, candidates, iceParams, mediaSections, pc.ICEGatheringState(), bundleGroup) 2661 } 2662 2663 func (pc *PeerConnection) setGatherCompleteHandler(handler func()) { 2664 pc.iceGatherer.onGatheringCompleteHandler.Store(handler) 2665 } 2666 2667 // SCTP returns the SCTPTransport for this PeerConnection 2668 // 2669 // The SCTP transport over which SCTP data is sent and received. If SCTP has not been negotiated, the value is nil. 2670 // https://www.w3.org/TR/webrtc/#attributes-15 2671 func (pc *PeerConnection) SCTP() *SCTPTransport { 2672 return pc.sctpTransport 2673 }