mediasoup 3.25.0 → 3.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ### NEXT
4
4
 
5
+ ### 3.26.0
6
+
7
+ - **Breaking change:** Simulcast and SVC: Limit temporal layer to the preferred one ([PR #1892](https://github.com/versatica/mediasoup/pull/1892)).
8
+
5
9
  ### 3.25.0
6
10
 
7
11
  - Worker: Fix undefined behavior in `RtpStreamRecv::UpdateScore()` when no packets were received ([PR #1886](https://github.com/versatica/mediasoup/pull/1886)).
@@ -211,7 +211,7 @@ class ConsumerImpl extends enhancedEvents_1.EnhancedEventEmitter {
211
211
  if (typeof spatialLayer !== 'number') {
212
212
  throw new TypeError('spatialLayer must be a number');
213
213
  }
214
- if (temporalLayer && typeof temporalLayer !== 'number') {
214
+ if (temporalLayer != null && typeof temporalLayer !== 'number') {
215
215
  throw new TypeError('if given, temporalLayer must be a number');
216
216
  }
217
217
  const builder = this.#channel.bufferBuilder;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mediasoup",
3
- "version": "3.25.0",
3
+ "version": "3.26.0",
4
4
  "description": "Cutting Edge WebRTC Video Conferencing",
5
5
  "contributors": [
6
6
  "Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)",
@@ -124,19 +124,19 @@
124
124
  "@types/node": "^26.2.0",
125
125
  "eslint": "^10.8.1",
126
126
  "eslint-config-prettier": "^10.1.8",
127
- "eslint-plugin-jest": "^29.16.0",
127
+ "eslint-plugin-jest": "^29.16.1",
128
128
  "eslint-plugin-prettier": "^5.5.6",
129
- "globals": "^17.9.0",
129
+ "globals": "^17.11.0",
130
130
  "ini": "^7.0.0",
131
131
  "jest": "^30.4.2",
132
- "knip": "^6.32.0",
133
- "marked": "^18.0.9",
132
+ "knip": "^6.32.2",
133
+ "marked": "^18.0.10",
134
134
  "open-cli": "^9.0.0",
135
135
  "pick-port": "^2.2.1",
136
136
  "prettier": "^3.9.6",
137
137
  "ts-jest": "^29.4.12",
138
138
  "typescript": "^6.0.3",
139
- "typescript-eslint": "^8.66.0",
139
+ "typescript-eslint": "^8.67.0",
140
140
  "werift-sctp": "^0.0.11"
141
141
  }
142
142
  }
@@ -238,6 +238,11 @@ namespace RTC
238
238
  uint32_t requiredBitrate{ 0u };
239
239
  int16_t spatialLayer{ 0 };
240
240
  int16_t temporalLayer{ 0 };
241
+ // Whether a usable spatial layer has been found, in which case we must not
242
+ // go above the preferred spatial layer. Same criteria as in
243
+ // RecalculateTargetLayers(), so both take the same decision no matter the
244
+ // bitrate of the layer.
245
+ bool usableSpatialLayerFound{ this->provisionalTargetLayers.spatial != -1 };
241
246
 
242
247
  for (size_t sIdx{ 0u }; sIdx < this->producerRtpStreams.size(); ++sIdx)
243
248
  {
@@ -262,8 +267,12 @@ namespace RTC
262
267
  {
263
268
  continue;
264
269
  }
265
- // If this is higher than preferred spatial layer, abort.
266
- else if (spatialLayer > this->preferredLayers.spatial)
270
+ // If this is higher than preferred spatial layer, abort unless no lower
271
+ // spatial layer is usable or this is the provisional one (so we may still
272
+ // increase its temporal layer).
273
+ else if (
274
+ spatialLayer > this->preferredLayers.spatial && usableSpatialLayerFound &&
275
+ spatialLayer != this->provisionalTargetLayers.spatial)
267
276
  {
268
277
  MS_DEBUG_DEV(
269
278
  "avoid upgrading to spatial layer %" PRIi16
@@ -313,10 +322,19 @@ namespace RTC
313
322
  continue;
314
323
  }
315
324
 
325
+ // This spatial layer is usable even if it has no bitrate at all.
326
+ usableSpatialLayerFound = true;
327
+
316
328
  temporalLayer = 0;
317
329
 
330
+ // Don't consider temporal layers above the preferred one, nor above the
331
+ // ones this stream has.
332
+ const auto maxTemporalLayer = std::min(
333
+ static_cast<int16_t>(producerRtpStream->GetTemporalLayers() - 1),
334
+ this->preferredLayers.temporal);
335
+
318
336
  // Check bitrate of every temporal layer.
319
- for (; std::cmp_less(temporalLayer, producerRtpStream->GetTemporalLayers()); ++temporalLayer)
337
+ for (; temporalLayer <= maxTemporalLayer; ++temporalLayer)
320
338
  {
321
339
  // Ignore temporal layers lower than the one we already have (taking
322
340
  // into account the spatial layer too).
@@ -1004,6 +1022,13 @@ namespace RTC
1004
1022
  continue;
1005
1023
  }
1006
1024
 
1025
+ // Don't go above the preferred spatial layer if we already found a usable
1026
+ // lower one.
1027
+ if (spatialLayer > this->preferredLayers.spatial && newTargetLayers.spatial != -1)
1028
+ {
1029
+ break;
1030
+ }
1031
+
1007
1032
  newTargetLayers.spatial = spatialLayer;
1008
1033
 
1009
1034
  // If this is the preferred or higher spatial layer take it and exit.
@@ -1015,19 +1040,11 @@ namespace RTC
1015
1040
 
1016
1041
  if (newTargetLayers.spatial != -1)
1017
1042
  {
1018
- if (newTargetLayers.spatial == this->preferredLayers.spatial)
1019
- {
1020
- newTargetLayers.temporal = this->preferredLayers.temporal;
1021
- }
1022
- else if (newTargetLayers.spatial < this->preferredLayers.spatial)
1023
- {
1024
- newTargetLayers.temporal =
1025
- static_cast<int16_t>(this->encodingContext->GetTemporalLayers() - 1);
1026
- }
1027
- else
1028
- {
1029
- newTargetLayers.temporal = 0;
1030
- }
1043
+ // Don't consider temporal layers above the preferred one, nor above the
1044
+ // ones this stream has.
1045
+ newTargetLayers.temporal = std::min(
1046
+ this->preferredLayers.temporal,
1047
+ static_cast<int16_t>(this->encodingContext->GetTemporalLayers() - 1));
1031
1048
  }
1032
1049
 
1033
1050
  // Return true if any target layer changed.
@@ -190,9 +190,14 @@ namespace RTC
190
190
 
191
191
  temporalLayer = 0;
192
192
 
193
+ // Don't consider temporal layers above the preferred one, nor above the
194
+ // ones this stream has.
195
+ const auto maxTemporalLayer = std::min(
196
+ static_cast<int16_t>(this->producerRtpStream->GetTemporalLayers() - 1),
197
+ this->preferredLayers.temporal);
198
+
193
199
  // Check bitrate of every temporal layer.
194
- for (; std::cmp_less(temporalLayer, this->producerRtpStream->GetTemporalLayers());
195
- ++temporalLayer)
200
+ for (; temporalLayer <= maxTemporalLayer; ++temporalLayer)
196
201
  {
197
202
  // Ignore temporal layers lower than the one we already have (taking
198
203
  // into account the spatial layer too).
@@ -247,8 +252,9 @@ namespace RTC
247
252
  }
248
253
  }
249
254
 
250
- // If this is the preferred or higher spatial layer, take it and exit.
251
- if (spatialLayer >= this->preferredLayers.spatial)
255
+ // If this is the preferred or higher spatial layer, take it and exit,
256
+ // unless we have not found any usable spatial layer yet.
257
+ if (spatialLayer >= this->preferredLayers.spatial && this->provisionalTargetLayers.spatial != -1)
252
258
  {
253
259
  break;
254
260
  }
@@ -589,6 +595,13 @@ namespace RTC
589
595
  continue;
590
596
  }
591
597
 
598
+ // Don't go above the preferred spatial layer if we already found a usable
599
+ // lower one.
600
+ if (spatialLayer > this->preferredLayers.spatial && newTargetLayers.spatial != -1)
601
+ {
602
+ break;
603
+ }
604
+
592
605
  newTargetLayers.spatial = spatialLayer;
593
606
 
594
607
  // If this is the preferred or higher spatial layer and has bitrate,
@@ -601,19 +614,11 @@ namespace RTC
601
614
 
602
615
  if (newTargetLayers.spatial != -1)
603
616
  {
604
- if (newTargetLayers.spatial == this->preferredLayers.spatial)
605
- {
606
- newTargetLayers.temporal = this->preferredLayers.temporal;
607
- }
608
- else if (newTargetLayers.spatial < this->preferredLayers.spatial)
609
- {
610
- newTargetLayers.temporal =
611
- static_cast<int16_t>(this->encodingContext->GetTemporalLayers() - 1);
612
- }
613
- else
614
- {
615
- newTargetLayers.temporal = 0;
616
- }
617
+ // Don't consider temporal layers above the preferred one, nor above the
618
+ // ones this stream has.
619
+ newTargetLayers.temporal = std::min(
620
+ this->preferredLayers.temporal,
621
+ static_cast<int16_t>(this->encodingContext->GetTemporalLayers() - 1));
617
622
  }
618
623
 
619
624
  done: