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.
Files changed (90) hide show
  1. package/lib/common/src/event.js +0 -3
  2. package/lib/common/src/event.js.map +1 -1
  3. package/lib/dtls/src/flight/server/flight2.js +5 -3
  4. package/lib/dtls/src/flight/server/flight2.js.map +1 -1
  5. package/lib/dtls/src/index.d.ts +1 -1
  6. package/lib/dtls/src/index.js.map +1 -1
  7. package/lib/dtls/src/record/receive.js +1 -1
  8. package/lib/dtls/src/record/receive.js.map +1 -1
  9. package/lib/ice/src/candidate.d.ts +2 -1
  10. package/lib/ice/src/candidate.js +17 -4
  11. package/lib/ice/src/candidate.js.map +1 -1
  12. package/lib/ice/src/helper.d.ts +6 -6
  13. package/lib/ice/src/helper.js +18 -15
  14. package/lib/ice/src/helper.js.map +1 -1
  15. package/lib/ice/src/ice.d.ts +28 -75
  16. package/lib/ice/src/ice.js +388 -418
  17. package/lib/ice/src/ice.js.map +1 -1
  18. package/lib/ice/src/iceBase.d.ts +109 -0
  19. package/lib/ice/src/iceBase.js +166 -0
  20. package/lib/ice/src/iceBase.js.map +1 -0
  21. package/lib/ice/src/index.d.ts +1 -0
  22. package/lib/ice/src/index.js +1 -0
  23. package/lib/ice/src/index.js.map +1 -1
  24. package/lib/ice/src/stun/message.d.ts +6 -0
  25. package/lib/ice/src/stun/message.js +4 -0
  26. package/lib/ice/src/stun/message.js.map +1 -1
  27. package/lib/ice/src/stun/protocol.d.ts +5 -6
  28. package/lib/ice/src/stun/protocol.js +18 -18
  29. package/lib/ice/src/stun/protocol.js.map +1 -1
  30. package/lib/ice/src/stun/transaction.js +6 -1
  31. package/lib/ice/src/stun/transaction.js.map +1 -1
  32. package/lib/ice/src/turn/protocol.d.ts +6 -5
  33. package/lib/ice/src/turn/protocol.js +54 -36
  34. package/lib/ice/src/turn/protocol.js.map +1 -1
  35. package/lib/ice/src/types/model.d.ts +4 -0
  36. package/lib/ice/src/types/model.js.map +1 -1
  37. package/lib/rtp/src/extra/container/webm/container.d.ts +3 -1
  38. package/lib/rtp/src/extra/container/webm/container.js +8 -2
  39. package/lib/rtp/src/extra/container/webm/container.js.map +1 -1
  40. package/lib/rtp/src/extra/container/webm/ebml/id.d.ts +6 -0
  41. package/lib/rtp/src/extra/container/webm/ebml/id.js +6 -0
  42. package/lib/rtp/src/extra/container/webm/ebml/id.js.map +1 -1
  43. package/lib/rtp/src/extra/processor/webm.d.ts +11 -16
  44. package/lib/rtp/src/extra/processor/webm.js.map +1 -1
  45. package/lib/rtp/src/extra/processor/webmCallback.d.ts +1 -10
  46. package/lib/rtp/src/extra/processor/webmCallback.js.map +1 -1
  47. package/lib/rtp/src/rtp/headerExtension.d.ts +45 -3
  48. package/lib/rtp/src/rtp/headerExtension.js +15 -0
  49. package/lib/rtp/src/rtp/headerExtension.js.map +1 -1
  50. package/lib/sctp/src/index.d.ts +1 -1
  51. package/lib/sctp/src/index.js.map +1 -1
  52. package/lib/webrtc/src/const.d.ts +2 -2
  53. package/lib/webrtc/src/const.js.map +1 -1
  54. package/lib/webrtc/src/media/extension/rtpExtension.d.ts +1 -0
  55. package/lib/webrtc/src/media/extension/rtpExtension.js +6 -0
  56. package/lib/webrtc/src/media/extension/rtpExtension.js.map +1 -1
  57. package/lib/webrtc/src/media/router.d.ts +0 -3
  58. package/lib/webrtc/src/media/router.js.map +1 -1
  59. package/lib/webrtc/src/media/rtpReceiver.d.ts +1 -2
  60. package/lib/webrtc/src/media/rtpReceiver.js +2 -2
  61. package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
  62. package/lib/webrtc/src/media/track.d.ts +2 -2
  63. package/lib/webrtc/src/media/track.js.map +1 -1
  64. package/lib/webrtc/src/nonstandard/recorder/index.d.ts +1 -0
  65. package/lib/webrtc/src/nonstandard/recorder/index.js.map +1 -1
  66. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +1 -0
  67. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
  68. package/lib/webrtc/src/peerConnection.d.ts +12 -6
  69. package/lib/webrtc/src/peerConnection.js +94 -82
  70. package/lib/webrtc/src/peerConnection.js.map +1 -1
  71. package/lib/webrtc/src/sdp.js +15 -3
  72. package/lib/webrtc/src/sdp.js.map +1 -1
  73. package/lib/webrtc/src/transport/dtls.d.ts +5 -5
  74. package/lib/webrtc/src/transport/dtls.js +7 -18
  75. package/lib/webrtc/src/transport/dtls.js.map +1 -1
  76. package/lib/webrtc/src/transport/ice.d.ts +20 -9
  77. package/lib/webrtc/src/transport/ice.js +97 -32
  78. package/lib/webrtc/src/transport/ice.js.map +1 -1
  79. package/package.json +1 -1
  80. package/src/const.ts +2 -2
  81. package/src/media/extension/rtpExtension.ts +6 -0
  82. package/src/media/router.ts +2 -3
  83. package/src/media/rtpReceiver.ts +4 -3
  84. package/src/media/track.ts +7 -2
  85. package/src/nonstandard/recorder/index.ts +1 -0
  86. package/src/nonstandard/recorder/writer/webm.ts +47 -43
  87. package/src/peerConnection.ts +118 -88
  88. package/src/sdp.ts +16 -3
  89. package/src/transport/dtls.ts +11 -9
  90. package/src/transport/ice.ts +73 -26
