werift 0.22.8 → 0.22.9

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/index.mjs CHANGED
@@ -229,6 +229,105 @@ var BitStream = class {
229
229
  }
230
230
  };
231
231
 
232
+ // ../common/src/crc.ts
233
+ var POLY_CRC32 = 3988292384;
234
+ var POLY_CRC32C = 2197175160;
235
+ function isBufferLike(input) {
236
+ return typeof input !== "string";
237
+ }
238
+ function generateCRCTable(polynomial) {
239
+ const table = new Array(256);
240
+ let c = 0;
241
+ for (let n = 0; n < 256; ++n) {
242
+ c = n;
243
+ c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
244
+ c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
245
+ c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
246
+ c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
247
+ c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
248
+ c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
249
+ c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
250
+ c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
251
+ table[n] = c;
252
+ }
253
+ return new Int32Array(table);
254
+ }
255
+ function generateSliceBy16Tables(table0) {
256
+ const table = new Int32Array(4096);
257
+ let c = 0;
258
+ let v = 0;
259
+ let n = 0;
260
+ for (n = 0; n < 256; ++n) table[n] = table0[n];
261
+ for (n = 0; n < 256; ++n) {
262
+ v = table0[n];
263
+ for (c = 256 + n; c < 4096; c += 256) {
264
+ v = table[c] = v >>> 8 ^ table0[v & 255];
265
+ }
266
+ }
267
+ const out = [];
268
+ for (n = 1; n < 16; ++n) {
269
+ out[n - 1] = table.subarray(n * 256, n * 256 + 256);
270
+ }
271
+ return out;
272
+ }
273
+ function crcGenericString(value, seed, table0) {
274
+ let crc = seed ^ -1;
275
+ let i = 0;
276
+ const len = value.length;
277
+ let c = 0;
278
+ let d = 0;
279
+ while (i < len) {
280
+ c = value.charCodeAt(i++);
281
+ if (c < 128) {
282
+ crc = crc >>> 8 ^ table0[(crc ^ c) & 255];
283
+ } else if (c < 2048) {
284
+ crc = crc >>> 8 ^ table0[(crc ^ (192 | c >> 6 & 31)) & 255];
285
+ crc = crc >>> 8 ^ table0[(crc ^ (128 | c & 63)) & 255];
286
+ } else if (c >= 55296 && c < 57344) {
287
+ c = (c & 1023) + 64;
288
+ d = value.charCodeAt(i++) & 1023;
289
+ crc = crc >>> 8 ^ table0[(crc ^ (240 | c >> 8 & 7)) & 255];
290
+ crc = crc >>> 8 ^ table0[(crc ^ (128 | c >> 2 & 63)) & 255];
291
+ crc = crc >>> 8 ^ table0[(crc ^ (128 | d >> 6 & 15 | (c & 3) << 4)) & 255];
292
+ crc = crc >>> 8 ^ table0[(crc ^ (128 | d & 63)) & 255];
293
+ } else {
294
+ crc = crc >>> 8 ^ table0[(crc ^ (224 | c >> 12 & 15)) & 255];
295
+ crc = crc >>> 8 ^ table0[(crc ^ (128 | c >> 6 & 63)) & 255];
296
+ crc = crc >>> 8 ^ table0[(crc ^ (128 | c & 63)) & 255];
297
+ }
298
+ }
299
+ return ~crc >>> 0;
300
+ }
301
+ function crcBuffer(value, seed, table0, tables16) {
302
+ const [t1, t2, t3, t4, t5, t6, t7, t8, t9, ta, tb, tc, td, te, tf] = tables16;
303
+ let crc = seed ^ -1;
304
+ let i = 0;
305
+ let len = value.length - 15;
306
+ while (i < len) {
307
+ crc = tf[value[i++] ^ crc & 255] ^ te[value[i++] ^ crc >>> 8 & 255] ^ td[value[i++] ^ crc >>> 16 & 255] ^ tc[value[i++] ^ crc >>> 24] ^ tb[value[i++]] ^ ta[value[i++]] ^ t9[value[i++]] ^ t8[value[i++]] ^ t7[value[i++]] ^ t6[value[i++]] ^ t5[value[i++]] ^ t4[value[i++]] ^ t3[value[i++]] ^ t2[value[i++]] ^ t1[value[i++]] ^ table0[value[i++]];
308
+ }
309
+ for (len += 15; i < len; ) {
310
+ crc = crc >>> 8 ^ table0[(crc ^ value[i++]) & 255];
311
+ }
312
+ return ~crc >>> 0;
313
+ }
314
+ var table32 = generateCRCTable(POLY_CRC32);
315
+ var tables32By16 = generateSliceBy16Tables(table32);
316
+ var table32c = generateCRCTable(POLY_CRC32C);
317
+ var tables32cBy16 = generateSliceBy16Tables(table32c);
318
+ function crc32(input, seed = 0) {
319
+ if (isBufferLike(input)) {
320
+ return crcBuffer(input, seed, table32, tables32By16);
321
+ }
322
+ return crcGenericString(input, seed, table32);
323
+ }
324
+ function crc32c(input, seed = 0) {
325
+ if (isBufferLike(input)) {
326
+ return crcBuffer(input, seed, table32c, tables32cBy16);
327
+ }
328
+ return crcGenericString(input, seed, table32c);
329
+ }
330
+
232
331
  // ../common/src/number.ts
