mediasoup 3.20.8 → 3.20.10

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 (145) hide show
  1. package/README.md +14 -2
  2. package/node/lib/WebRtcServer.d.ts.map +1 -1
  3. package/node/lib/WebRtcServer.js +0 -7
  4. package/node/lib/WebRtcServerTypes.d.ts +0 -5
  5. package/node/lib/WebRtcServerTypes.d.ts.map +1 -1
  6. package/node/lib/Worker.d.ts +1 -1
  7. package/node/lib/Worker.d.ts.map +1 -1
  8. package/node/lib/Worker.js +1 -11
  9. package/node/lib/WorkerTypes.d.ts +0 -9
  10. package/node/lib/WorkerTypes.d.ts.map +1 -1
  11. package/node/lib/fbs/plain-transport/connect-response.d.ts.map +1 -1
  12. package/node/lib/fbs/plain-transport/connect-response.js +0 -1
  13. package/node/lib/fbs/web-rtc-server/dump-response.d.ts +2 -9
  14. package/node/lib/fbs/web-rtc-server/dump-response.d.ts.map +1 -1
  15. package/node/lib/fbs/web-rtc-server/dump-response.js +5 -33
  16. package/node/lib/fbs/web-rtc-server.d.ts +0 -1
  17. package/node/lib/fbs/web-rtc-server.d.ts.map +1 -1
  18. package/node/lib/fbs/web-rtc-server.js +1 -4
  19. package/node/lib/fbs/worker/dump-response.d.ts +1 -5
  20. package/node/lib/fbs/worker/dump-response.d.ts.map +1 -1
  21. package/node/lib/fbs/worker/dump-response.js +3 -16
  22. package/node/lib/index.d.ts +1 -1
  23. package/node/lib/index.d.ts.map +1 -1
  24. package/node/lib/index.js +1 -2
  25. package/node/lib/test/test-PlainTransport.js +30 -0
  26. package/node/lib/test/test-WebRtcServer.js +0 -7
  27. package/node/lib/test/test-Worker.js +0 -1
  28. package/npm-scripts.mjs +177 -60
  29. package/package.json +10 -8
  30. package/worker/fbs/webRtcServer.fbs +0 -6
  31. package/worker/include/RTC/ICE/StunPacket.hpp +21 -2
  32. package/worker/include/RTC/NackGenerator.hpp +2 -2
  33. package/worker/include/RTC/RTP/RtpStreamRecv.hpp +2 -2
  34. package/worker/include/RTC/TransportTuple.hpp +70 -14
  35. package/worker/include/RTC/WebRtcServer.hpp +5 -2
  36. package/worker/include/Utils.hpp +6 -0
  37. package/worker/src/RTC/ICE/IceServer.cpp +2 -1
  38. package/worker/src/RTC/ICE/StunPacket.cpp +8 -0
  39. package/worker/src/RTC/NackGenerator.cpp +1 -1
  40. package/worker/src/RTC/PortManager.cpp +16 -20
  41. package/worker/src/RTC/Producer.cpp +1 -1
  42. package/worker/src/RTC/SeqManager.cpp +5 -4
  43. package/worker/src/RTC/TransportTuple.cpp +87 -50
  44. package/worker/src/RTC/WebRtcServer.cpp +20 -29
  45. package/worker/test/src/RTC/ICE/TestStunPacket.cpp +6 -2
  46. package/worker/test/src/RTC/RTP/TestRtpStreamRecv.cpp +1 -1
  47. package/worker/test/src/RTC/TestNackGenerator.cpp +1 -1
  48. package/worker/test/src/RTC/TestSeqManager.cpp +167 -62
  49. package/worker/test/src/RTC/TestTransportTuple.cpp +21 -14
  50. package/node/lib/fbs/data-consumer/binary.d.ts +0 -25
  51. package/node/lib/fbs/data-consumer/binary.d.ts.map +0 -1
  52. package/node/lib/fbs/data-consumer/binary.js +0 -110
  53. package/node/lib/fbs/data-consumer/data.d.ts +0 -10
  54. package/node/lib/fbs/data-consumer/data.d.ts.map +0 -1
  55. package/node/lib/fbs/data-consumer/data.js +0 -30
  56. package/node/lib/fbs/data-consumer/string.d.ts +0 -22
  57. package/node/lib/fbs/data-consumer/string.d.ts.map +0 -1
  58. package/node/lib/fbs/data-consumer/string.js +0 -92
  59. package/node/lib/fbs/data-producer/binary.d.ts +0 -25
  60. package/node/lib/fbs/data-producer/binary.d.ts.map +0 -1
  61. package/node/lib/fbs/data-producer/binary.js +0 -110
  62. package/node/lib/fbs/data-producer/data.d.ts +0 -10
  63. package/node/lib/fbs/data-producer/data.d.ts.map +0 -1
  64. package/node/lib/fbs/data-producer/data.js +0 -30
  65. package/node/lib/fbs/data-producer/string.d.ts +0 -22
  66. package/node/lib/fbs/data-producer/string.d.ts.map +0 -1
  67. package/node/lib/fbs/data-producer/string.js +0 -92
  68. package/node/lib/fbs/lib-uring/dump.d.ts +0 -27
  69. package/node/lib/fbs/lib-uring/dump.d.ts.map +0 -1
  70. package/node/lib/fbs/lib-uring/dump.js +0 -113
  71. package/node/lib/fbs/lib-uring.d.ts +0 -2
  72. package/node/lib/fbs/lib-uring.d.ts.map +0 -1
  73. package/node/lib/fbs/lib-uring.js +0 -8
  74. package/node/lib/fbs/message/type.d.ts +0 -7
  75. package/node/lib/fbs/message/type.d.ts.map +0 -1
  76. package/node/lib/fbs/message/type.js +0 -11
  77. package/node/lib/fbs/message-from-worker/body.d.ts +0 -12
  78. package/node/lib/fbs/message-from-worker/body.d.ts.map +0 -1
  79. package/node/lib/fbs/message-from-worker/body.js +0 -34
  80. package/node/lib/fbs/message-from-worker/message.d.ts +0 -30
  81. package/node/lib/fbs/message-from-worker/message.d.ts.map +0 -1
  82. package/node/lib/fbs/message-from-worker/message.js +0 -122
  83. package/node/lib/fbs/message-from-worker.d.ts +0 -3
  84. package/node/lib/fbs/message-from-worker.d.ts.map +0 -1
  85. package/node/lib/fbs/message-from-worker.js +0 -9
  86. package/node/lib/fbs/message-to-worker/body.d.ts +0 -10
  87. package/node/lib/fbs/message-to-worker/body.d.ts.map +0 -1
  88. package/node/lib/fbs/message-to-worker/body.js +0 -30
  89. package/node/lib/fbs/message-to-worker/message.d.ts +0 -29
  90. package/node/lib/fbs/message-to-worker/message.d.ts.map +0 -1
  91. package/node/lib/fbs/message-to-worker/message.js +0 -122
  92. package/node/lib/fbs/message-to-worker.d.ts +0 -3
  93. package/node/lib/fbs/message-to-worker.d.ts.map +0 -1
  94. package/node/lib/fbs/message-to-worker.js +0 -9
  95. package/node/lib/fbs/notification-from-worker/body.d.ts +0 -44
  96. package/node/lib/fbs/notification-from-worker/body.d.ts.map +0 -1
  97. package/node/lib/fbs/notification-from-worker/body.js +0 -98
  98. package/node/lib/fbs/notification-from-worker/event.d.ts +0 -31
  99. package/node/lib/fbs/notification-from-worker/event.d.ts.map +0 -1
  100. package/node/lib/fbs/notification-from-worker/event.js +0 -35
  101. package/node/lib/fbs/notification-from-worker/notification.d.ts +0 -52
  102. package/node/lib/fbs/notification-from-worker/notification.d.ts.map +0 -1
  103. package/node/lib/fbs/notification-from-worker/notification.js +0 -140
  104. package/node/lib/fbs/notification-from-worker.d.ts +0 -4
  105. package/node/lib/fbs/notification-from-worker.d.ts.map +0 -1
  106. package/node/lib/fbs/notification-from-worker.js +0 -11
  107. package/node/lib/fbs/notification-to-worker/body.d.ts +0 -12
  108. package/node/lib/fbs/notification-to-worker/body.d.ts.map +0 -1
  109. package/node/lib/fbs/notification-to-worker/body.js +0 -34
  110. package/node/lib/fbs/notification-to-worker/event.d.ts +0 -6
  111. package/node/lib/fbs/notification-to-worker/event.d.ts.map +0 -1
  112. package/node/lib/fbs/notification-to-worker/event.js +0 -10
  113. package/node/lib/fbs/notification-to-worker/notification.d.ts +0 -36
  114. package/node/lib/fbs/notification-to-worker/notification.d.ts.map +0 -1
  115. package/node/lib/fbs/notification-to-worker/notification.js +0 -140
  116. package/node/lib/fbs/notification-to-worker.d.ts +0 -4
  117. package/node/lib/fbs/notification-to-worker.d.ts.map +0 -1
  118. package/node/lib/fbs/notification-to-worker.js +0 -11
  119. package/node/lib/fbs/sctp-parameters/num-sctp-streams.d.ts +0 -24
  120. package/node/lib/fbs/sctp-parameters/num-sctp-streams.d.ts.map +0 -1
  121. package/node/lib/fbs/sctp-parameters/num-sctp-streams.js +0 -102
  122. package/node/lib/fbs/trace-events/fir-trace-info.d.ts +0 -21
  123. package/node/lib/fbs/trace-events/fir-trace-info.d.ts.map +0 -1
  124. package/node/lib/fbs/trace-events/fir-trace-info.js +0 -90
  125. package/node/lib/fbs/trace-events/key-frame-trace-info.d.ts +0 -25
  126. package/node/lib/fbs/trace-events/key-frame-trace-info.d.ts.map +0 -1
  127. package/node/lib/fbs/trace-events/key-frame-trace-info.js +0 -104
  128. package/node/lib/fbs/trace-events/pli-trace-info.d.ts +0 -21
  129. package/node/lib/fbs/trace-events/pli-trace-info.d.ts.map +0 -1
  130. package/node/lib/fbs/trace-events/pli-trace-info.js +0 -90
  131. package/node/lib/fbs/trace-events/rtp-trace-info.d.ts +0 -25
  132. package/node/lib/fbs/trace-events/rtp-trace-info.d.ts.map +0 -1
  133. package/node/lib/fbs/trace-events/rtp-trace-info.js +0 -104
  134. package/node/lib/fbs/trace-events/trace-event-type.d.ts +0 -8
  135. package/node/lib/fbs/trace-events/trace-event-type.d.ts.map +0 -1
  136. package/node/lib/fbs/trace-events/trace-event-type.js +0 -12
  137. package/node/lib/fbs/trace-events/trace-info.d.ts +0 -14
  138. package/node/lib/fbs/trace-events/trace-info.d.ts.map +0 -1
  139. package/node/lib/fbs/trace-events/trace-info.js +0 -38
  140. package/node/lib/fbs/trace-events.d.ts +0 -7
  141. package/node/lib/fbs/trace-events.d.ts.map +0 -1
  142. package/node/lib/fbs/trace-events.js +0 -20
  143. package/node/lib/fbs/web-rtc-server/tuple-hash.d.ts +0 -25
  144. package/node/lib/fbs/web-rtc-server/tuple-hash.d.ts.map +0 -1
  145. package/node/lib/fbs/web-rtc-server/tuple-hash.js +0 -104
