@@ -98,11 +98,11 @@ type RTCPeerConnection struct {
98
98
// OnNegotiationNeeded func() // FIXME NOT-USED
99
99
// OnIceCandidate func() // FIXME NOT-USED
100
100
// OnIceCandidateError func() // FIXME NOT-USED
101
- // OnSignalingStateChange func() // FIXME NOT-USED
102
101
103
102
// OnIceGatheringStateChange func() // FIXME NOT-USED
104
103
// OnConnectionStateChange func() // FIXME NOT-USED
105
104
105
+ onSignalingStateChangeHandler func (RTCSignalingState )
106
106
onICEConnectionStateChangeHandler func (ice.ConnectionState )
107
107
onTrackHandler func (* RTCTrack )
108
108
onDataChannelHandler func (* RTCDataChannel )
@@ -225,6 +225,33 @@ func (pc *RTCPeerConnection) initConfiguration(configuration RTCConfiguration) e
225
225
return nil
226
226
}
227
227
228
+ // OnSignalingStateChange sets an event handler which is invoked when the
229
+ // peer connection's signaling state changes
230
+ func (pc * RTCPeerConnection ) OnSignalingStateChange (f func (RTCSignalingState )) {
231
+ pc .Lock ()
232
+ defer pc .Unlock ()
233
+ pc .onSignalingStateChangeHandler = f
234
+ }
235
+
236
+ func (pc * RTCPeerConnection ) onSignalingStateChange (newState RTCSignalingState ) (done chan struct {}) {
237
+ pc .RLock ()
238
+ hdlr := pc .onSignalingStateChangeHandler
239
+ pc .RUnlock ()
240
+
241
+ done = make (chan struct {})
242
+ if hdlr == nil {
243
+ close (done )
244
+ return
245
+ }
246
+
247
+ go func () {
248
+ hdlr (newState )
249
+ close (done )
250
+ }()
251
+
252
+ return
253
+ }
254
+
228
255
// OnDataChannel sets an event handler which is invoked when a data
229
256
// channel message arrives from a remote peer.
230
257
func (pc * RTCPeerConnection ) OnDataChannel (f func (* RTCDataChannel )) {
@@ -424,13 +451,19 @@ func (pc *RTCPeerConnection) CreateOffer(options *RTCOfferOptions) (RTCSessionDe
424
451
m .WithPropertyAttribute ("setup:actpass" )
425
452
}
426
453
427
- pc . CurrentLocalDescription = & RTCSessionDescription {
454
+ desc := RTCSessionDescription {
428
455
Type : RTCSdpTypeOffer ,
429
456
Sdp : d .Marshal (),
430
457
parsed : d ,
431
458
}
459
+ pc .lastOffer = desc .Sdp
432
460
433
- return * pc .CurrentLocalDescription , nil
461
+ // FIXME: This doesn't follow the JS API spec, but removing it
462
+ // would mean our examples and existing code have to change
463
+ if err := pc .SetLocalDescription (desc ); err != nil {
464
+ return RTCSessionDescription {}, err
465
+ }
466
+ return desc , nil
434
467
}
435
468
436
469
// CreateAnswer starts the RTCPeerConnection and generates the localDescription
@@ -448,7 +481,7 @@ func (pc *RTCPeerConnection) CreateAnswer(options *RTCAnswerOptions) (RTCSession
448
481
d := sdp .NewJSEPSessionDescription (pc .networkManager .DTLSFingerprint (), useIdentity )
449
482
450
483
bundleValue := "BUNDLE"
451
- for _ , remoteMedia := range pc .CurrentRemoteDescription .parsed .MediaDescriptions {
484
+ for _ , remoteMedia := range pc .RemoteDescription () .parsed .MediaDescriptions {
452
485
// TODO @trivigy better SDP parser
453
486
var peerDirection RTCRtpTransceiverDirection
454
487
midValue := ""
@@ -484,18 +517,148 @@ func (pc *RTCPeerConnection) CreateAnswer(options *RTCAnswerOptions) (RTCSession
484
517
485
518
d = d .WithValueAttribute (sdp .AttrKeyGroup , bundleValue )
486
519
487
- pc . CurrentLocalDescription = & RTCSessionDescription {
520
+ desc := RTCSessionDescription {
488
521
Type : RTCSdpTypeAnswer ,
489
522
Sdp : d .Marshal (),
490
523
parsed : d ,
491
524
}
492
- return * pc .CurrentLocalDescription , nil
525
+ pc .lastAnswer = desc .Sdp
526
+
527
+ // FIXME: This doesn't follow the JS API spec, but removing it
528
+ // would mean our examples and existing code have to change
529
+ if err := pc .SetLocalDescription (desc ); err != nil {
530
+ return RTCSessionDescription {}, err
531
+ }
532
+ return desc , nil
493
533
}
494
534
495
- // // SetLocalDescription sets the SessionDescription of the local peer
496
- // func (pc *RTCPeerConnection) SetLocalDescription() {
497
- // panic("not implemented yet") // FIXME NOT-IMPLEMENTED nolint
498
- // }
535
+ // 4.4.1.6 Set the RTCSessionDescription
536
+ func (pc * RTCPeerConnection ) setDescription (sd * RTCSessionDescription , op rtcStateChangeOp ) error {
537
+ if pc .isClosed {
538
+ return & rtcerr.InvalidStateError {Err : ErrConnectionClosed }
539
+ }
540
+
541
+ cur := pc .SignalingState
542
+ setLocal := rtcStateChangeOpSetLocal
543
+ setRemote := rtcStateChangeOpSetRemote
544
+ newSdpDoesNotMatchOffer := & rtcerr.InvalidModificationError {Err : errors .New ("New sdp does not match previous offer" )}
545
+ newSdpDoesNotMatchAnswer := & rtcerr.InvalidModificationError {Err : errors .New ("New sdp does not match previous answer" )}
546
+
547
+ var nextState RTCSignalingState
548
+ var err error
549
+ switch op {
550
+ case setLocal :
551
+ switch sd .Type {
552
+ // stable->SetLocal(offer)->have-local-offer
553
+ case RTCSdpTypeOffer :
554
+ if sd .Sdp != pc .lastOffer {
555
+ return newSdpDoesNotMatchOffer
556
+ }
557
+ nextState , err = checkNextSignalingState (cur , RTCSignalingStateHaveLocalOffer , setLocal , sd .Type )
558
+ if err == nil {
559
+ pc .PendingLocalDescription = sd
560
+ }
561
+ // have-remote-offer->SetLocal(answer)->stable
562
+ // have-local-pranswer->SetLocal(answer)->stable
563
+ case RTCSdpTypeAnswer :
564
+ if sd .Sdp != pc .lastAnswer {
565
+ return newSdpDoesNotMatchAnswer
566
+ }
567
+ nextState , err = checkNextSignalingState (cur , RTCSignalingStateStable , setLocal , sd .Type )
568
+ if err == nil {
569
+ pc .CurrentLocalDescription = sd
570
+ pc .CurrentRemoteDescription = pc .PendingRemoteDescription
571
+ pc .PendingRemoteDescription = nil
572
+ pc .PendingLocalDescription = nil
573
+ }
574
+ case RTCSdpTypeRollback :
575
+ nextState , err = checkNextSignalingState (cur , RTCSignalingStateStable , setLocal , sd .Type )
576
+ if err == nil {
577
+ pc .PendingLocalDescription = nil
578
+ }
579
+ // have-remote-offer->SetLocal(pranswer)->have-local-pranswer
580
+ case RTCSdpTypePranswer :
581
+ if sd .Sdp != pc .lastAnswer {
582
+ return newSdpDoesNotMatchAnswer
583
+ }
584
+ nextState , err = checkNextSignalingState (cur , RTCSignalingStateHaveLocalPranswer , setLocal , sd .Type )
585
+ if err == nil {
586
+ pc .PendingLocalDescription = sd
587
+ }
588
+ default :
589
+ return & rtcerr.OperationError {Err : fmt .Errorf ("Invalid state change op: %s(%s)" , op , sd .Type )}
590
+ }
591
+ case setRemote :
592
+ switch sd .Type {
593
+ // stable->SetRemote(offer)->have-remote-offer
594
+ case RTCSdpTypeOffer :
595
+ nextState , err = checkNextSignalingState (cur , RTCSignalingStateHaveRemoteOffer , setRemote , sd .Type )
596
+ if err == nil {
597
+ pc .PendingRemoteDescription = sd
598
+ }
599
+ // have-local-offer->SetRemote(answer)->stable
600
+ // have-remote-pranswer->SetRemote(answer)->stable
601
+ case RTCSdpTypeAnswer :
602
+ nextState , err = checkNextSignalingState (cur , RTCSignalingStateStable , setRemote , sd .Type )
603
+ if err == nil {
604
+ pc .CurrentRemoteDescription = sd
605
+ pc .CurrentLocalDescription = pc .PendingLocalDescription
606
+ pc .PendingRemoteDescription = nil
607
+ pc .PendingLocalDescription = nil
608
+ }
609
+ case RTCSdpTypeRollback :
610
+ nextState , err = checkNextSignalingState (cur , RTCSignalingStateStable , setRemote , sd .Type )
611
+ if err == nil {
612
+ pc .PendingRemoteDescription = nil
613
+ }
614
+ // have-local-offer->SetRemote(pranswer)->have-remote-pranswer
615
+ case RTCSdpTypePranswer :
616
+ nextState , err = checkNextSignalingState (cur , RTCSignalingStateHaveRemotePranswer , setRemote , sd .Type )
617
+ if err == nil {
618
+ pc .PendingRemoteDescription = sd
619
+ }
620
+ default :
621
+ return & rtcerr.OperationError {Err : fmt .Errorf ("Invalid state change op: %s(%s)" , op , sd .Type )}
622
+ }
623
+ default :
624
+ return & rtcerr.OperationError {Err : fmt .Errorf ("Unhandled state change op: %q" , op )}
625
+ }
626
+
627
+ if err == nil {
628
+ pc .SignalingState = nextState
629
+ pc .onSignalingStateChange (nextState )
630
+ }
631
+ return err
632
+ }
633
+
634
+ // SetLocalDescription sets the SessionDescription of the local peer
635
+ func (pc * RTCPeerConnection ) SetLocalDescription (desc RTCSessionDescription ) error {
636
+ if pc .isClosed {
637
+ return & rtcerr.InvalidStateError {Err : ErrConnectionClosed }
638
+ }
639
+
640
+ // JSEP 5.4
641
+ if desc .Sdp == "" {
642
+ switch desc .Type {
643
+ case RTCSdpTypeAnswer , RTCSdpTypePranswer :
644
+ desc .Sdp = pc .lastAnswer
645
+ case RTCSdpTypeOffer :
646
+ desc .Sdp = pc .lastOffer
647
+ default :
648
+ return & rtcerr.InvalidModificationError {
649
+ Err : fmt .Errorf ("Invalid SDP type supplied to SetLocalDescription(): %s" , desc .Type ),
650
+ }
651
+ }
652
+ }
653
+
654
+ // TODO: Initiate ICE candidate gathering?
655
+
656
+ desc .parsed = & sdp.SessionDescription {}
657
+ if err := desc .parsed .Unmarshal (desc .Sdp ); err != nil {
658
+ return err
659
+ }
660
+ return pc .setDescription (& desc , rtcStateChangeOpSetLocal )
661
+ }
499
662
500
663
// LocalDescription returns PendingLocalDescription if it is not null and
501
664
// otherwise it returns CurrentLocalDescription. This property is used to
@@ -510,9 +673,21 @@ func (pc *RTCPeerConnection) LocalDescription() *RTCSessionDescription {
510
673
511
674
// SetRemoteDescription sets the SessionDescription of the remote peer
512
675
func (pc * RTCPeerConnection ) SetRemoteDescription (desc RTCSessionDescription ) error {
676
+ // FIXME: Remove this when renegotiation is supported
513
677
if pc .CurrentRemoteDescription != nil {
514
678
return errors .Errorf ("remoteDescription is already defined, SetRemoteDescription can only be called once" )
515
679
}
680
+ if pc .isClosed {
681
+ return & rtcerr.InvalidStateError {Err : ErrConnectionClosed }
682
+ }
683
+
684
+ desc .parsed = & sdp.SessionDescription {}
685
+ if err := desc .parsed .Unmarshal (desc .Sdp ); err != nil {
686
+ return err
687
+ }
688
+ if err := pc .setDescription (& desc , rtcStateChangeOpSetRemote ); err != nil {
689
+ return err
690
+ }
516
691
517
692
weOffer := true
518
693
remoteUfrag := ""
@@ -521,13 +696,7 @@ func (pc *RTCPeerConnection) SetRemoteDescription(desc RTCSessionDescription) er
521
696
weOffer = false
522
697
}
523
698
524
- pc .CurrentRemoteDescription = & desc
525
- pc .CurrentRemoteDescription .parsed = & sdp.SessionDescription {}
526
- if err := pc .CurrentRemoteDescription .parsed .Unmarshal (pc .CurrentRemoteDescription .Sdp ); err != nil {
527
- return err
528
- }
529
-
530
- for _ , m := range pc .CurrentRemoteDescription .parsed .MediaDescriptions {
699
+ for _ , m := range pc .RemoteDescription ().parsed .MediaDescriptions {
531
700
for _ , a := range m .Attributes {
532
701
if strings .HasPrefix (* a .String (), "candidate" ) {
533
702
if c := sdp .ICECandidateUnmarshal (* a .String ()); c != nil {
0 commit comments