233
332
  function uint8Add(a, b) {
234
333
  return a + b & 255;
@@ -6320,7 +6419,6 @@ var methods = /* @__PURE__ */ ((methods2) => {
6320
6419
 
6321
6420
  // ../ice/src/stun/message.ts
6322
6421
  import { createHmac as createHmac4 } from "crypto";
6323
- import crc32 from "buffer-crc32";
6324
6422
 
6325
6423
  // ../ice/src/helper.ts
6326
6424
  import { randomBytes as randomBytes5 } from "crypto";
@@ -6330,19 +6428,6 @@ function randomString(length) {
6330
6428
  function randomTransactionId() {
6331
6429
  return randomBytes5(12);
6332
6430
  }
6333
- function bufferXor2(a, b) {
6334
- if (a.length !== b.length) {
6335
- throw new TypeError(
6336
- "[webrtc-stun] You can not XOR buffers which length are different"
6337
- );
6338
- }
6339
- const length = a.length;
6340
- const buffer2 = Buffer.allocUnsafe(length);
6341
- for (let i = 0; i < length; i++) {
6342
- buffer2[i] = a[i] ^ b[i];
6343
- }
6344
- return buffer2;
6345
- }
6346
6431
  var PQueue = class {
6347
6432
  queue = [];
6348
6433
  wait = new Event();
@@ -6676,11 +6761,7 @@ function messageFingerprint(data) {
6676
6761
  data,
6677
6762
  data.length - HEADER_LENGTH + FINGERPRINT_LENGTH
6678
6763
  );
6679
- const crc32Buf = crc32(checkData);
6680
- const xorBuf = Buffer.alloc(4);
6681
- xorBuf.writeInt32BE(FINGERPRINT_XOR, 0);
6682
- const fingerprint2 = bufferXor2(crc32Buf, xorBuf);
6683
- return fingerprint2.readUInt32BE(0);
6764
+ return (crc32(checkData) ^ FINGERPRINT_XOR) >>> 0;
6684
6765
  }
6685
6766
  function messageIntegrity(data, key) {
6686
6767
  const checkData = setBodyLength(
@@ -10173,7 +10254,6 @@ import { createHmac as createHmac5, randomBytes as randomBytes7 } from "crypto";
10173
10254
  import { jspack as jspack5 } from "@shinyoshiaki/jspack";
10174
10255
 
10175
10256
  // ../sctp/src/chunk.ts
10176
- import crc32c from "turbo-crc32/crc32c.js";
10177
10257
  var Chunk = class _Chunk {
10178
10258
  constructor(flags = 0, _body = Buffer.from("")) {
10179
10259
  this.flags = flags;
@@ -10737,6 +10817,8 @@ var SCTP_RTO_INITIAL = 3;
10737
10817
  var SCTP_RTO_MIN = 1;
10738
10818
  var SCTP_RTO_MAX = 60;
10739
10819
  var SCTP_TSN_MODULO = 2 ** 32;
10820
+ var SCTP_SACK_DELAY_MS = 200;
10821
+ var SCTP_HEARTBEAT_INTERVAL = 30;
10740
10822
  var RECONFIG_MAX_STREAMS = 135;
10741
10823
  var SCTP_STATE_COOKIE = 7;
10742
10824
  var SCTP_SUPPORTED_CHUNK_EXT = 32776;
@@ -10768,6 +10850,8 @@ var SCTP = class _SCTP {
10768
10850
  started = false;
10769
10851
  state = "new";
10770
10852
  isServer = true;
10853
+ isStopping = false;
10854
+ isClosed = false;
10771
10855
  hmacKey = randomBytes7(16);
10772
10856
  localPartialReliability = true;
10773
10857
  localPort;
@@ -10779,6 +10863,10 @@ var SCTP = class _SCTP {
10779
10863
  // inbound
10780
10864
  advertisedRwnd = 1024 * 1024;
10781
10865
  // Receiver Window
10866
+ peerAdvertisedRwnd = this.advertisedRwnd;
10867
+ get peerRwnd() {
10868
+ return Math.max(0, this.peerAdvertisedRwnd - this.flightSize);
10869
+ }
10782
10870
  inboundStreams = {};
10783
10871
  _inboundStreamsCount = 0;
10784
10872
  _inboundStreamsMax = MAX_STREAMS;
@@ -10787,6 +10875,9 @@ var SCTP = class _SCTP {
10787
10875
  sackDuplicates = [];
10788
10876
  sackMisOrdered = /* @__PURE__ */ new Set();
10789
10877
  sackNeeded = false;
10878
+ sackPacketCount = 0;
10879
+ sackHasNewDataInPacket = false;
10880
+ sackImmediate = false;
10790
10881
  sackTimeout;
10791
10882
  // # outbound
10792
10883
  cwnd = 3 * USERDATA_MAX_LENGTH;
@@ -10805,6 +10896,8 @@ var SCTP = class _SCTP {
10805
10896
  // acknowledgement
10806
10897
  partialBytesAcked = 0;
10807
10898
  sentQueue = [];
10899
+ transmitting = false;
10900
+ transmitRequested = false;
10808
10901
  // # reconfiguration
10809
10902
  /**初期TSNと同じ値に初期化される単調に増加する数です. これは、新しいre-configuration requestパラメーターを送信するたびに1ずつ増加します */
10810
10903
  reconfigRequestSeq = this.localTsn;
@@ -10830,8 +10923,13 @@ var SCTP = class _SCTP {
10830
10923
  /**Re-configuration Timer */
10831
10924
  timerReconfigHandle;
10832
10925
  timerReconfigFailures = 0;
10926
+ timerHeartbeatHandle;
10927
+ heartbeatInterval = SCTP_HEARTBEAT_INTERVAL;
10833
10928
  // etc
10834
10929
  ssthresh;
10930
+ get isStopped() {
10931
+ return this.isStopping || this.isClosed;
10932
+ }
10835
10933
  get maxChannels() {
10836
10934
  if (this._inboundStreamsCount > 0) {
10837
10935
  return Math.min(this._inboundStreamsCount, this._outboundStreamsCount);
@@ -10850,6 +10948,7 @@ var SCTP = class _SCTP {
10850
10948
  }
10851
10949
  // call from dtls transport
10852
10950
  async handleData(data) {
10951
+ if (this.isStopped) return;
10853
10952
  let expectedTag;
10854
10953
  const [, , verificationTag, chunks] = parsePacket2(data);
10855
10954
  const initChunk = chunks.filter((v) => v.type === InitChunk.type).length;
@@ -10864,17 +10963,41 @@ var SCTP = class _SCTP {
10864
10963
  if (verificationTag !== expectedTag) {
10865
10964
  return;
10866
10965
  }
10966
+ this.sackHasNewDataInPacket = false;
10867
10967
  for (const chunk of chunks) {
10868
10968
  await this.receiveChunk(chunk);
10869
10969
  }
10870
10970
  if (this.sackNeeded) {
10971
+ if (this.sackHasNewDataInPacket) {
10972
+ this.sackPacketCount++;
10973
+ }
10974
+ if (this.sackPacketCount >= 2) {
10975
+ this.sackImmediate = true;
10976
+ }
10977
+ await this.scheduleSack();
10978
+ }
10979
+ }
10980
+ async scheduleSack() {
10981
+ if (this.isStopped) return;
10982
+ if (!this.sackNeeded) return;
10983
+ if (this.sackImmediate) {
10984
+ if (this.sackTimeout) {
10985
+ clearTimeout(this.sackTimeout);
10986
+ this.sackTimeout = void 0;
10987
+ }
10871
10988
  await this.sendSack();
10989
+ return;
10872
10990
  }
10991
+ if (this.sackTimeout) return;
10992
+ this.sackTimeout = setTimeout(() => {
10993
+ this.sackTimeout = void 0;
10994
+ this.sendSack().catch((err5) => {
10995
+ log29("send delayed sack failed", err5.message);
10996
+ });
10997
+ }, SCTP_SACK_DELAY_MS);
10873
10998
  }
10874
10999
  async sendSack() {
10875
- if (this.sackTimeout) return;
10876
- await new Promise((r) => this.sackTimeout = setImmediate(r));
10877
- this.sackTimeout = void 0;
11000
+ if (this.isStopped) return;
10878
11001
  if (!this.sackNeeded) return;
10879
11002
  const gaps = [];
10880
11003
  let gapNext;
@@ -10897,6 +11020,8 @@ var SCTP = class _SCTP {
10897
11020
  });
10898
11021
  this.sackDuplicates = [];
10899
11022
  this.sackNeeded = false;
11023
+ this.sackPacketCount = 0;
11024
+ this.sackImmediate = false;
10900
11025
  }
10901
11026
  async receiveChunk(chunk) {
10902
11027
  switch (chunk.type) {
@@ -10914,6 +11039,7 @@ var SCTP = class _SCTP {
10914
11039
  this.reconfigResponseSeq = tsnMinusOne(init.initialTsn);
10915
11040
  this.remoteVerificationTag = init.initiateTag;
10916
11041
  this.ssthresh = init.advertisedRwnd;
11042
+ this.peerAdvertisedRwnd = init.advertisedRwnd;
10917
11043
  this.getExtensions(init.params);
10918
11044
  this._inboundStreamsCount = Math.min(
10919
11045
  init.outboundStreams,
@@ -10952,6 +11078,7 @@ var SCTP = class _SCTP {
10952
11078
  this.reconfigResponseSeq = tsnMinusOne(initAck.initialTsn);
10953
11079
  this.remoteVerificationTag = initAck.initiateTag;
10954
11080
  this.ssthresh = initAck.advertisedRwnd;
11081
+ this.peerAdvertisedRwnd = initAck.advertisedRwnd;
10955
11082
  this.getExtensions(initAck.params);
10956
11083
  this._inboundStreamsCount = Math.min(
10957
11084
  initAck.outboundStreams,
@@ -11149,7 +11276,18 @@ var SCTP = class _SCTP {
11149
11276
  }
11150
11277
  receiveDataChunk(chunk) {
11151
11278
  this.sackNeeded = true;
11152
- if (this.markReceived(chunk.tsn)) return;
11279
+ if (this.markReceived(chunk.tsn)) {
11280
+ this.sackImmediate = true;
11281
+ return;
11282
+ }
11283
+ this.sackHasNewDataInPacket = true;
11284
+ this.sackImmediate = true;
11285
+ if ((chunk.flags & SCTP_DATA_LAST_FRAG) === 0) {
11286
+ this.sackImmediate = true;
11287
+ }
11288
+ if (this.sackMisOrdered.size > 0) {
11289
+ this.sackImmediate = true;
11290
+ }
11153
11291
  const inboundStream = this.getInboundStream(chunk.streamId);
11154
11292
  inboundStream.addChunk(chunk);
11155
11293
  this.advertisedRwnd -= chunk.userData.length;
@@ -11248,12 +11386,14 @@ var SCTP = class _SCTP {
11248
11386
  } else if (done > 0) {
11249
11387
  this.timer3Restart();
11250
11388
  }
11389
+ this.peerAdvertisedRwnd = chunk.advertisedRwnd;
11251
11390
  this.updateAdvancedPeerAckPoint();
11252
11391
  await this.onSackReceived();
11253
11392
  await this.transmit();
11254
11393
  }
11255
11394
  receiveForwardTsnChunk(chunk) {
11256
11395
  this.sackNeeded = true;
11396
+ this.sackImmediate = true;
11257
11397
  if (uint32Gte(this.lastReceivedTsn, chunk.cumulativeTsn)) {
11258
11398
  return;
11259
11399
  }
@@ -11360,17 +11500,29 @@ var SCTP = class _SCTP {
11360
11500
  if (ordered) {
11361
11501
  this.outboundStreamSeq[streamId] = uint16Add(streamSeqNum, 1);
11362
11502
  }
11363
- if (!this.timer3Handle) {
11364
- await this.transmit();
11365
- } else {
11366
- if (this.outboundQueue.length) {
11367
- await this.flush.asPromise();
11368
- } else {
11369
- await new Promise((r) => setImmediate(r));
11370
- }
11503
+ await this.transmit();
11504
+ while (this.outboundQueue.length) {
11505
+ await this.flush.asPromise();
11371
11506
  }
11372
11507
  };
11373
11508
  async transmit() {
11509
+ if (this.isStopped) return;
11510
+ if (this.transmitting) {
11511
+ this.transmitRequested = true;
11512
+ return;
11513
+ }
11514
+ this.transmitting = true;
11515
+ try {
11516
+ do {
11517
+ this.transmitRequested = false;
11518
+ await this.transmitOnce();
11519
+ } while (this.transmitRequested);
11520
+ } finally {
11521
+ this.transmitting = false;
11522
+ }
11523
+ }
11524
+ async transmitOnce() {
11525
+ if (this.isStopped) return;
11374
11526
  if (this.forwardTsnChunk) {
11375
11527
  await this.sendChunk(this.forwardTsnChunk).catch((err5) => {
11376
11528
  log29("send forwardTsn failed", err5.message);
@@ -11388,7 +11540,7 @@ var SCTP = class _SCTP {
11388
11540
  if (this.fastRecoveryTransmit) {
11389
11541
  this.fastRecoveryTransmit = false;
11390
11542
  } else if (this.flightSize >= cwnd) {
11391
- return;
11543
+ break;
11392
11544
  }
11393
11545
  this.flightSizeIncrease(dataChunk);
11394
11546
  dataChunk.misses = 0;
@@ -11403,9 +11555,13 @@ var SCTP = class _SCTP {
11403
11555
  }
11404
11556
  retransmitEarliest = false;
11405
11557
  }
11406
- while (this.outboundQueue.length > 0) {
11558
+ while (this.outboundQueue.length > 0 && this.flightSize < cwnd && this.peerRwnd > 0) {
11407
11559
  const chunk = this.outboundQueue.shift();
11408
- if (!chunk) return;
11560
+ if (!chunk) break;
11561
+ if (chunk.bookSize > this.peerRwnd && this.flightSize > 0) {
11562
+ this.outboundQueue.unshift(chunk);
11563
+ break;
11564
+ }
11409
11565
  this.sentQueue.push(chunk);
11410
11566
  this.flightSizeIncrease(chunk);
11411
11567
  chunk.sentCount++;
@@ -11417,7 +11573,9 @@ var SCTP = class _SCTP {
11417
11573
  this.timer3Start();
11418
11574
  }
11419
11575
  }
11420
- this.outboundQueue = [];
11576
+ if (!this.outboundQueue.length) {
11577
+ this.outboundQueue = [];
11578
+ }
11421
11579
  this.flush.execute();
11422
11580
  }
11423
11581
  async transmitReconfigRequest() {
@@ -11470,16 +11628,19 @@ var SCTP = class _SCTP {
11470
11628
  this.timer1Handle = setTimeout(this.timer1Expired, this.rto * 1e3);
11471
11629
  }
11472
11630
  timer1Expired = () => {
11631
+ if (this.isStopped) return;
11473
11632
  this.timer1Failures++;
11474
11633
  this.timer1Handle = void 0;
11475
11634
  if (this.timer1Failures > SCTP_MAX_INIT_RETRANS) {
11476
11635
  this.setState(1 /* CLOSED */);
11477
11636
  } else {
11478
11637
  setImmediate(() => {
11638
+ if (this.isStopped) return;
11479
11639
  this.sendChunk(this.timer1Chunk).catch((err5) => {
11480
11640
  log29("send timer1 chunk failed", err5.message);
11481
11641
  });
11482
11642
  });
11643
+ if (this.isStopped) return;
11483
11644
  this.timer1Handle = setTimeout(this.timer1Expired, this.rto * 1e3);
11484
11645
  }
11485
11646
  };
@@ -11498,16 +11659,19 @@ var SCTP = class _SCTP {
11498
11659
  this.timer2Handle = setTimeout(this.timer2Expired, this.rto * 1e3);
11499
11660
  }
11500
11661
  timer2Expired = () => {
11662
+ if (this.isStopped) return;
11501
11663
  this.timer2Failures++;
11502
11664
  this.timer2Handle = void 0;
11503
11665
  if (this.timer2Failures > SCTP_MAX_ASSOCIATION_RETRANS) {
11504
11666
  this.setState(1 /* CLOSED */);
11505
11667
  } else {
11506
11668
  setImmediate(() => {
11669
+ if (this.isStopped) return;
11507
11670
  this.sendChunk(this.timer2Chunk).catch((err5) => {
11508
11671
  log29("send timer2Chunk failed", err5.message);
11509
11672
  });
11510
11673
  });
11674
+ if (this.isStopped) return;
11511
11675
  this.timer2Handle = setTimeout(this.timer2Expired, this.rto * 1e3);
11512
11676
  }
11513
11677
  };
@@ -11520,14 +11684,17 @@ var SCTP = class _SCTP {
11520
11684
  }
11521
11685
  /**t3 is wait for data sack */
11522
11686
  timer3Start() {
11687
+ if (this.isStopped) return;
11523
11688
  if (this.timer3Handle) throw new Error();
11524
11689
  this.timer3Handle = setTimeout(this.timer3Expired, this.rto * 1e3);
11525
11690
  }
11526
11691
  timer3Restart() {
11692
+ if (this.isStopped) return;
11527
11693
  this.timer3Cancel();
11528
- this.timer3Handle = setTimeout(this.timer3Expired, this.rto);
11694
+ this.timer3Handle = setTimeout(this.timer3Expired, this.rto * 1e3);
11529
11695
  }
11530
11696
  timer3Expired = () => {
11697
+ if (this.isStopped) return;
11531
11698
  this.timer3Handle = void 0;
11532
11699
  this.sentQueue.forEach((chunk) => {
11533
11700
  if (!this.maybeAbandon(chunk)) {
@@ -11553,6 +11720,7 @@ var SCTP = class _SCTP {
11553
11720
  }
11554
11721
  /**Re-configuration Timer */
11555
11722
  timerReconfigHandleStart() {
11723
+ if (this.isStopped) return;
11556
11724
  if (this.timerReconfigHandle) return;
11557
11725
  log29("timerReconfigHandleStart", { rto: this.rto });
11558
11726
  this.timerReconfigFailures = 0;
@@ -11562,6 +11730,7 @@ var SCTP = class _SCTP {
11562
11730
  );
11563
11731
  }
11564
11732
  timerReconfigHandleExpired = async () => {
11733
+ if (this.isStopped) return;
11565
11734
  this.timerReconfigFailures++;
11566
11735
  this.rto = Math.ceil(this.rto * 1.5);
11567
11736
  if (this.timerReconfigFailures > SCTP_MAX_ASSOCIATION_RETRANS) {
@@ -11571,6 +11740,7 @@ var SCTP = class _SCTP {
11571
11740
  } else if (this.reconfigRequest) {
11572
11741
  log29("timerReconfigHandleExpired", this.timerReconfigFailures, this.rto);
11573
11742
  await this.sendReconfigParam(this.reconfigRequest);
11743
+ if (this.isStopped) return;
11574
11744
  this.timerReconfigHandle = setTimeout(
11575
11745
  this.timerReconfigHandleExpired,
11576
11746
  this.rto * 1e3
@@ -11585,6 +11755,47 @@ var SCTP = class _SCTP {
11585
11755
  this.timerReconfigFailures = 0;
11586
11756
  }
11587
11757
  }
11758
+ heartbeatStart() {
11759
+ if (this.timerHeartbeatHandle || this.associationState !== 4 /* ESTABLISHED */) {
11760
+ return;
11761
+ }
11762
+ this.timerHeartbeatHandle = setTimeout(
11763
+ this.timerHeartbeatExpired,
11764
+ (this.rto + this.heartbeatInterval) * 1e3
11765
+ );
11766
+ }
11767
+ heartbeatRestart() {
11768
+ this.heartbeatCancel();
11769
+ this.heartbeatStart();
11770
+ }
11771
+ heartbeatCancel() {
11772
+ if (this.timerHeartbeatHandle) {
11773
+ clearTimeout(this.timerHeartbeatHandle);
11774
+ this.timerHeartbeatHandle = void 0;
11775
+ }
11776
+ }
11777
+ timerHeartbeatExpired = async () => {
11778
+ this.timerHeartbeatHandle = void 0;
11779
+ if (this.associationState !== 4 /* ESTABLISHED */) return;
11780
+ if (this.flightSize === 0 && this.outboundQueue.length === 0) {
11781
+ const heartbeat = new HeartbeatChunk();
11782
+ heartbeat.params.push([
11783
+ 1,
11784
+ Buffer.from(jspack5.Pack("!L", [Math.floor(Date.now() / 1e3)]))
11785
+ ]);
11786
+ await this.sendChunk(heartbeat).catch((err5) => {
11787
+ log29("send heartbeat failed", err5.message);
11788
+ });
11789
+ }
11790
+ this.heartbeatStart();
11791
+ };
11792
+ setHeartbeatInterval(interval) {
11793
+ if (interval <= 0) {
11794
+ throw new Error("heartbeat interval must be > 0");
11795
+ }
11796
+ this.heartbeatInterval = interval;
11797
+ this.heartbeatRestart();
11798
+ }
11588
11799
  updateAdvancedPeerAckPoint() {
11589
11800
  if (uint32Gt(this.lastSackedTsn, this.advancedPeerAckTsn)) {
11590
11801
  this.advancedPeerAckTsn = this.lastSackedTsn;
@@ -11696,12 +11907,21 @@ var SCTP = class _SCTP {
11696
11907
  this.associationState = state;
11697
11908
  }
11698
11909
  if (state === 4 /* ESTABLISHED */) {
11910
+ this.isStopping = false;
11911
+ this.isClosed = false;
11699
11912
  this.setConnectionState("connected");
11913
+ this.heartbeatStart();
11700
11914
  } else if (state === 1 /* CLOSED */) {
11915
+ this.isClosed = true;
11701
11916
  this.timer1Cancel();
11702
11917
  this.timer2Cancel();
11703
11918
  this.timer3Cancel();
11704
11919
  this.timerReconfigCancel();
11920
+ this.heartbeatCancel();
11921
+ if (this.sackTimeout) {
11922
+ clearTimeout(this.sackTimeout);
11923
+ this.sackTimeout = void 0;
11924
+ }
11705
11925
  this.setConnectionState("closed");
11706
11926
  this.removeAllListeners();
11707
11927
  }
@@ -11712,6 +11932,16 @@ var SCTP = class _SCTP {
11712
11932
  this.stateChanged[state].execute();
11713
11933
  }
11714
11934
  async stop() {
11935
+ if (this.isStopped) {
11936
+ this.setState(1 /* CLOSED */);
11937
+ return;
11938
+ }
11939
+ this.isStopping = true;
11940
+ this.transport.onData = void 0;
11941
+ if (this.sackTimeout) {
11942
+ clearTimeout(this.sackTimeout);
11943
+ this.sackTimeout = void 0;
11944
+ }
11715
11945
  if (this.associationState !== 1 /* CLOSED */) {
11716
11946
  await this.abort();
11717
11947
  }
@@ -11720,6 +11950,8 @@ var SCTP = class _SCTP {
11720
11950
  clearTimeout(this.timer2Handle);
11721
11951
  clearTimeout(this.timer3Handle);
11722
11952
  clearTimeout(this.timerReconfigHandle);
11953
+ clearTimeout(this.timerHeartbeatHandle);
11954
+ clearTimeout(this.sackTimeout);
11723
11955
  }
11724
11956
  async abort() {
11725
11957
  const abort = new AbortChunk();
@@ -12045,7 +12277,6 @@ var RTCSctpTransport = class {
12045
12277
  }
12046
12278
  async dataChannelFlush() {
12047
12279
  if (this.sctp.associationState != 4 /* ESTABLISHED */) return;
12048
- if (this.sctp.outboundQueue.length > 0) return;
12049
12280
  while (this.dataChannelQueue.length > 0) {
12050
12281
  const [channel, protocol, userData] = this.dataChannelQueue.shift();
12051
12282
  let streamId = channel.id;
@@ -15680,6 +15911,8 @@ export {
15680
15911
  codecParametersFromString,
15681
15912
  codecParametersToString,
15682
15913
  compactNtp,
15914
+ crc32,
15915
+ crc32c,
15683
15916
  createBufferWriter,
15684
15917
  createSelfSignedCertificate,
15685
15918
  createStunOverTurnClient,