@@ -96,7 +96,6 @@ test('worker.createWebRtcServer() succeeds', async () => {
96
96
  tcpServers: [{ ip: '127.0.0.1', port: port2 }],
97
97
  webRtcTransportIds: [],
98
98
  localIceUsernameFragments: [],
99
- tupleHashes: [],
100
99
  });
101
100
  // API not exposed in the interface.
102
101
  expect(ctx.worker.webRtcServersForTesting.size).toBe(1);
@@ -154,7 +153,6 @@ test('worker.createWebRtcServer() with portRange succeeds', async () => {
154
153
  tcpServers: [{ ip: '127.0.0.1', port: port2 }],
155
154
  webRtcTransportIds: [],
156
155
  localIceUsernameFragments: [],
157
- tupleHashes: [],
158
156
  });
159
157
  // API not exposed in the interface.
160
158
  expect(ctx.worker.webRtcServersForTesting.size).toBe(1);
@@ -200,7 +198,6 @@ test('worker.createWebRtcServer() without specifying port/portRange succeeds', a
200
198
  tcpServers: [{ ip: '127.0.0.1', port: expect.any(Number) }],
201
199
  webRtcTransportIds: [],
202
200
  localIceUsernameFragments: [],
203
- tupleHashes: [],
204
201
  });
