mediasoup 3.20.9 → 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.
package/README.md CHANGED
@@ -13,8 +13,10 @@
13
13
  [![][github-actions-shield-mediasoup-rust]][github-actions-mediasoup-rust]
14
14
  [![][github-actions-shield-mediasoup-worker-fuzzer]][github-actions-mediasoup-worker-fuzzer]
15
15
  [![][github-actions-shield-mediasoup-npm-publish]][github-actions-mediasoup-npm-publish]
16
+ [![][github-actions-shield-mediasoup-crate-publish]][github-actions-mediasoup-crate-publish]
16
17
  [![][github-actions-shield-mediasoup-worker-prebuild]][github-actions-mediasoup-worker-prebuild]
17
- [![][github-actions-shield-mediasoup-website-publish]][github-actions-mediasoup-website-publish]
18
+ [![][github-actions-shield-mediasoup-website-update]][github-actions-mediasoup-website-update]
19
+ [![][github-actions-shield-mediasoup-demo-update]][github-actions-mediasoup-demo-update]
18
20
  [![][github-actions-mediasoup-codeql-shield-mediasoup]][github-actions-mediasoup-codeql-mediasoup]
19
21
 
20
22
  ## Website and Documentation
@@ -108,8 +110,12 @@ You can support mediasoup by [sponsoring][sponsor] it. Thanks!
108
110
  [github-actions-mediasoup-worker-prebuild]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-worker-prebuild.yaml?query=event%3Aworkflow_run
109
111
  [github-actions-shield-mediasoup-npm-publish]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-npm-publish.yaml/badge.svg?event=push
110
112
  [github-actions-mediasoup-npm-publish]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-npm-publish.yaml?query=event%3Apush
111
- [github-actions-shield-mediasoup-website-publish]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-website-publish.yaml/badge.svg?event=workflow_run
112
- [github-actions-mediasoup-website-publish]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-website-publish.yaml?query=event%3Aworkflow_run
113
+ [github-actions-shield-mediasoup-crate-publish]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-crate-publish.yaml/badge.svg?event=push
114
+ [github-actions-mediasoup-crate-publish]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-crate-publish.yaml?query=event%3Apush
115
+ [github-actions-shield-mediasoup-website-update]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-website-update.yaml/badge.svg?event=workflow_run
116
+ [github-actions-mediasoup-website-update]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-website-update.yaml?query=event%3Aworkflow_run
117
+ [github-actions-shield-mediasoup-demo-update]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-demo-update.yaml/badge.svg?event=workflow_run
118
+ [github-actions-mediasoup-demo-update]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-demo-update.yaml?query=event%3Aworkflow_run
113
119
  [github-actions-mediasoup-codeql-shield-mediasoup]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-codeql.yaml/badge.svg?branch=v3
114
120
  [github-actions-mediasoup-codeql-mediasoup]: https://github.com/versatica/mediasoup/actions/workflows/mediasoup-codeql.yaml?query=branch%3Av3
115
121
  [sponsor]: https://mediasoup.org/sponsor
package/npm-scripts.mjs CHANGED
@@ -138,6 +138,12 @@ async function run() {
138
138
  break;
139
139
  }
140
140
 
