werift 0.20.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/common/src/event.js +0 -3
- package/lib/common/src/event.js.map +1 -1
- package/lib/dtls/src/flight/server/flight2.js +5 -3
- package/lib/dtls/src/flight/server/flight2.js.map +1 -1
- package/lib/dtls/src/index.d.ts +1 -1
- package/lib/dtls/src/index.js.map +1 -1
- package/lib/dtls/src/record/receive.js +1 -1
- package/lib/dtls/src/record/receive.js.map +1 -1
- package/lib/ice/src/candidate.d.ts +2 -1
- package/lib/ice/src/candidate.js +17 -4
- package/lib/ice/src/candidate.js.map +1 -1
- package/lib/ice/src/helper.d.ts +6 -6
- package/lib/ice/src/helper.js +18 -15
- package/lib/ice/src/helper.js.map +1 -1
- package/lib/ice/src/ice.d.ts +28 -75
- package/lib/ice/src/ice.js +388 -418
- package/lib/ice/src/ice.js.map +1 -1
- package/lib/ice/src/iceBase.d.ts +109 -0
- package/lib/ice/src/iceBase.js +166 -0
- package/lib/ice/src/iceBase.js.map +1 -0
- package/lib/ice/src/index.d.ts +1 -0
- package/lib/ice/src/index.js +1 -0
- package/lib/ice/src/index.js.map +1 -1
- package/lib/ice/src/stun/message.d.ts +6 -0
- package/lib/ice/src/stun/message.js +4 -0
- package/lib/ice/src/stun/message.js.map +1 -1
- package/lib/ice/src/stun/protocol.d.ts +5 -6
- package/lib/ice/src/stun/protocol.js +18 -18
- package/lib/ice/src/stun/protocol.js.map +1 -1
- package/lib/ice/src/stun/transaction.js +6 -1
- package/lib/ice/src/stun/transaction.js.map +1 -1
- package/lib/ice/src/turn/protocol.d.ts +6 -5
- package/lib/ice/src/turn/protocol.js +54 -36
- package/lib/ice/src/turn/protocol.js.map +1 -1
- package/lib/ice/src/types/model.d.ts +4 -0
- package/lib/ice/src/types/model.js.map +1 -1
- package/lib/rtp/src/extra/container/webm/container.d.ts +3 -1
- package/lib/rtp/src/extra/container/webm/container.js +8 -2
- package/lib/rtp/src/extra/container/webm/container.js.map +1 -1
- package/lib/rtp/src/extra/container/webm/ebml/id.d.ts +6 -0
- package/lib/rtp/src/extra/container/webm/ebml/id.js +6 -0
- package/lib/rtp/src/extra/container/webm/ebml/id.js.map +1 -1
- package/lib/rtp/src/extra/processor/webm.d.ts +11 -16
- package/lib/rtp/src/extra/processor/webm.js.map +1 -1
- package/lib/rtp/src/extra/processor/webmCallback.d.ts +1 -10
- package/lib/rtp/src/extra/processor/webmCallback.js.map +1 -1
- package/lib/rtp/src/rtp/headerExtension.d.ts +45 -3
- package/lib/rtp/src/rtp/headerExtension.js +15 -0
- package/lib/rtp/src/rtp/headerExtension.js.map +1 -1
- package/lib/sctp/src/index.d.ts +1 -1
- package/lib/sctp/src/index.js.map +1 -1
- package/lib/webrtc/src/const.d.ts +2 -2
- package/lib/webrtc/src/const.js.map +1 -1
- package/lib/webrtc/src/media/extension/rtpExtension.d.ts +1 -0
- package/lib/webrtc/src/media/extension/rtpExtension.js +6 -0
- package/lib/webrtc/src/media/extension/rtpExtension.js.map +1 -1
- package/lib/webrtc/src/media/router.d.ts +0 -3
- package/lib/webrtc/src/media/router.js.map +1 -1
- package/lib/webrtc/src/media/rtpReceiver.d.ts +1 -2
- package/lib/webrtc/src/media/rtpReceiver.js +2 -2
- package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
- package/lib/webrtc/src/media/track.d.ts +2 -2
- package/lib/webrtc/src/media/track.js.map +1 -1
- package/lib/webrtc/src/nonstandard/recorder/index.d.ts +1 -0
- package/lib/webrtc/src/nonstandard/recorder/index.js.map +1 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +1 -0
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
- package/lib/webrtc/src/peerConnection.d.ts +12 -6
- package/lib/webrtc/src/peerConnection.js +94 -82
- package/lib/webrtc/src/peerConnection.js.map +1 -1
- package/lib/webrtc/src/sdp.js +15 -3
- package/lib/webrtc/src/sdp.js.map +1 -1
- package/lib/webrtc/src/transport/dtls.d.ts +5 -5
- package/lib/webrtc/src/transport/dtls.js +7 -18
- package/lib/webrtc/src/transport/dtls.js.map +1 -1
- package/lib/webrtc/src/transport/ice.d.ts +20 -9
- package/lib/webrtc/src/transport/ice.js +97 -32
- package/lib/webrtc/src/transport/ice.js.map +1 -1
- package/package.json +1 -1
- package/src/const.ts +2 -2
- package/src/media/extension/rtpExtension.ts +6 -0
- package/src/media/router.ts +2 -3
- package/src/media/rtpReceiver.ts +4 -3
- package/src/media/track.ts +7 -2
- package/src/nonstandard/recorder/index.ts +1 -0
- package/src/nonstandard/recorder/writer/webm.ts +47 -43
- package/src/peerConnection.ts +118 -88
- package/src/sdp.ts +16 -3
- package/src/transport/dtls.ts +11 -9
- package/src/transport/ice.ts +73 -26
package/src/peerConnection.ts
CHANGED
|
@@ -81,7 +81,6 @@ const log = debug("werift:packages/webrtc/src/peerConnection.ts");
|
|
|
81
81
|
export class RTCPeerConnection extends EventTarget {
|
|
82
82
|
readonly cname = uuid.v4();
|
|
83
83
|
sctpTransport?: RTCSctpTransport;
|
|
84
|
-
transportEstablished = false;
|
|
85
84
|
config: Required<PeerConfig> = cloneDeep<PeerConfig>(defaultPeerConfig);
|
|
86
85
|
connectionState: ConnectionState = "new";
|
|
87
86
|
iceConnectionState: RTCIceConnectionState = "new";
|
|
@@ -95,8 +94,7 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
95
94
|
private replaceTransceiver(t: RTCRtpTransceiver, index: number) {
|
|
96
95
|
this.transceivers[index] = t;
|
|
97
96
|
}
|
|
98
|
-
|
|
99
|
-
candidatesSent = new Set<string>();
|
|
97
|
+
needRestart = false;
|
|
100
98
|
|
|
101
99
|
readonly iceGatheringStateChange = new Event<[IceGathererState]>();
|
|
102
100
|
readonly iceConnectionStateChange = new Event<[RTCIceConnectionState]>();
|
|
@@ -117,7 +115,7 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
117
115
|
onconnectionstatechange?: Callback;
|
|
118
116
|
|
|
119
117
|
private readonly router = new RtpRouter();
|
|
120
|
-
private
|
|
118
|
+
private certificate?: RTCCertificate;
|
|
121
119
|
sctpRemotePort?: number;
|
|
122
120
|
private seenMid = new Set<string>();
|
|
123
121
|
private currentLocalDescription?: SessionDescription;
|
|
@@ -147,9 +145,28 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
147
145
|
return this.router.extIdUriMap;
|
|
148
146
|
}
|
|
149
147
|
|
|
148
|
+
get iceGeneration() {
|
|
149
|
+
return this.iceTransports[0].connection.generation;
|
|
150
|
+
}
|
|
151
|
+
|
|
150
152
|
constructor(config: Partial<PeerConfig> = {}) {
|
|
151
153
|
super();
|
|
152
154
|
|
|
155
|
+
this.setConfiguration(config);
|
|
156
|
+
|
|
157
|
+
this.iceConnectionStateChange.subscribe((state) => {
|
|
158
|
+
switch (state) {
|
|
159
|
+
case "disconnected":
|
|
160
|
+
this.setConnectionState("disconnected");
|
|
161
|
+
break;
|
|
162
|
+
case "closed":
|
|
163
|
+
this.close();
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
setConfiguration(config: Partial<PeerConfig>) {
|
|
153
170
|
deepMerge(this.config, config);
|
|
154
171
|
|
|
155
172
|
if (this.config.icePortRange) {
|
|
@@ -194,23 +211,15 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
194
211
|
|
|
195
212
|
if (this.config.dtls) {
|
|
196
213
|
const { keys } = this.config.dtls;
|
|
214
|
+
|
|
197
215
|
if (keys) {
|
|
198
|
-
this.
|
|
199
|
-
|
|
216
|
+
this.certificate = new RTCCertificate(
|
|
217
|
+
keys.keyPem,
|
|
218
|
+
keys.certPem,
|
|
219
|
+
keys.signatureHash,
|
|
200
220
|
);
|
|
201
221
|
}
|
|
202
222
|
}
|
|
203
|
-
|
|
204
|
-
this.iceConnectionStateChange.subscribe((state) => {
|
|
205
|
-
switch (state) {
|
|
206
|
-
case "disconnected":
|
|
207
|
-
this.setConnectionState("disconnected");
|
|
208
|
-
break;
|
|
209
|
-
case "closed":
|
|
210
|
-
this.close();
|
|
211
|
-
break;
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
223
|
}
|
|
215
224
|
|
|
216
225
|
get localDescription() {
|
|
@@ -251,8 +260,16 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
251
260
|
return this.config;
|
|
252
261
|
}
|
|
253
262
|
|
|
254
|
-
async createOffer() {
|
|
263
|
+
async createOffer({ iceRestart }: { iceRestart?: boolean } = {}) {
|
|
264
|
+
if (iceRestart || this.needRestart) {
|
|
265
|
+
this.needRestart = false;
|
|
266
|
+
for (const t of this.iceTransports) {
|
|
267
|
+
t.restart();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
255
271
|
await this.ensureCerts();
|
|
272
|
+
|
|
256
273
|
const description = this.buildOfferSdp();
|
|
257
274
|
return description.toJSON();
|
|
258
275
|
}
|
|
@@ -465,7 +482,9 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
465
482
|
|
|
466
483
|
private needNegotiation = async () => {
|
|
467
484
|
this.shouldNegotiationneeded = true;
|
|
468
|
-
if (this.negotiationneeded || this.signalingState !== "stable")
|
|
485
|
+
if (this.negotiationneeded || this.signalingState !== "stable") {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
469
488
|
this.shouldNegotiationneeded = false;
|
|
470
489
|
setImmediate(() => {
|
|
471
490
|
this.negotiationneeded = true;
|
|
@@ -493,12 +512,13 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
493
512
|
additionalHostAddresses: this.config.iceAdditionalHostAddresses,
|
|
494
513
|
filterStunResponse: this.config.iceFilterStunResponse,
|
|
495
514
|
filterCandidatePair: this.config.iceFilterCandidatePair,
|
|
515
|
+
localPasswordPrefix: this.config.icePasswordPrefix,
|
|
496
516
|
useIpv4: this.config.iceUseIpv4,
|
|
497
517
|
useIpv6: this.config.iceUseIpv6,
|
|
498
518
|
turnTransport: this.config.forceTurnTCP === true ? "tcp" : "udp",
|
|
499
519
|
});
|
|
500
520
|
if (existing) {
|
|
501
|
-
iceGatherer.connection.
|
|
521
|
+
iceGatherer.connection.localUsername = existing.connection.localUsername;
|
|
502
522
|
iceGatherer.connection.localPassword = existing.connection.localPassword;
|
|
503
523
|
}
|
|
504
524
|
iceGatherer.onGatheringStateChange.subscribe(() => {
|
|
@@ -509,8 +529,10 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
509
529
|
iceTransport.onStateChange.subscribe(() => {
|
|
510
530
|
this.updateIceConnectionState();
|
|
511
531
|
});
|
|
512
|
-
|
|
513
|
-
|
|
532
|
+
iceTransport.onNegotiationNeeded.subscribe(() => {
|
|
533
|
+
this.needNegotiation();
|
|
534
|
+
});
|
|
535
|
+
iceTransport.onIceCandidate.subscribe((candidate) => {
|
|
514
536
|
if (!this.localDescription) {
|
|
515
537
|
log("localDescription not found when ice candidate was gathered");
|
|
516
538
|
return;
|
|
@@ -549,28 +571,18 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
549
571
|
|
|
550
572
|
candidate.foundation = "candidate:" + candidate.foundation;
|
|
551
573
|
|
|
552
|
-
// prevent ice candidates that have already been sent from being being resent
|
|
553
|
-
// when the connection is renegotiated during a later setLocalDescription call.
|
|
554
|
-
if (candidate.sdpMid) {
|
|
555
|
-
const candidateKey = `${candidate.foundation}:${candidate.sdpMid}`;
|
|
556
|
-
if (this.candidatesSent.has(candidateKey)) {
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
this.candidatesSent.add(candidateKey);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
574
|
this.onIceCandidate.execute(candidate.toJSON());
|
|
563
575
|
if (this.onicecandidate) {
|
|
564
576
|
this.onicecandidate({ candidate: candidate.toJSON() });
|
|
565
577
|
}
|
|
566
578
|
this.emit("icecandidate", { candidate });
|
|
567
|
-
};
|
|
579
|
+
});
|
|
568
580
|
|
|
569
581
|
const dtlsTransport = new RTCDtlsTransport(
|
|
570
582
|
this.config,
|
|
571
583
|
iceTransport,
|
|
572
584
|
this.router,
|
|
573
|
-
this.
|
|
585
|
+
this.certificate,
|
|
574
586
|
srtpProfiles,
|
|
575
587
|
);
|
|
576
588
|
|
|
@@ -617,7 +629,7 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
617
629
|
}
|
|
618
630
|
|
|
619
631
|
// # assign MID
|
|
620
|
-
description.media
|
|
632
|
+
for (const [i, media] of enumerate(description.media)) {
|
|
621
633
|
const mid = media.rtp.muxId!;
|
|
622
634
|
this.seenMid.add(mid);
|
|
623
635
|
if (["audio", "video"].includes(media.kind)) {
|
|
@@ -629,9 +641,10 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
629
641
|
if (media.kind === "application" && this.sctpTransport) {
|
|
630
642
|
this.sctpTransport.mid = mid;
|
|
631
643
|
}
|
|
632
|
-
}
|
|
644
|
+
}
|
|
633
645
|
|
|
634
|
-
|
|
646
|
+
// setup ice,dtls role
|
|
647
|
+
for (const dtlsTransport of this.dtlsTransports) {
|
|
635
648
|
const iceTransport = dtlsTransport.iceTransport;
|
|
636
649
|
|
|
637
650
|
// # set ICE role
|
|
@@ -654,34 +667,22 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
654
667
|
dtlsTransport.role = role;
|
|
655
668
|
}
|
|
656
669
|
}
|
|
657
|
-
}
|
|
658
|
-
this.dtlsTransports.forEach((d) => setupRole(d));
|
|
670
|
+
}
|
|
659
671
|
|
|
660
672
|
// # configure direction
|
|
661
673
|
if (["answer", "pranswer"].includes(description.type)) {
|
|
662
|
-
this.transceivers
|
|
674
|
+
for (const t of this.transceivers) {
|
|
663
675
|
const direction = andDirection(t.direction, t.offerDirection);
|
|
664
676
|
t.setCurrentDirection(direction);
|
|
665
|
-
}
|
|
677
|
+
}
|
|
666
678
|
}
|
|
667
679
|
|
|
668
680
|
// for trickle ice
|
|
669
681
|
this.setLocal(description);
|
|
670
682
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
);
|
|
675
|
-
if (this.remoteIsBundled && connected) {
|
|
676
|
-
// no need to gather ice candidates on an existing bundled connection
|
|
677
|
-
await connected.iceGather.gather();
|
|
678
|
-
} else {
|
|
679
|
-
await Promise.allSettled(
|
|
680
|
-
this.iceTransports.map((iceTransport) =>
|
|
681
|
-
iceTransport.iceGather.gather(),
|
|
682
|
-
),
|
|
683
|
-
);
|
|
684
|
-
}
|
|
683
|
+
await this.gatherCandidates().catch((e) => {
|
|
684
|
+
log("gatherCandidates failed", e);
|
|
685
|
+
});
|
|
685
686
|
|
|
686
687
|
// connect transports
|
|
687
688
|
if (description.type === "answer") {
|
|
@@ -700,6 +701,20 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
700
701
|
return description;
|
|
701
702
|
}
|
|
702
703
|
|
|
704
|
+
private async gatherCandidates() {
|
|
705
|
+
// # gather candidates
|
|
706
|
+
const connected = this.iceTransports.find(
|
|
707
|
+
(transport) => transport.state === "connected",
|
|
708
|
+
);
|
|
709
|
+
if (this.remoteIsBundled && connected) {
|
|
710
|
+
// no need to gather ice candidates on an existing bundled connection
|
|
711
|
+
} else {
|
|
712
|
+
await Promise.allSettled(
|
|
713
|
+
this.iceTransports.map((iceTransport) => iceTransport.gather()),
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
703
718
|
private setLocal(description: SessionDescription) {
|
|
704
719
|
description.media
|
|
705
720
|
.filter((m) => ["audio", "video"].includes(m.kind))
|
|
@@ -771,20 +786,25 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
771
786
|
}
|
|
772
787
|
|
|
773
788
|
private async connect() {
|
|
774
|
-
if (this.transportEstablished) {
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
789
|
log("start connect");
|
|
778
790
|
|
|
779
|
-
this.setConnectionState("connecting");
|
|
780
|
-
|
|
781
791
|
await Promise.allSettled(
|
|
782
792
|
this.dtlsTransports.map(async (dtlsTransport) => {
|
|
783
793
|
const { iceTransport } = dtlsTransport;
|
|
794
|
+
if (iceTransport.state === "connected") {
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
this.setConnectionState("connecting");
|
|
799
|
+
|
|
784
800
|
await iceTransport.start().catch((err) => {
|
|
785
801
|
log("iceTransport.start failed", err);
|
|
786
802
|
throw err;
|
|
787
803
|
});
|
|
804
|
+
|
|
805
|
+
if (dtlsTransport.state === "connected") {
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
788
808
|
await dtlsTransport.start().catch((err) => {
|
|
789
809
|
log("dtlsTransport.start failed", err);
|
|
790
810
|
throw err;
|
|
@@ -801,7 +821,6 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
801
821
|
}),
|
|
802
822
|
);
|
|
803
823
|
|
|
804
|
-
this.transportEstablished = true;
|
|
805
824
|
this.setConnectionState("connected");
|
|
806
825
|
}
|
|
807
826
|
|
|
@@ -851,7 +870,7 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
851
870
|
return receiveParameters;
|
|
852
871
|
}
|
|
853
872
|
|
|
854
|
-
get remoteIsBundled() {
|
|
873
|
+
private get remoteIsBundled() {
|
|
855
874
|
const remoteSdp = this._remoteDescription;
|
|
856
875
|
if (!remoteSdp) {
|
|
857
876
|
return undefined;
|
|
@@ -862,6 +881,11 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
862
881
|
return bundle;
|
|
863
882
|
}
|
|
864
883
|
|
|
884
|
+
restartIce() {
|
|
885
|
+
this.needRestart = true;
|
|
886
|
+
this.needNegotiation();
|
|
887
|
+
}
|
|
888
|
+
|
|
865
889
|
async setRemoteDescription(sessionDescription: RTCSessionDescriptionInit) {
|
|
866
890
|
if (
|
|
867
891
|
!sessionDescription.sdp ||
|
|
@@ -954,9 +978,11 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
954
978
|
|
|
955
979
|
const iceTransport = dtlsTransport.iceTransport;
|
|
956
980
|
|
|
957
|
-
if (remoteMedia.iceParams
|
|
958
|
-
|
|
959
|
-
|
|
981
|
+
if (remoteMedia.iceParams) {
|
|
982
|
+
const renomination = !!remoteSdp.media.find(
|
|
983
|
+
(m) => m.direction === "inactive",
|
|
984
|
+
);
|
|
985
|
+
iceTransport.setRemoteParams(remoteMedia.iceParams, renomination);
|
|
960
986
|
|
|
961
987
|
// One agent full, one lite: The full agent MUST take the controlling role, and the lite agent MUST take the controlled role
|
|
962
988
|
// RFC 8445 S6.1.1
|
|
@@ -964,6 +990,9 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
964
990
|
iceTransport.connection.iceControlling = true;
|
|
965
991
|
}
|
|
966
992
|
}
|
|
993
|
+
if (remoteMedia.dtlsParams) {
|
|
994
|
+
dtlsTransport.setRemoteParams(remoteMedia.dtlsParams);
|
|
995
|
+
}
|
|
967
996
|
|
|
968
997
|
// # add ICE candidates
|
|
969
998
|
remoteMedia.iceCandidates.forEach(iceTransport.addRemoteCandidate);
|
|
@@ -1035,13 +1064,17 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
1035
1064
|
const localCodecs = this.config.codecs[remoteMedia.kind] || [];
|
|
1036
1065
|
|
|
1037
1066
|
const existCodec = findCodecByMimeType(localCodecs, remoteCodec);
|
|
1038
|
-
if (!existCodec)
|
|
1067
|
+
if (!existCodec) {
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1039
1070
|
|
|
1040
1071
|
if (existCodec?.name.toLowerCase() === "rtx") {
|
|
1041
1072
|
const params = codecParametersFromString(existCodec.parameters ?? "");
|
|
1042
1073
|
const pt = params["apt"];
|
|
1043
1074
|
const origin = remoteMedia.rtp.codecs.find((c) => c.payloadType === pt);
|
|
1044
|
-
if (!origin)
|
|
1075
|
+
if (!origin) {
|
|
1076
|
+
return false;
|
|
1077
|
+
}
|
|
1045
1078
|
return !!findCodecByMimeType(localCodecs, origin);
|
|
1046
1079
|
}
|
|
1047
1080
|
|
|
@@ -1315,22 +1348,18 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
1315
1348
|
}
|
|
1316
1349
|
|
|
1317
1350
|
private async ensureCerts() {
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
this.certificates.push(localCertificate);
|
|
1322
|
-
} else {
|
|
1323
|
-
dtlsTransport.localCertificate = this.certificates[0];
|
|
1324
|
-
}
|
|
1325
|
-
};
|
|
1351
|
+
if (!this.certificate) {
|
|
1352
|
+
this.certificate = await RTCDtlsTransport.SetupCertificate();
|
|
1353
|
+
}
|
|
1326
1354
|
|
|
1327
1355
|
for (const dtlsTransport of this.dtlsTransports) {
|
|
1328
|
-
|
|
1356
|
+
dtlsTransport.localCertificate = this.certificate;
|
|
1329
1357
|
}
|
|
1330
1358
|
}
|
|
1331
1359
|
|
|
1332
1360
|
async createAnswer() {
|
|
1333
1361
|
await this.ensureCerts();
|
|
1362
|
+
|
|
1334
1363
|
const description = this.buildAnswer();
|
|
1335
1364
|
return description.toJSON();
|
|
1336
1365
|
}
|
|
@@ -1393,11 +1422,11 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
1393
1422
|
|
|
1394
1423
|
if (this.config.bundlePolicy !== "disable") {
|
|
1395
1424
|
const bundle = new GroupDescription("BUNDLE", []);
|
|
1396
|
-
description.media
|
|
1425
|
+
for (const media of description.media) {
|
|
1397
1426
|
if (media.direction !== "inactive") {
|
|
1398
1427
|
bundle.items.push(media.rtp.muxId!);
|
|
1399
1428
|
}
|
|
1400
|
-
}
|
|
1429
|
+
}
|
|
1401
1430
|
description.group.push(bundle);
|
|
1402
1431
|
}
|
|
1403
1432
|
|
|
@@ -1440,8 +1469,8 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
1440
1469
|
|
|
1441
1470
|
function allMatch(...state: IceGathererState[]) {
|
|
1442
1471
|
return (
|
|
1443
|
-
all.filter((check) => state.includes(check.
|
|
1444
|
-
|
|
1472
|
+
all.filter((check) => state.includes(check.gatheringState)).length ===
|
|
1473
|
+
all.length
|
|
1445
1474
|
);
|
|
1446
1475
|
}
|
|
1447
1476
|
|
|
@@ -1451,9 +1480,7 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
1451
1480
|
newState = "complete";
|
|
1452
1481
|
} else if (!all.length || allMatch("new", "complete")) {
|
|
1453
1482
|
newState = "new";
|
|
1454
|
-
} else if (
|
|
1455
|
-
all.map((check) => check.iceGather.gatheringState).includes("gathering")
|
|
1456
|
-
) {
|
|
1483
|
+
} else if (all.map((check) => check.gatheringState).includes("gathering")) {
|
|
1457
1484
|
newState = "gathering";
|
|
1458
1485
|
} else {
|
|
1459
1486
|
newState = "new";
|
|
@@ -1520,7 +1547,9 @@ export class RTCPeerConnection extends EventTarget {
|
|
|
1520
1547
|
log("connectionStateChange", state);
|
|
1521
1548
|
this.connectionState = state;
|
|
1522
1549
|
this.connectionStateChange.execute(state);
|
|
1523
|
-
if (this.onconnectionstatechange)
|
|
1550
|
+
if (this.onconnectionstatechange) {
|
|
1551
|
+
this.onconnectionstatechange();
|
|
1552
|
+
}
|
|
1524
1553
|
this.emit("connectionstatechange");
|
|
1525
1554
|
}
|
|
1526
1555
|
|
|
@@ -1600,11 +1629,10 @@ export function addTransportDescription(
|
|
|
1600
1629
|
dtlsTransport: RTCDtlsTransport,
|
|
1601
1630
|
) {
|
|
1602
1631
|
const iceTransport = dtlsTransport.iceTransport;
|
|
1603
|
-
const iceGatherer = iceTransport.iceGather;
|
|
1604
1632
|
|
|
1605
|
-
media.iceCandidates =
|
|
1606
|
-
media.iceCandidatesComplete =
|
|
1607
|
-
media.iceParams =
|
|
1633
|
+
media.iceCandidates = iceTransport.localCandidates;
|
|
1634
|
+
media.iceCandidatesComplete = iceTransport.gatheringState === "complete";
|
|
1635
|
+
media.iceParams = iceTransport.localParameters;
|
|
1608
1636
|
media.iceOptions = "trickle";
|
|
1609
1637
|
|
|
1610
1638
|
media.host = DISCARD_HOST;
|
|
@@ -1672,6 +1700,7 @@ export interface PeerConfig {
|
|
|
1672
1700
|
dtls: Partial<{
|
|
1673
1701
|
keys: DtlsKeys;
|
|
1674
1702
|
}>;
|
|
1703
|
+
icePasswordPrefix: string | undefined;
|
|
1675
1704
|
bundlePolicy: BundlePolicy;
|
|
1676
1705
|
debug: Partial<{
|
|
1677
1706
|
/**% */
|
|
@@ -1739,6 +1768,7 @@ export const defaultPeerConfig: PeerConfig = {
|
|
|
1739
1768
|
iceUseIpv6: true,
|
|
1740
1769
|
iceFilterStunResponse: undefined,
|
|
1741
1770
|
iceFilterCandidatePair: undefined,
|
|
1771
|
+
icePasswordPrefix: undefined,
|
|
1742
1772
|
dtls: {},
|
|
1743
1773
|
bundlePolicy: "max-compat",
|
|
1744
1774
|
debug: {},
|
package/src/sdp.ts
CHANGED
|
@@ -563,15 +563,22 @@ function ipAddressToSdp(addr: string) {
|
|
|
563
563
|
|
|
564
564
|
export function candidateToSdp(c: IceCandidate) {
|
|
565
565
|
let sdp = `${c.foundation} ${c.component} ${c.protocol} ${c.priority} ${c.ip} ${c.port} typ ${c.type}`;
|
|
566
|
-
if (c.relatedAddress) {
|
|
566
|
+
if (c.relatedAddress != undefined) {
|
|
567
567
|
sdp += ` raddr ${c.relatedAddress}`;
|
|
568
568
|
}
|
|
569
|
-
if (c.relatedPort) {
|
|
569
|
+
if (c.relatedPort != undefined) {
|
|
570
570
|
sdp += ` rport ${c.relatedPort}`;
|
|
571
571
|
}
|
|
572
|
-
if (c.tcpType) {
|
|
572
|
+
if (c.tcpType != undefined) {
|
|
573
573
|
sdp += ` tcptype ${c.tcpType}`;
|
|
574
574
|
}
|
|
575
|
+
if (c.generation != undefined) {
|
|
576
|
+
sdp += ` generation ${c.generation}`;
|
|
577
|
+
}
|
|
578
|
+
if (c.ufrag != undefined) {
|
|
579
|
+
sdp += ` ufrag ${c.ufrag}`;
|
|
580
|
+
}
|
|
581
|
+
|
|
575
582
|
return sdp;
|
|
576
583
|
}
|
|
577
584
|
|
|
@@ -644,6 +651,12 @@ export function candidateFromSdp(sdp: string) {
|
|
|
644
651
|
case "tcptype":
|
|
645
652
|
candidate.tcpType = bits[i + 1];
|
|
646
653
|
break;
|
|
654
|
+
case "generation":
|
|
655
|
+
candidate.generation = Number.parseInt(bits[i + 1]);
|
|
656
|
+
break;
|
|
657
|
+
case "ufrag":
|
|
658
|
+
candidate.ufrag = bits[i + 1];
|
|
659
|
+
break;
|
|
647
660
|
}
|
|
648
661
|
});
|
|
649
662
|
|
package/src/transport/dtls.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
} from "../../../dtls/src/cipher/const";
|
|
19
19
|
import { CipherContext } from "../../../dtls/src/context/cipher";
|
|
20
20
|
import type { Profile } from "../../../dtls/src/context/srtp";
|
|
21
|
-
import type {
|
|
21
|
+
import type { IceConnection } from "../../../ice/src";
|
|
22
22
|
import {
|
|
23
23
|
type RtcpPacket,
|
|
24
24
|
RtcpPacketConverter,
|
|
@@ -51,18 +51,18 @@ export class RTCDtlsTransport {
|
|
|
51
51
|
|
|
52
52
|
readonly onStateChange = new Event<[DtlsState]>();
|
|
53
53
|
|
|
54
|
-
localCertificate?: RTCCertificate;
|
|
55
|
-
localCertificatePromise?: Promise<RTCCertificate>;
|
|
54
|
+
static localCertificate?: RTCCertificate;
|
|
55
|
+
static localCertificatePromise?: Promise<RTCCertificate>;
|
|
56
56
|
private remoteParameters?: RTCDtlsParameters;
|
|
57
57
|
|
|
58
58
|
constructor(
|
|
59
59
|
readonly config: PeerConfig,
|
|
60
60
|
readonly iceTransport: RTCIceTransport,
|
|
61
61
|
readonly router: RtpRouter,
|
|
62
|
-
|
|
62
|
+
public localCertificate?: RTCCertificate,
|
|
63
63
|
private readonly srtpProfiles: Profile[] = [],
|
|
64
64
|
) {
|
|
65
|
-
this.localCertificate
|
|
65
|
+
this.localCertificate ??= RTCDtlsTransport.localCertificate;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
get localParameters() {
|
|
@@ -72,7 +72,7 @@ export class RTCDtlsTransport {
|
|
|
72
72
|
);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
async
|
|
75
|
+
static async SetupCertificate() {
|
|
76
76
|
if (this.localCertificate) {
|
|
77
77
|
return this.localCertificate;
|
|
78
78
|
}
|
|
@@ -360,10 +360,12 @@ export class RTCDtlsParameters {
|
|
|
360
360
|
}
|
|
361
361
|
|
|
362
362
|
class IceTransport implements Transport {
|
|
363
|
-
constructor(private ice:
|
|
363
|
+
constructor(private ice: IceConnection) {
|
|
364
364
|
ice.onData.subscribe((buf) => {
|
|
365
365
|
if (isDtls(buf)) {
|
|
366
|
-
if (this.onData)
|
|
366
|
+
if (this.onData) {
|
|
367
|
+
this.onData(buf);
|
|
368
|
+
}
|
|
367
369
|
}
|
|
368
370
|
});
|
|
369
371
|
}
|
|
@@ -378,4 +380,4 @@ class IceTransport implements Transport {
|
|
|
378
380
|
}
|
|
379
381
|
}
|
|
380
382
|
|
|
381
|
-
const createIceTransport = (ice:
|
|
383
|
+
const createIceTransport = (ice: IceConnection) => new IceTransport(ice);
|