205
202
  // API not exposed in the interface.
206
203
  expect(ctx.worker.webRtcServersForTesting.size).toBe(1);
@@ -403,7 +400,6 @@ test('router.createWebRtcTransport() with webRtcServer succeeds and transport is
403
400
  localIceUsernameFragments: [
404
401
  { /* localIceUsernameFragment: xxx, */ webRtcTransportId: transport.id },
405
402
  ],
406
- tupleHashes: [],
407
403
  });
408
404
  transport.close();
409
405
  expect(transport.closed).toBe(true);
@@ -419,7 +415,6 @@ test('router.createWebRtcTransport() with webRtcServer succeeds and transport is
419
415
  tcpServers: [{ ip: '127.0.0.1', port: port2 }],
420
416
  webRtcTransportIds: [],
421
417
  localIceUsernameFragments: [],
422
- tupleHashes: [],
423
418
  });
424
419
  }, 2000);
425
420
  test('router.createWebRtcTransport() with webRtcServer succeeds and webRtcServer is closed', async () => {
@@ -482,7 +477,6 @@ test('router.createWebRtcTransport() with webRtcServer succeeds and webRtcServer
482
477
  localIceUsernameFragments: [
483
478
  { /* localIceUsernameFragment: xxx, */ webRtcTransportId: transport.id },
484
479
  ],
485
- tupleHashes: [],
486
480
  });
487
481
  // Let's restart ICE in the transport so it should add a new entry in
488
482
  // localIceUsernameFragments in the WebRtcServer.
@@ -496,7 +490,6 @@ test('router.createWebRtcTransport() with webRtcServer succeeds and webRtcServer
496
490
  { /* localIceUsernameFragment: xxx, */ webRtcTransportId: transport.id },
497
491
  { /* localIceUsernameFragment: yyy, */ webRtcTransportId: transport.id },
498
492
  ],
499
- tupleHashes: [],
500
493
  });