@@ -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 readonly certificates: RTCCertificate[] = [];
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.certificates.push(
199
- new RTCCertificate(keys.keyPem, keys.certPem, keys.signatureHash),
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") return;
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.localUserName = existing.connection.localUserName;
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
- iceTransport.iceGather.onIceCandidate = (candidate) => {
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.certificates,
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.forEach((media, i) => {
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
- const setupRole = (dtlsTransport: RTCDtlsTransport) => {
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.forEach((t) => {
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
- // # gather candidates
672
- const connected = this.iceTransports.find(
673
- (transport) => transport.state === "connected",
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 && remoteMedia.dtlsParams) {
958
- iceTransport.setRemoteParams(remoteMedia.iceParams);
959
- dtlsTransport.setRemoteParams(remoteMedia.dtlsParams);
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) return false;
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) return false;
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
- const ensureCert = async (dtlsTransport: RTCDtlsTransport) => {
1319
- if (this.certificates.length === 0) {
1320
- const localCertificate = await dtlsTransport.setupCertificate();
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
- await ensureCert(dtlsTransport);
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.forEach((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.iceGather.gatheringState))
1444
- .length === all.length
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) 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 = iceGatherer.localCandidates;
1606
- media.iceCandidatesComplete = iceGatherer.gatheringState === "complete";
1607
- media.iceParams = iceGatherer.localParameters;
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
 
@@ -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 { Connection } from "../../../ice/src";
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
- readonly certificates: RTCCertificate[],
62
+ public localCertificate?: RTCCertificate,
63
63
  private readonly srtpProfiles: Profile[] = [],
64
64
  ) {
65
- this.localCertificate = this.certificates[0];
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 setupCertificate() {
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: Connection) {
363
+ constructor(private ice: IceConnection) {
364
364
  ice.onData.subscribe((buf) => {
365
365
  if (isDtls(buf)) {
366
- if (this.onData) this.onData(buf);
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: Connection) => new IceTransport(ice);
383
+ const createIceTransport = (ice: IceConnection) => new IceTransport(ice);