141
+ case 'prepublishOnly': {
142
+ prepublishOnly();
143
+
144
+ break;
145
+ }
146
+
141
147
  case 'typescript:build': {
142
148
  buildTypescript({ force: true, args: taskArgs });
143
149
 
@@ -524,6 +530,26 @@ function installNodeDeps() {
524
530
  executeCmd('npm audit --prefix worker/scripts');
525
531
  }
526
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
+
527
553
  function publishDryRun() {
528
554
  logInfo('publishDryRun()');
529
555
 
@@ -551,7 +577,7 @@ async function checkRelease() {
551
577
  try {
552
578
  versionChanges = await getVersionChanges();
553
579
  } catch (error) {
554
- logError(error.message);
580
+ logError(`checkRelease() | ${error.message}`);
555
581
 
556
582
  exitWithError();
557
583
  }
@@ -609,10 +635,19 @@ async function release({ args = '' } = {}) {
609
635
  await updateChangelog(version);
610
636
 
611
637
  // Commit the bump, tag it, and push both. The pushed tag triggers
612
- // mediasoup-npm-publish.yaml, which checks, creates the GitHub release and
613
- // publishes to NPM; on its success mediasoup-worker-prebuild.yaml builds and
614
- // uploads the prebuilt binaries.
615
- executeCmd(`git commit -am 'version ${version}'`);
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]'`);
616
651
  executeCmd(`git tag -a ${version} -m '${version}'`);
617
652
  executeCmd(`git push origin ${MAIN_BRANCH}`);
618
653
  executeCmd(`git push origin '${version}'`);
@@ -664,8 +699,10 @@ async function prebuildWorker() {
664
699
  }
665
700
  }
666
701
 
667
- // Returns a Promise resolving to true if a mediasoup-worker prebuilt binary
668
- // 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
+ */
669
706
  async function downloadPrebuiltWorker() {
670
707
  const releaseBase =
671
708
  process.env.MEDIASOUP_WORKER_PREBUILT_DOWNLOAD_BASE_URL ||
@@ -873,11 +910,14 @@ async function updateChangelog(version) {
873
910
  fs.writeFileSync('./CHANGELOG.md', updatedChangelog);
874
911
  }
875
912
 
876
- function executeCmd(command) {
877
- logInfo(`executeCmd(): ${command}`);
913
+ function executeCmd(command, { cwd } = {}) {
914
+ logInfo(`executeCmd(): ${command}${cwd ? ` [cwd:${cwd}]` : ''}`);
878
915
 
879
916
  try {
880
- execSync(command, { stdio: ['ignore', process.stdout, process.stderr] });
917
+ execSync(command, {
918
+ cwd,
919
+ stdio: ['ignore', process.stdout, process.stderr],
920
+ });
881
921
  } catch (error) {
882
922
  logError(`executeCmd() failed, exiting: ${error}`);
883
923
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mediasoup",
3
- "version": "3.20.9",
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",
@@ -112,7 +113,6 @@
112
113
  },
113
114
  "devDependencies": {
114
115
  "@eslint/js": "^10.0.1",
115
- "@octokit/rest": "^22.0.1",
116
116
  "@types/debug": "^4.1.13",
117
117
  "@types/ini": "^4.1.1",
118
118
  "@types/jest": "^30.0.0",
@@ -121,17 +121,17 @@
121
121
  "eslint-config-prettier": "^10.1.8",
122
122
  "eslint-plugin-jest": "^29.15.2",
123
123
  "eslint-plugin-prettier": "^5.5.6",
124
- "globals": "^17.6.0",
124
+ "globals": "^17.7.0",
125
125
  "ini": "^7.0.0",
126
126
  "jest": "^30.4.2",
127
- "knip": "^6.17.1",
127
+ "knip": "^6.18.0",
128
128
  "marked": "^18.0.5",
129
129
  "open-cli": "^9.0.0",
130
130
  "pick-port": "^2.2.1",
131
131
  "prettier": "^3.8.4",
132
132
  "ts-jest": "^29.4.11",
133
133
  "typescript": "^6.0.3",
134
- "typescript-eslint": "^8.61.1",
134
+ "typescript-eslint": "^8.62.0",
135
135
  "werift-sctp": "^0.0.11"
136
136
  }
137
137
  }
@@ -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.
@@ -523,7 +523,8 @@ namespace RTC
523
523
  HandleTuple(
524
524
  tuple,
525
525
  request->HasAttribute(StunPacket::AttributeType::USE_CANDIDATE),
526
- request->HasAttribute(StunPacket::AttributeType::NOMINATION),
526
+ request->HasAttribute(StunPacket::AttributeType::NOMINATION) ||
527
+ request->HasAttribute(StunPacket::AttributeType::NOMINATION_OLD),
527
528
  request->GetNomination());
528
529
 
529
530
  // If state is 'connected' or 'completed' after handling the tuple, then
@@ -250,6 +250,11 @@ namespace RTC
250
250
  MS_DUMP_CLEAN(indentation + 1, " nomination: %" PRIu32, GetNomination());
251
251
  }
252
252
 
253
+ if (HasAttribute(StunPacket::AttributeType::NOMINATION_OLD))
254
+ {
255
+ MS_DUMP_CLEAN(indentation + 1, " nomination (old): %" PRIu32, GetNomination());
256
+ }
257
+
253
258
  if (HasAttribute(StunPacket::AttributeType::SOFTWARE))
254
259
  {
255
260
  const auto software = GetSoftware();
@@ -404,6 +409,8 @@ namespace RTC
404
409
 
405
410
  StoreNewAttribute(
406
411
  StunPacket::AttributeType::NOMINATION, AttributeFactoryBuffer, sizeof(nomination));
412
+ StoreNewAttribute(
413
+ StunPacket::AttributeType::NOMINATION_OLD, AttributeFactoryBuffer, sizeof(nomination));
407
414
  }
408
415
 
409
416
  void StunPacket::AddSoftware(const std::string_view software)
@@ -1058,6 +1065,7 @@ namespace RTC
1058
1065
  }
1059
1066
 
1060
1067
  case StunPacket::AttributeType::NOMINATION:
1068
+ case StunPacket::AttributeType::NOMINATION_OLD:
1061
1069
  {
1062
1070
  if (attrLen != 4)
1063
1071
  {
@@ -16,7 +16,7 @@ namespace RTC
16
16
 
17
17
  /* Instance methods. */
18
18
 
19
- NackGenerator::NackGenerator(Listener* listener, SharedInterface* shared, unsigned int sendNackDelayMs)
19
+ NackGenerator::NackGenerator(Listener* listener, SharedInterface* shared, uint32_t sendNackDelayMs)
20
20
  : listener(listener),
21
21
  shared(shared),
22
22
  sendNackDelayMs(sendNackDelayMs),
@@ -20,7 +20,7 @@ namespace RTC
20
20
 
21
21
  static constexpr size_t ProducerSendBufferSize{ 65536 };
22
22
  static thread_local uint8_t ProducerSendBuffer[ProducerSendBufferSize];
23
- static constexpr unsigned int SendNackDelay{ 10u }; // In ms.
23
+ static constexpr uint32_t SendNackDelay{ 10u }; // In ms.
24
24
 
25
25
  /* Instance methods. */
26
26
 
@@ -140,9 +140,7 @@ namespace RTC
140
140
  }
141
141
 
142
142
  // There are dropped inputs, calculate 'base' for this input.
143
- auto droppedCount = std::distance(
144
- this->dropped.begin(),
145
- std::lower_bound(this->dropped.begin(), this->dropped.end(), input, SeqLowerThan()));
143
+ auto droppedCount = std::distance(this->dropped.begin(), it);
146
144
 
147
145
  base = (this->base - droppedCount) & SeqManager::MaxValue;
148
146
  }
@@ -508,7 +508,9 @@ SCENARIO("ICE StunPacket", "[serializable][ice][stunpacket]")
508
508
  // Byte length: 8.
509
509
  uint64_t iceControlling = 15697499370457501716u;
510
510
  // Byte length of USE_CANDIDATE: 0.
511
- // // Byte length: 4.
511
+ // NOTE: `AddNomination()` adds the "NOMINATION" attribute with both the old
512
+ // and the new value, so it will insert 2 attributes instead of one.
513
+ // Byte length: 4 x 2.
512
514
  uint32_t nomination = 12345678u;
513
515
  // Byte length: 18 (2 byte of padding needed).
514
516
  std::string software = "mediasoup x.y.z :)";
@@ -518,7 +520,7 @@ SCENARIO("ICE StunPacket", "[serializable][ice][stunpacket]")
518
520
 
519
521
  // Total length of the attributes.
520
522
  size_t attributesLen =
521
- (4 + 27 + 1) + (4 + 4) + (4 + 8) + (4) + (4 + 4) + (4 + 18 + 2) + (4 + 4 + 23 + 1);
523
+ (4 + 27 + 1) + (4 + 4) + (4 + 8) + (4) + ((4 + 4) * 2) + (4 + 18 + 2) + (4 + 4 + 23 + 1);
522
524
 
523
525
  request->AddUsername(username);
524
526
  request->AddPriority(priority);
@@ -533,6 +535,8 @@ SCENARIO("ICE StunPacket", "[serializable][ice][stunpacket]")
533
535
  REQUIRE_THROWS_AS(request->AddPriority(priority), MediaSoupError);
534
536
  REQUIRE_THROWS_AS(request->AddIceControlling(iceControlling), MediaSoupError);
535
537
  REQUIRE_THROWS_AS(request->AddUseCandidate(), MediaSoupError);
538
+ // NOTE: `AddNomination()` adds the "NOMINATION" attribute with both the old
539
+ // and the new value, so it will insert 2 attributes instead of one.
536
540
  REQUIRE_THROWS_AS(request->AddNomination(nomination), MediaSoupError);
537
541
  REQUIRE_THROWS_AS(request->AddSoftware(software), MediaSoupError);
538
542
  REQUIRE_THROWS_AS(request->AddErrorCode(errorCode, errorReasonPhrase), MediaSoupError);
@@ -8,7 +8,7 @@
8
8
 
9
9
  // 17: 16 bit mask + the initial sequence number.
10
10
  static constexpr size_t MaxRequestedPackets{ 17 };
11
- static constexpr unsigned int SendNackDelay{ 0u }; // In ms.
11
+ static constexpr uint32_t SendNackDelay{ 0u }; // In ms.
12
12
  static const bool UseRtpInactivityCheck{ false };
13
13
 
14
14
  SCENARIO("RtpStreamRecv", "[rtp][rtpstream][rtpstreamrecv]")
@@ -9,7 +9,7 @@
9
9
 
10
10
  SCENARIO("NackGenerator generator", "[rtp][rtcp][nack]")
11
11
  {
12
- constexpr unsigned int SendNackDelay{ 0u }; // In ms.
12
+ constexpr uint32_t SendNackDelay{ 0u }; // In ms.
13
13
 
14
14
  struct TestNackGeneratorInput
15
15
  {