501
494
  const onObserverClose = jest.fn();
502
495
  webRtcServer.observer.once('close', onObserverClose);
@@ -71,7 +71,6 @@ test('mediasoup.createWorker() succeeds', async () => {
71
71
  dtlsCertificateFile: path.join(__dirname, 'data', 'dtls-cert.pem'),
72
72
  dtlsPrivateKeyFile: path.join(__dirname, 'data', 'dtls-key.pem'),
73
73
  libwebrtcFieldTrials: 'WebRTC-Bwe-AlrLimitedBackoff/Disabled/',
74
- disableLiburing: true,
75
74
  appData: { foo: 456 },
76
75
  });
77
76
  expect(worker2.constructor.name).toBe('WorkerImpl');
package/npm-scripts.mjs CHANGED
@@ -8,7 +8,9 @@ import * as tar from 'tar';
8
8
  import pkg from './package.json' with { type: 'json' };
9
9
 
10
10
  const IS_WINDOWS = os.platform() === 'win32';
11
- const MAYOR_VERSION = pkg.version.split('.')[0];
11
+ // Main Git branch is 'v' concatenated with the major SEMVER number of the
12
+ // "version" field in package.json.
13
+ const MAIN_BRANCH = `v${pkg.version.split('.')[0]}`;
12
14
  const PYTHON = getPython();
13
15
  const PIP_INVOKE_DIR = path.resolve('worker/pip_invoke');
14
16
  const WORKER_RELEASE_DIR = 'worker/out/Release';
@@ -17,8 +19,6 @@ const WORKER_RELEASE_BIN = IS_WINDOWS
17
19
  : 'mediasoup-worker';
18
20
  const WORKER_RELEASE_BIN_PATH = `${WORKER_RELEASE_DIR}/${WORKER_RELEASE_BIN}`;
19
21
  const WORKER_PREBUILD_DIR = 'worker/prebuild';
20
- const GH_OWNER = 'versatica';
21
- const GH_REPO = 'mediasoup';
22
22
 
23
23
  // Paths for ESLint to check.
24
24
  const ESLINT_PATHS = [
@@ -27,6 +27,7 @@ const ESLINT_PATHS = [
27
27
  'knip.config.mjs',
28
28
  'node/src',
29
29
  'npm-scripts.mjs',
30
+ 'rust-scripts.mjs',
30
31
  'worker/scripts',
31
32
  ];
32
33
 
@@ -47,6 +48,7 @@ const PRETTIER_PATHS = [
47
48
  'node/src',
48
49
  'npm-scripts.mjs',
49
50
  'package.json',
51
+ 'rust-scripts.mjs',
50
52
  'tsconfig.json',
51
53
  'worker/scripts',
52
54
  ];
@@ -136,14 +138,20 @@ async function run() {
136
138
  break;
137
139
  }
138
140
 
141
+ case 'prepublishOnly': {
142
+ prepublishOnly();
143
+
144
+ break;
145
+ }
146
+
139
147
  case 'typescript:build': {
140
- buildTypescript({ force: true });
148
+ buildTypescript({ force: true, args: taskArgs });
141
149
 
142
150
  break;
143
151
  }
144
152
 
145
153
  case 'typescript:watch': {
146
- watchTypescript();
154
+ watchTypescript({ args: taskArgs });
147
155
 
148
156
  break;
149
157
  }
@@ -215,7 +223,7 @@ async function run() {
215
223
  }
216
224
 
217
225
  case 'test:node': {
218
- testNode();
226
+ testNode({ args: taskArgs });
219
227
 
220
228
  break;
221
229
  }
@@ -227,7 +235,7 @@ async function run() {
227
235
  }
228
236
 
229
237
  case 'coverage:node': {
230
- coverageNode();
238
+ coverageNode({ args: taskArgs });
231
239
 
232
240
  break;
233
241
  }
@@ -245,7 +253,7 @@ async function run() {
245
253
  }
246
254
 
247
255
  case 'release': {
248
- await release();
256
+ await release({ args: taskArgs });
249
257
 
250
258
  break;
251
259
  }
@@ -317,7 +325,7 @@ function deleteNodeLib() {
317
325
  fs.rmSync('node/lib', { recursive: true, force: true });
318
326
  }
319
327
 
320
- function buildTypescript({ force }) {
328
+ function buildTypescript({ force, args = '' }) {
321
329
  // Skip JavaScript code generation if the output already exists, unless forced.
322
330
  if (!force && fs.existsSync('node/lib')) {
323
331
  return;
@@ -327,15 +335,15 @@ function buildTypescript({ force }) {
327
335
 
328
336
  deleteNodeLib();
329
337
 
330
- executeCmd(`tsc ${taskArgs}`);
338
+ executeCmd(`tsc ${args}`);
331
339
  }
332
340
 
333
- function watchTypescript() {
341
+ function watchTypescript({ args = '' } = {}) {
334
342
  logInfo('watchTypescript()');
335
343
 
336
344
  deleteNodeLib();
337
345
 
338
- executeCmd(`tsc --watch ${taskArgs}`);
346
+ executeCmd(`tsc --watch ${args}`);
339
347
  }
340
348
 
341
349
  function buildWorker() {
@@ -487,10 +495,10 @@ function flatcWorker() {
487
495
  executeCmd(`"${PYTHON}" -m invoke -r worker flatc`);
488
496
  }
489
497
 
490
- function testNode() {
498
+ function testNode({ args = '' } = {}) {
491
499
  logInfo('testNode()');
492
500
 
493
- executeCmd(`jest --silent false --detectOpenHandles ${taskArgs}`);
501
+ executeCmd(`jest --silent false --detectOpenHandles ${args}`);
494
502
  }
495
503
 
496
504
  function testWorker() {
@@ -501,10 +509,10 @@ function testWorker() {
501
509
  executeCmd(`"${PYTHON}" -m invoke -r worker test`);
502
510
  }
503
511
 
504
- function coverageNode() {
512
+ function coverageNode({ args = '' } = {}) {
505
513
  logInfo('coverageNode()');
506
514
 
507
- executeCmd(`jest --coverage ${taskArgs}`);
515
+ executeCmd(`jest --coverage ${args}`);
508
516
  executeCmd('open-cli coverage/lcov-report/index.html');
509
517
  }
510
518
 
@@ -522,6 +530,26 @@ function installNodeDeps() {
522
530
  executeCmd('npm audit --prefix worker/scripts');
523
531
  }
524
532
 
533
+ /**
534
+ * `prepublishOnly` is run by NPM only on `npm publish` (not on `npm pack`,
535
+ * `npm install` or `npm ci`). We use it to forbid publishing mediasoup from a
536
+ * local machine. The package must only be published by the
537
+ * `mediasoup-npm-publish.yaml` workflow, which runs inside GitHub Actions (where
538
+ * GITHUB_ACTIONS environment variable is set to 'true') and uses OIDC trusted
539
+ * publishing.
540
+ */
541
+ function prepublishOnly() {
542
+ logInfo('prepublishOnly()');
543
+
544
+ if (process.env.GITHUB_ACTIONS !== 'true') {
545
+ logError(
546
+ "prepublishOnly() | refusing to 'npm publish' outside of GitHub Actions: mediasoup is published only by the mediasoup-npm-publish.yaml workflow (triggered by pushing a release tag via 'npm run release')"
547
+ );
548
+
549
+ exitWithError();
550
+ }
551
+ }
552
+
525
553
  function publishDryRun() {
526
554
  logInfo('publishDryRun()');
527
555
 
@@ -542,6 +570,18 @@ function publishDryRun() {
542
570
  async function checkRelease() {
543
571
  logInfo('checkRelease()');
544
572
 
573
+ // Verify that CHANGELOG.md has an entry for the new version (and grab its
574
+ // changes, used as the GitHub release body) before the slow build steps.
575
+ let versionChanges;
576
+
577
+ try {
578
+ versionChanges = await getVersionChanges();
579
+ } catch (error) {
580
+ logError(`checkRelease() | ${error.message}`);
581
+
582
+ exitWithError();
583
+ }
584
+
545
585
  installNodeDeps();
546
586
  await flatcNode({ force: true });
547
587
  buildTypescript({ force: true });
@@ -553,41 +593,64 @@ async function checkRelease() {
553
593
  // Validate packaging (the `files` list in package.json) before the
554
594
  // irreversible release steps (git push, GitHub release, npm publish).
555
595
  publishDryRun();
596
+
597
+ return { versionChanges };
556
598
  }
557
599
 
558
- async function release() {
600
+ async function release({ args = '' } = {}) {
559
601
  logInfo('release()');
560
602
 
561
- let octokit;
562
- let versionChanges;
603
+ const version = args.trim();
563
604
 
564
- try {
565
- octokit = await getOctokit();
566
- versionChanges = await getVersionChanges();
567
- } catch (error) {
568
- logError(error.message);
605
+ if (!/^\d+\.\d+\.\d+$/.test(version)) {
606
+ logError(
607
+ `release() | a SEMVER 'x.y.z' argument is required, but got '${version}'`
608
+ );
609
+
610
+ exitWithError();
611
+ }
612
+
613
+ // Must be on the main branch.
614
+ const branch = execSync('git rev-parse --abbrev-ref HEAD', {
615
+ encoding: 'utf-8',
616
+ }).trim();
617
+
618
+ if (branch !== MAIN_BRANCH) {
619
+ logError(
620
+ `release() | must be on '${MAIN_BRANCH}' branch, but it is on '${branch}' branch`
621
+ );
569
622
 
570
623
  exitWithError();
571
624
  }
572
625
 
626
+ // Clean working tree required before bumping the version.
627
+ checkGitClean();
628
+
629
+ // Lint, test, build, publish dry-run, and verify the CHANGELOG entry (of the
630
+ // previous version still in package.json, which is harmless).
573
631
  await checkRelease();
574
- executeCmd(`git commit -am '${pkg.version}'`);
575
- executeCmd(`git tag -a ${pkg.version} -m '${pkg.version}'`);
576
- executeCmd(`git push origin v${MAYOR_VERSION}`);
577
- executeCmd(`git push origin '${pkg.version}'`);
578
-
579
- logInfo('creating release in GitHub');
580
-
581
- await octokit.repos.createRelease({
582
- owner: GH_OWNER,
583
- repo: GH_REPO,
584
- name: pkg.version,
585
- body: versionChanges,
586
- tag_name: pkg.version,
587
- draft: false,
588
- });
589
632
 
590
- executeInteractiveCmd('npm publish');
633
+ // Bump the version in package.json + package-lock.json and in CHANGELOG.md.
634
+ executeCmd(`npm version ${version} --no-git-tag-version`);
635
+ await updateChangelog(version);
636
+
637
+ // Commit the bump, tag it, and push both. The pushed tag triggers
638
+ // `mediasoup-npm-publish.yaml`, which checks, creates the GitHub release and
639
+ // publishes to NPM; on its success `mediasoup-worker-prebuild.yaml` builds
640
+ // and uploads the prebuilt binaries.
641
+ //
642
+ // The commit message carries a "[no-ci]" marker so the regular branch CI
643
+ // workflows (node, worker, rust, fuzzer, codeql) skip this commit: it only
644
+ // bumps version/CHANGELOG (no code change) and its parent already passed CI,
645
+ // and the release is driven by the tag-triggered workflows instead.
646
+ //
647
+ // NOTE: "[no-ci]" (with a hyphen) is a custom marker, NOT GitHub's native
648
+ // "[skip ci]"/"[no ci]" (which would also skip mediasoup-npm-publish, since
649
+ // the tag push shares this same commit).
650
+ executeCmd(`git commit -am 'release ${version} [no-ci]'`);
651
+ executeCmd(`git tag -a ${version} -m '${version}'`);
652
+ executeCmd(`git push origin ${MAIN_BRANCH}`);
653
+ executeCmd(`git push origin '${version}'`);
591
654
  }
592
655
 
593
656
  function ensureDir(dir) {
@@ -636,8 +699,10 @@ async function prebuildWorker() {
636
699
  }
637
700
  }
638
701
 
639
- // Returns a Promise resolving to true if a mediasoup-worker prebuilt binary
640
- // was downloaded and uncompressed, false otherwise.
702
+ /**
703
+ * Returns a Promise resolving to true if a mediasoup-worker prebuilt binary was
704
+ * downloaded and uncompressed, false otherwise.
705
+ */
641
706
  async function downloadPrebuiltWorker() {
642
707
  const releaseBase =
643
708
  process.env.MEDIASOUP_WORKER_PREBUILT_DOWNLOAD_BASE_URL ||
@@ -757,19 +822,21 @@ async function downloadPrebuiltWorker() {
757
822
  });
758
823
  }
759
824
 
760
- async function getOctokit() {
761
- if (!process.env.GITHUB_TOKEN) {
762
- throw new Error('missing GITHUB_TOKEN environment variable');
763
- }
764
-
765
- // NOTE: Load dep on demand since it's a devDependency.
766
- const { Octokit } = await import('@octokit/rest');
825
+ function checkGitClean() {
826
+ logInfo('checkGitClean()');
767
827
 
768
- const octokit = new Octokit({
769
- auth: process.env.GITHUB_TOKEN,
828
+ const status = execSync('git status --porcelain', {
829
+ encoding: 'utf-8',
830
+ stdio: ['ignore', 'pipe', 'ignore'],
770
831
  });
771
832
 
772
- return octokit;
833
+ if (status.trim()) {
834
+ logError(
835
+ 'checkGitClean() | Git working tree is not clean, commit or stash your changes first'
836
+ );
837
+
838
+ exitWithError();
839
+ }
773
840
  }
774
841
 
775
842
  async function getVersionChanges() {
@@ -785,9 +852,26 @@ async function getVersionChanges() {
785
852
  const entry = entries[idx];
786
853
 
787
854
  if (entry.type === 'heading' && entry.text === pkg.version) {
788
- const changes = entries[idx + 1].raw;
855
+ // Collect every token after the matching heading until the next heading.
856
+ // NOTE: We cannot just use `entries[idx + 1].raw` because `marked`
857
+ // inserts a `space` token between the heading and its content.
858
+ let changes = '';
859
+
860
+ for (let next = idx + 1; next < entries.length; ++next) {
861
+ if (entries[next].type === 'heading') {
862
+ break;
863
+ }
789
864
 
790
- return changes;
865
+ changes += entries[next].raw;
866
+ }
867
+
868
+ changes = changes.trim();
869
+
870
+ if (changes) {
871
+ return changes;
872
+ }
873
+
874
+ break;
791
875
  }
792
876
  }
793
877
 
@@ -797,11 +881,43 @@ async function getVersionChanges() {
797
881
  );
798
882
  }
799
883
 
800
- function executeCmd(command) {
801
- logInfo(`executeCmd(): ${command}`);
884
+ async function updateChangelog(version) {
885
+ logInfo(`updateChangelog() [version:${version}]`);
886
+
887
+ // NOTE: Load dep on demand since it's a devDependency.
888
+ const marked = await import('marked');
889
+
890
+ const changelog = fs.readFileSync('./CHANGELOG.md', { encoding: 'utf-8' });
891
+ const tokens = marked.lexer(changelog);
892
+
893
+ // Locate the top "### NEXT" heading.
894
+ const nextHeading = tokens.find(
895
+ token =>
896
+ token.type === 'heading' && token.depth === 3 && token.text === 'NEXT'
897
+ );
898
+
899
+ if (!nextHeading) {
900
+ throw new Error("no '### NEXT' heading found in CHANGELOG.md");
901
+ }
902
+
903
+ // Insert "### <version>" right below "### NEXT" (keeping the empty "### NEXT"
904
+ // for future unreleased changes), preserving the heading's trailing newlines.
905
+ const updatedChangelog = changelog.replace(
906
+ nextHeading.raw,
907
+ `### NEXT\n\n### ${version}${nextHeading.raw.slice('### NEXT'.length)}`
908
+ );
909
+
910
+ fs.writeFileSync('./CHANGELOG.md', updatedChangelog);
911
+ }
912
+
913
+ function executeCmd(command, { cwd } = {}) {
914
+ logInfo(`executeCmd(): ${command}${cwd ? ` [cwd:${cwd}]` : ''}`);
802
915
 
803
916
  try {
804
- execSync(command, { stdio: ['ignore', process.stdout, process.stderr] });
917
+ execSync(command, {
918
+ cwd,
919
+ stdio: ['ignore', process.stdout, process.stderr],
920
+ });
805
921
  } catch (error) {
806
922
  logError(`executeCmd() failed, exiting: ${error}`);
807
923
 
@@ -809,11 +925,12 @@ function executeCmd(command) {
809
925
  }
810
926
  }
811
927
 
812
- function executeInteractiveCmd(command) {
813
- logInfo(`executeInteractiveCmd(): ${command}`);
928
+ // eslint-disable-next-line no-unused-vars
929
+ function executeInteractiveCmd(command, { cwd } = {}) {
930
+ logInfo(`executeInteractiveCmd(): ${command}${cwd ? ` [cwd:${cwd}]` : ''}`);
814
931
 
815
932
  try {
816
- execSync(command, { stdio: 'inherit', env: process.env });
933
+ execSync(command, { cwd, stdio: 'inherit', env: process.env });
817
934
  } catch (error) {
818
935
  logError(`executeInteractiveCmd() failed, exiting: ${error}`);
819
936
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mediasoup",
3
- "version": "3.20.8",
3
+ "version": "3.20.10",
4
4
  "description": "Cutting Edge WebRTC Video Conferencing",
5
5
  "contributors": [
6
6
  "Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)",
@@ -75,6 +75,7 @@
75
75
  "scripts": {
76
76
  "prepare": "node npm-scripts.mjs prepare",
77
77
  "postinstall": "node npm-scripts.mjs postinstall",
78
+ "prepublishOnly": "node npm-scripts.mjs prepublishOnly",
78
79
  "typescript:build": "node npm-scripts.mjs typescript:build",
79
80
  "typescript:watch": "node npm-scripts.mjs typescript:watch",
80
81
  "worker:build": "node npm-scripts.mjs worker:build",
@@ -98,7 +99,9 @@
98
99
  "coverage:node": "node npm-scripts.mjs coverage:node",
99
100
  "publish:dry-run": "node npm-scripts.mjs publish:dry-run",
100
101
  "release:check": "node npm-scripts.mjs release:check",
101
- "release": "node npm-scripts.mjs release"
102
+ "release": "node npm-scripts.mjs release",
103
+ "release:rust:check": "node rust-scripts.mjs release:check",
104
+ "release:rust": "node rust-scripts.mjs release"
102
105
  },
103
106
  "dependencies": {
104
107
  "debug": "^4.4.3",
@@ -110,26 +113,25 @@
110
113
  },
111
114
  "devDependencies": {
112
115
  "@eslint/js": "^10.0.1",
113
- "@octokit/rest": "^22.0.1",
114
116
  "@types/debug": "^4.1.13",
115
117
  "@types/ini": "^4.1.1",
116
118
  "@types/jest": "^30.0.0",
117
- "@types/node": "^25.9.3",
119
+ "@types/node": "^26.0.0",
118
120
  "eslint": "^10.5.0",
119
121
  "eslint-config-prettier": "^10.1.8",
120
122
  "eslint-plugin-jest": "^29.15.2",
121
123
  "eslint-plugin-prettier": "^5.5.6",
122
- "globals": "^17.6.0",
123
- "ini": "^6.0.0",
124
+ "globals": "^17.7.0",
125
+ "ini": "^7.0.0",
124
126
  "jest": "^30.4.2",
125
- "knip": "^6.17.1",
127
+ "knip": "^6.18.0",
126
128
  "marked": "^18.0.5",
127
129
  "open-cli": "^9.0.0",
128
130
  "pick-port": "^2.2.1",
129
131
  "prettier": "^3.8.4",
130
132
  "ts-jest": "^29.4.11",
131
133
  "typescript": "^6.0.3",
132
- "typescript-eslint": "^8.61.1",
134
+ "typescript-eslint": "^8.62.0",
133
135
  "werift-sctp": "^0.0.11"
134
136
  }
135
137
  }
@@ -12,17 +12,11 @@ table IceUserNameFragment {
12
12
  web_rtc_transport_id: string (required);
13
13
  }
14
14
 
15
- table TupleHash {
16
- tuple_hash: uint64;
17
- web_rtc_transport_id: string (required);
18
- }
19
-
20
15
  table DumpResponse {
21
16
  id: string (required);
22
17
  udp_sockets: [IpPort] (required);
23
18
  tcp_servers: [IpPort] (required);
24
19
  web_rtc_transport_ids: [string] (required);
25
20
  local_ice_username_fragments: [IceUserNameFragment] (required);
26
- tuple_hashes: [TupleHash] (required);
27
21
  }
28
22
 
@@ -113,7 +113,21 @@ namespace RTC
113
113
  FINGERPRINT = 0x8028,
114
114
  ICE_CONTROLLED = 0x8029,
115
115
  ICE_CONTROLLING = 0x802A,
116
- NOMINATION = 0xC001
116
+ /**
117
+ * In libwebrtc native code, STUN_ATTR_NOMINATION is defined as 0xC001.
118
+ * However that value is not defined in any RFC/draft, not even in the
119
+ * draft that defines the NOMINATION attribute.
120
+ *
121
+ * @see https://datatracker.ietf.org/doc/html/draft-thatcher-ice-renomination
122
+ * @see https://issues.webrtc.org/issues/496629058
123
+ */
124
+ NOMINATION_OLD = 0xC001,
125
+ /**
126
+ * Value of the NOMINATION attribute in the new specification.
127
+ *
128
+ * @see https://juberti.github.io/draft-renomination/draft-thatcher-tsvwg-renomination.html
129
+ */
130
+ NOMINATION = 0x0030
117
131
  };
118
132
 
119
133
  // Authentication result.
@@ -290,7 +304,12 @@ namespace RTC
290
304
 
291
305
  uint32_t GetNomination() const
292
306
  {
293
- const auto* attribute = GetAttribute(StunPacket::AttributeType::NOMINATION);
307
+ auto* attribute = GetAttribute(StunPacket::AttributeType::NOMINATION);
308
+
309
+ if (!attribute)
310
+ {
311
+ attribute = GetAttribute(StunPacket::AttributeType::NOMINATION_OLD);
312
+ }
294
313
 
295
314
  if (!attribute)
296
315
  {
@@ -48,7 +48,7 @@ namespace RTC
48
48
  };
49
49
 
50
50
  public:
51
- explicit NackGenerator(Listener* listener, SharedInterface* shared, unsigned int sendNackDelayMs);
51
+ explicit NackGenerator(Listener* listener, SharedInterface* shared, uint32_t sendNackDelayMs);
52
52
  ~NackGenerator() override;
53
53
 
54
54
  bool ReceivePacket(const RTC::RTP::Packet* packet, bool isRecovered);
@@ -76,7 +76,7 @@ namespace RTC
76
76
  // Passed by argument.
77
77
  Listener* listener{ nullptr };
78
78
  SharedInterface* shared{ nullptr };
79
- unsigned int sendNackDelayMs{ 0u };
79
+ uint32_t sendNackDelayMs{ 0u };
80
80
  // Allocated by this.
81
81
  TimerHandleInterface* timer{ nullptr };
82
82
  // Others.
@@ -49,7 +49,7 @@ namespace RTC
49
49
  RTP::RtpStreamRecv::Listener* listener,
50
50
  SharedInterface* shared,
51
51
  RTP::RtpStream::Params& params,
52
- unsigned int sendNackDelayMs,
52
+ uint32_t sendNackDelayMs,
53
53
  bool useRtpInactivityCheck);
54
54
  ~RtpStreamRecv() override;
55
55
 
@@ -105,7 +105,7 @@ namespace RTC
105
105
 
106
106
  private:
107
107
  // Passed by argument.
108
- unsigned int sendNackDelayMs{ 0u };
108
+ uint32_t sendNackDelayMs{ 0u };
109
109
  bool useRtpInactivityCheck{ false };
110
110
  // Others.
111
111
  // Packets expected at last interval.