mediasoup 3.20.4 → 3.20.6

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 (49) hide show
  1. package/package.json +4 -4
  2. package/worker/include/RTC/Consumer.hpp +80 -45
  3. package/worker/include/RTC/PipeProducerStreamManager.hpp +78 -0
  4. package/worker/include/RTC/ProducerStreamManager.hpp +181 -0
  5. package/worker/include/RTC/SCTP/association/Association.hpp +24 -0
  6. package/worker/include/RTC/SCTP/association/StateCookie.hpp +104 -11
  7. package/worker/include/RTC/SCTP/packet/parameters/StateCookieParameter.hpp +4 -1
  8. package/worker/include/RTC/SCTP/public/SctpOptions.hpp +13 -0
  9. package/worker/include/RTC/SeqManager.hpp +2 -2
  10. package/worker/include/RTC/SimpleProducerStreamManager.hpp +72 -0
  11. package/worker/include/RTC/SimulcastProducerStreamManager.hpp +93 -0
  12. package/worker/include/RTC/SvcProducerStreamManager.hpp +72 -0
  13. package/worker/include/RTC/Transport.hpp +7 -1
  14. package/worker/meson.build +9 -5
  15. package/worker/src/RTC/Consumer.cpp +1404 -30
  16. package/worker/src/RTC/DirectTransport.cpp +4 -1
  17. package/worker/src/RTC/PipeProducerStreamManager.cpp +266 -0
  18. package/worker/src/RTC/PipeTransport.cpp +4 -1
  19. package/worker/src/RTC/PlainTransport.cpp +4 -1
  20. package/worker/src/RTC/SCTP/association/Association.cpp +142 -3
  21. package/worker/src/RTC/SCTP/association/StateCookie.cpp +96 -31
  22. package/worker/src/RTC/SCTP/association/StreamResetHandler.cpp +4 -0
  23. package/worker/src/RTC/SCTP/packet/Packet.cpp +1 -1
  24. package/worker/src/RTC/SCTP/packet/parameters/StateCookieParameter.cpp +12 -3
  25. package/worker/src/RTC/SCTP/public/SctpOptions.cpp +4 -0
  26. package/worker/src/RTC/SCTP/rx/DataTracker.cpp +4 -1
  27. package/worker/src/RTC/SeqManager.cpp +42 -29
  28. package/worker/src/RTC/SimpleProducerStreamManager.cpp +343 -0
  29. package/worker/src/RTC/SimulcastProducerStreamManager.cpp +1068 -0
  30. package/worker/src/RTC/SvcProducerStreamManager.cpp +664 -0
  31. package/worker/src/RTC/Transport.cpp +7 -44
  32. package/worker/src/RTC/WebRtcTransport.cpp +8 -2
  33. package/worker/test/include/RTC/SCTP/sctpCommon.hpp +1 -1
  34. package/worker/test/src/RTC/SCTP/association/TestAssociation.cpp +115 -0
  35. package/worker/test/src/RTC/SCTP/association/TestStateCookie.cpp +123 -0
  36. package/worker/test/src/RTC/SCTP/packet/TestPacket.cpp +4 -4
  37. package/worker/test/src/RTC/{TestSimpleConsumer.cpp → TestConsumer.cpp} +6 -7
  38. package/worker/test/src/RTC/TestPipeProducerStreamManager.cpp +471 -0
  39. package/worker/test/src/RTC/TestSimpleProducerStreamManager.cpp +531 -0
  40. package/worker/test/src/RTC/TestSimulcastProducerStreamManager.cpp +1040 -0
  41. package/worker/test/src/RTC/TestSvcProducerStreamManager.cpp +1278 -0
  42. package/worker/include/RTC/PipeConsumer.hpp +0 -95
  43. package/worker/include/RTC/SimpleConsumer.hpp +0 -102
  44. package/worker/include/RTC/SimulcastConsumer.hpp +0 -141
  45. package/worker/include/RTC/SvcConsumer.hpp +0 -118
  46. package/worker/src/RTC/PipeConsumer.cpp +0 -874
  47. package/worker/src/RTC/SimpleConsumer.cpp +0 -882
  48. package/worker/src/RTC/SimulcastConsumer.cpp +0 -1887
  49. package/worker/src/RTC/SvcConsumer.cpp +0 -1384
@@ -0,0 +1,664 @@
1
+ #define MS_CLASS "RTC::SvcProducerStreamManager"
2
+ // #define MS_LOG_DEV_LEVEL 3
3
+
4
+ #include "RTC/SvcProducerStreamManager.hpp"
5
+ #include "Logger.hpp"
6
+
7
+ namespace RTC
8
+ {
9
+ /* Static. */
10
+
11
+ static constexpr uint64_t BweDowngradeConservativeMs{ 10000u };
12
+ static constexpr uint64_t BweDowngradeMinActiveMs{ 8000u };
13
+
14
+ /* Instance methods. */
15
+
16
+ SvcProducerStreamManager::SvcProducerStreamManager(
17
+ const std::vector<RTC::RtpEncodingParameters>& consumableRtpEncodings,
18
+ const RTC::ConsumerTypes::VideoLayers& preferredLayers,
19
+ std::unique_ptr<RTC::RTP::Codecs::EncodingContext> encodingContext,
20
+ RTC::Media::Kind kind,
21
+ bool keyFrameSupported,
22
+ Listener* listener,
23
+ SharedInterface* shared)
24
+ : ProducerStreamManager(
25
+ consumableRtpEncodings,
26
+ preferredLayers,
27
+ std::move(encodingContext),
28
+ kind,
29
+ keyFrameSupported,
30
+ listener,
31
+ shared)
32
+ {
33
+ MS_TRACE();
34
+ }
35
+
36
+ RTC::RTP::RtpStreamRecv* SvcProducerStreamManager::GetProducerCurrentRtpStream() const
37
+ {
38
+ MS_TRACE();
39
+
40
+ // SVC has a single producer stream. Return it if we have a current layer.
41
+ if (this->encodingContext->GetCurrentSpatialLayer() == -1)
42
+ {
43
+ return nullptr;
44
+ }
45
+
46
+ return this->producerRtpStream;
47
+ }
48
+
49
+ RTC::RTP::RtpStreamRecv* SvcProducerStreamManager::GetProducerTargetRtpStream() const
50
+ {
51
+ MS_TRACE();
52
+
53
+ // SVC has a single producer stream. Return it if we have a target layer.
54
+ if (this->encodingContext->GetTargetSpatialLayer() == -1)
55
+ {
56
+ return nullptr;
57
+ }
58
+
59
+ return this->producerRtpStream;
60
+ }
61
+
62
+ bool SvcProducerStreamManager::IsActive() const
63
+ {
64
+ MS_TRACE();
65
+
66
+ // clang-format off
67
+ return (
68
+ this->listener->IsActive() &&
69
+ this->producerRtpStream &&
70
+ // If there is no RTP inactivity check do not consider the stream
71
+ // inactive despite it has score 0.
72
+ (this->producerRtpStream->GetScore() > 0u || !this->producerRtpStream->HasRtpInactivityCheckEnabled())
73
+ );
74
+ // clang-format on
75
+ }
76
+
77
+ void SvcProducerStreamManager::ProducerRtpStream(
78
+ RTC::RTP::RtpStreamRecv* rtpStream, uint32_t /*mappedSsrc*/)
79
+ {
80
+ MS_TRACE();
81
+
82
+ this->producerRtpStream = rtpStream;
83
+ }
84
+
85
+ void SvcProducerStreamManager::ProducerNewRtpStream(
86
+ RTC::RTP::RtpStreamRecv* rtpStream, uint32_t /*mappedSsrc*/)
87
+ {
88
+ MS_TRACE();
89
+
90
+ this->producerRtpStream = rtpStream;
91
+
92
+ // Emit the score event.
93
+ this->listener->OnProducerStreamManagerScore();
94
+
95
+ if (IsActive())
96
+ {
97
+ MayChangeLayers(/*force*/ false);
98
+ }
99
+ }
100
+
101
+ void SvcProducerStreamManager::ProducerRtpStreamScore(
102
+ RTC::RTP::RtpStreamRecv* /*rtpStream*/, uint8_t score, uint8_t previousScore)
103
+ {
104
+ MS_TRACE();
105
+
106
+ if (this->listener->IsActive())
107
+ {
108
+ // Just check target layers if the stream has died or reborned or if
109
+ // bitrate is not externally managed.
110
+ if (!this->externallyManagedBitrate || (score == 0u || previousScore == 0u))
111
+ {
112
+ MayChangeLayers(/*force*/ false);
113
+ }
114
+ }
115
+ }
116
+
117
+ void SvcProducerStreamManager::ProducerRtcpSenderReport(
118
+ RTC::RTP::RtpStreamRecv* /*rtpStream*/, bool /*first*/)
119
+ {
120
+ MS_TRACE();
121
+
122
+ // Do nothing.
123
+ }
124
+
125
+ uint32_t SvcProducerStreamManager::IncreaseLayer(
126
+ uint32_t bitrate, bool considerLoss, float lossPercentage, uint64_t nowMs)
127
+ {
128
+ MS_TRACE();
129
+
130
+ if (!this->producerRtpStream || this->producerRtpStream->GetScore() == 0u)
131
+ {
132
+ return 0u;
133
+ }
134
+
135
+ // If already in the preferred layers, do nothing.
136
+ if (this->provisionalTargetLayers == this->preferredLayers)
137
+ {
138
+ return 0u;
139
+ }
140
+
141
+ uint32_t virtualBitrate;
142
+
143
+ if (considerLoss)
144
+ {
145
+ // Calculate virtual available bitrate based on given bitrate and our
146
+ // packet lost.
147
+ if (lossPercentage < 2)
148
+ {
149
+ virtualBitrate = 1.08 * bitrate;
150
+ }
151
+ else if (lossPercentage > 10)
152
+ {
153
+ virtualBitrate = (1 - 0.5 * (lossPercentage / 100)) * bitrate;
154
+ }
155
+ else
156
+ {
157
+ virtualBitrate = bitrate;
158
+ }
159
+ }
160
+ else
161
+ {
162
+ virtualBitrate = bitrate;
163
+ }
164
+
165
+ uint32_t requiredBitrate{ 0u };
166
+ int16_t spatialLayer{ 0 };
167
+ int16_t temporalLayer{ 0 };
168
+
169
+ for (; std::cmp_less(spatialLayer, this->producerRtpStream->GetSpatialLayers()); ++spatialLayer)
170
+ {
171
+ // If this is higher than current spatial layer and we moved to current
172
+ // spatial layer due to BWE limitations, check how much it has elapsed
173
+ // since then.
174
+ if (nowMs - this->lastBweDowngradeAtMs < BweDowngradeConservativeMs)
175
+ {
176
+ if (this->provisionalTargetLayers.spatial > -1 && spatialLayer > this->encodingContext->GetCurrentSpatialLayer())
177
+ {
178
+ MS_DEBUG_DEV(
179
+ "avoid upgrading to spatial layer %" PRIi16 " due to recent BWE downgrade", spatialLayer);
180
+
181
+ goto done;
182
+ }
183
+ }
184
+
185
+ // Ignore spatial layers lower than the one we already have.
186
+ if (spatialLayer < this->provisionalTargetLayers.spatial)
187
+ {
188
+ continue;
189
+ }
190
+
191
+ temporalLayer = 0;
192
+
193
+ // Check bitrate of every temporal layer.
194
+ for (; std::cmp_less(temporalLayer, this->producerRtpStream->GetTemporalLayers());
195
+ ++temporalLayer)
196
+ {
197
+ // Ignore temporal layers lower than the one we already have (taking
198
+ // into account the spatial layer too).
199
+ if (
200
+ spatialLayer == this->provisionalTargetLayers.spatial &&
201
+ temporalLayer <= this->provisionalTargetLayers.temporal)
202
+ {
203
+ continue;
204
+ }
205
+
206
+ requiredBitrate =
207
+ this->producerRtpStream->GetLayerBitrate(nowMs, spatialLayer, temporalLayer);
208
+
209
+ // When using K-SVC we must subtract the bitrate of the current used
210
+ // layer if the new layer is the temporal layer 0 of a higher spatial
211
+ // layer.
212
+ if (
213
+ this->encodingContext->IsKSvc() && requiredBitrate && temporalLayer == 0 &&
214
+ this->provisionalTargetLayers.spatial > -1 &&
215
+ spatialLayer > this->provisionalTargetLayers.spatial)
216
+ {
217
+ auto provisionalRequiredBitrate = this->producerRtpStream->GetSpatialLayerBitrate(
218
+ nowMs, this->provisionalTargetLayers.spatial);
219
+
220
+ if (requiredBitrate > provisionalRequiredBitrate)
221
+ {
222
+ requiredBitrate -= provisionalRequiredBitrate;
223
+ }
224
+ else
225
+ {
226
+ requiredBitrate = 1u; // Don't set 0 since it would be ignored.
227
+ }
228
+ }
229
+
230
+ MS_DEBUG_DEV(
231
+ "testing layers %" PRIi16 ":%" PRIi16 " [virtual bitrate:%" PRIu32
232
+ ", required bitrate:%" PRIu32 "]",
233
+ spatialLayer,
234
+ temporalLayer,
235
+ virtualBitrate,
236
+ requiredBitrate);
237
+
238
+ // If active layer, end iterations here. Otherwise move to next spatial
239
+ // layer.
240
+ if (requiredBitrate)
241
+ {
242
+ goto done;
243
+ }
244
+ else
245
+ {
246
+ break;
247
+ }
248
+ }
249
+
250
+ // If this is the preferred or higher spatial layer, take it and exit.
251
+ if (spatialLayer >= this->preferredLayers.spatial)
252
+ {
253
+ break;
254
+ }
255
+ }
256
+
257
+ done:
258
+
259
+ // No higher active layers found.
260
+ if (!requiredBitrate)
261
+ {
262
+ return 0u;
263
+ }
264
+
265
+ // No luck.
266
+ if (requiredBitrate > virtualBitrate)
267
+ {
268
+ return 0u;
269
+ }
270
+
271
+ // Set provisional layers.
272
+ this->provisionalTargetLayers.spatial = spatialLayer;
273
+ this->provisionalTargetLayers.temporal = temporalLayer;
274
+
275
+ MS_DEBUG_DEV(
276
+ "upgrading to layers %" PRIi16 ":%" PRIi16 " [virtual bitrate:%" PRIu32
277
+ ", required bitrate:%" PRIu32 "]",
278
+ this->provisionalTargetLayers.spatial,
279
+ this->provisionalTargetLayers.temporal,
280
+ virtualBitrate,
281
+ requiredBitrate);
282
+
283
+ if (requiredBitrate <= bitrate)
284
+ {
285
+ return requiredBitrate;
286
+ }
287
+ else if (requiredBitrate <= virtualBitrate)
288
+ {
289
+ return bitrate;
290
+ }
291
+ else
292
+ {
293
+ return requiredBitrate; // NOTE: This cannot happen.
294
+ }
295
+ }
296
+
297
+ void SvcProducerStreamManager::ApplyLayers(uint64_t rtpStreamActiveMs)
298
+ {
299
+ MS_TRACE();
300
+
301
+ auto provisionalTargetLayers = this->provisionalTargetLayers;
302
+
303
+ // Reset provisional target layers.
304
+ this->provisionalTargetLayers.Reset();
305
+
306
+ if (provisionalTargetLayers != this->encodingContext->GetTargetLayers())
307
+ {
308
+ UpdateTargetLayers(provisionalTargetLayers.spatial, provisionalTargetLayers.temporal);
309
+
310
+ // If this looks like a spatial layer downgrade due to BWE limitations,
311
+ // set member.
312
+ if (
313
+ rtpStreamActiveMs > BweDowngradeMinActiveMs &&
314
+ this->encodingContext->GetTargetSpatialLayer() <
315
+ this->encodingContext->GetCurrentSpatialLayer() &&
316
+ this->encodingContext->GetCurrentSpatialLayer() <= this->preferredLayers.spatial)
317
+ {
318
+ MS_DEBUG_DEV(
319
+ "possible target spatial layer downgrade (from %" PRIi16 " to %" PRIi16
320
+ ") due to BWE limitation",
321
+ this->encodingContext->GetCurrentSpatialLayer(),
322
+ this->encodingContext->GetTargetSpatialLayer());
323
+
324
+ this->lastBweDowngradeAtMs = this->shared->GetTimeMs();
325
+ }
326
+ }
327
+ }
328
+
329
+ uint32_t SvcProducerStreamManager::GetDesiredBitrate(uint64_t nowMs) const
330
+ {
331
+ MS_TRACE();
332
+
333
+ if (!this->producerRtpStream)
334
+ {
335
+ return 0u;
336
+ }
337
+
338
+ uint32_t desiredBitrate{ 0u };
339
+
340
+ // When using K-SVC each spatial layer is independent of the others.
341
+ if (this->encodingContext->IsKSvc())
342
+ {
343
+ // Let's iterate all spatial layers of the Producer (from highest to lowest)
344
+ // and obtain their bitrate. Choose the highest one.
345
+ // NOTE: When the Producer enables a higher spatial layer, initially the
346
+ // bitrate of it could be less than the bitrate of a lower one. That's why
347
+ // we iterate all spatial layers here anyway.
348
+ for (auto spatialLayer{ this->producerRtpStream->GetSpatialLayers() - 1 }; spatialLayer >= 0;
349
+ --spatialLayer)
350
+ {
351
+ auto spatialLayerBitrate =
352
+ this->producerRtpStream->GetSpatialLayerBitrate(nowMs, spatialLayer);
353
+
354
+ desiredBitrate = std::max(spatialLayerBitrate, desiredBitrate);
355
+ }
356
+ }
357
+ else
358
+ {
359
+ desiredBitrate = this->producerRtpStream->GetBitrate(nowMs);
360
+ }
361
+
362
+ return desiredBitrate;
363
+ }
364
+
365
+ ProducerStreamManager::RtpPacketProcessResult SvcProducerStreamManager::ProcessRtpPacket(
366
+ RTC::RTP::Packet* packet,
367
+ bool /*lastSentPacketHasMarker*/,
368
+ uint32_t /*clockRate*/,
369
+ uint32_t /*maxPacketTs*/)
370
+ {
371
+ MS_TRACE();
372
+
373
+ RtpPacketProcessResult result;
374
+
375
+ if (this->encodingContext->GetTargetSpatialLayer() == -1 || this->encodingContext->GetTargetTemporalLayer() == -1)
376
+ {
377
+ result.type = RtpPacketProcessResult::Type::DROP;
378
+
379
+ #ifdef MS_RTC_LOGGER_RTP
380
+ packet->logger.Discarded(RTC::RtcLogger::RtpPacket::DiscardReason::INVALID_TARGET_LAYER);
381
+ #endif
382
+
383
+ return result;
384
+ }
385
+
386
+ // If we need to sync and this is not a key frame, ignore the packet.
387
+ if (this->syncRequired && !packet->IsKeyFrame())
388
+ {
389
+ // NOTE: No need to drop the packet in the RTP sequence manager since here
390
+ // we are blocking all packets but the key frame that would trigger sync
391
+ // below.
392
+
393
+ // Store the packet for the scenario in which this packet is part of the
394
+ // key frame and it arrived before the first packet of the key frame.
395
+ result.type = RtpPacketProcessResult::Type::BUFFER;
396
+
397
+ #ifdef MS_RTC_LOGGER_RTP
398
+ packet->logger.Discarded(RTC::RtcLogger::RtpPacket::DiscardReason::NOT_A_KEYFRAME);
399
+ #endif
400
+
401
+ return result;
402
+ }
403
+
404
+ // Packets with only padding are not forwarded.
405
+ if (packet->GetPayloadLength() == 0)
406
+ {
407
+ result.type = RtpPacketProcessResult::Type::DROP;
408
+
409
+ #ifdef MS_RTC_LOGGER_RTP
410
+ packet->logger.Discarded(RTC::RtcLogger::RtpPacket::DiscardReason::EMPTY_PAYLOAD);
411
+ #endif
412
+
413
+ return result;
414
+ }
415
+
416
+ // Whether this is the first packet after re-sync.
417
+ const bool isSyncPacket = this->syncRequired;
418
+
419
+ // Whether packets stored in the target layer retransmission buffer must be
420
+ // sent once this packet is sent.
421
+ bool sendBufferedPackets{ false };
422
+
423
+ // Sync sequence number and timestamp if required.
424
+ if (isSyncPacket)
425
+ {
426
+ if (packet->IsKeyFrame())
427
+ {
428
+ MS_DEBUG_TAG(
429
+ rtp,
430
+ "sync key frame received [ssrc:%" PRIu32 ", seq:%" PRIu16 ", ts:%" PRIu32 "]",
431
+ packet->GetSsrc(),
432
+ packet->GetSequenceNumber(),
433
+ packet->GetTimestamp());
434
+
435
+ sendBufferedPackets = true;
436
+ }
437
+
438
+ result.isSyncPacket = true;
439
+ result.syncSeqValue = packet->GetSequenceNumber() - 1;
440
+ result.shouldSyncEncodingContext = true;
441
+
442
+ // Sync the encoding context before ProcessPayload runs below.
443
+ this->encodingContext->SyncRequired();
444
+
445
+ this->syncRequired = false;
446
+ }
447
+
448
+ auto previousLayers = this->encodingContext->GetCurrentLayers();
449
+
450
+ bool marker{ false };
451
+
452
+ if (!packet->ProcessPayload(this->encodingContext.get(), marker))
453
+ {
454
+ result.type = RtpPacketProcessResult::Type::DROP;
455
+
456
+ #ifdef MS_RTC_LOGGER_RTP
457
+ packet->logger.Discarded(RTC::RtcLogger::RtpPacket::DiscardReason::DROPPED_BY_CODEC);
458
+ #endif
459
+
460
+ return result;
461
+ }
462
+
463
+ if (previousLayers != this->encodingContext->GetCurrentLayers())
464
+ {
465
+ result.temporalLayerChanged = true;
466
+ }
467
+
468
+ // Set forward action.
469
+ result.type = RtpPacketProcessResult::Type::FORWARD;
470
+ result.tsOffset = 0u;
471
+ result.marker = marker;
472
+ result.sendBufferedPackets = sendBufferedPackets;
473
+
474
+ return result;
475
+ }
476
+
477
+ void SvcProducerStreamManager::RequestKeyFrame()
478
+ {
479
+ MS_TRACE();
480
+
481
+ auto mappedSsrc = this->consumableRtpEncodings[0].ssrc;
482
+
483
+ this->listener->OnProducerStreamManagerKeyFrameRequested(mappedSsrc);
484
+ }
485
+
486
+ void SvcProducerStreamManager::RequestKeyFrameForTargetSpatialLayer()
487
+ {
488
+ MS_TRACE();
489
+
490
+ RequestKeyFrame();
491
+ }
492
+
493
+ void SvcProducerStreamManager::RequestKeyFrameForCurrentSpatialLayer()
494
+ {
495
+ MS_TRACE();
496
+
497
+ RequestKeyFrame();
498
+ }
499
+
500
+ void SvcProducerStreamManager::UpdateTargetLayers(
501
+ int16_t newTargetSpatialLayer, int16_t newTargetTemporalLayer)
502
+ {
503
+ MS_TRACE();
504
+
505
+ if (newTargetSpatialLayer == -1)
506
+ {
507
+ // Unset current and target layers.
508
+ this->encodingContext->SetTargetSpatialLayer(-1);
509
+ this->encodingContext->SetCurrentSpatialLayer(-1);
510
+ this->encodingContext->SetTargetTemporalLayer(-1);
511
+ this->encodingContext->SetCurrentTemporalLayer(-1);
512
+
513
+ MS_DEBUG_TAG(svc, "target layers changed [spatial:-1, temporal:-1]");
514
+
515
+ this->listener->OnProducerStreamManagerLayersChanged();
516
+
517
+ return;
518
+ }
519
+
520
+ this->encodingContext->SetTargetSpatialLayer(newTargetSpatialLayer);
521
+ this->encodingContext->SetTargetTemporalLayer(newTargetTemporalLayer);
522
+
523
+ MS_DEBUG_TAG(
524
+ svc,
525
+ "target layers changed [spatial:%" PRIi16 ", temporal:%" PRIi16 "]",
526
+ newTargetSpatialLayer,
527
+ newTargetTemporalLayer);
528
+
529
+ // Target spatial layer has changed.
530
+ if (newTargetSpatialLayer != this->encodingContext->GetCurrentSpatialLayer())
531
+ {
532
+ // In K-SVC always ask for a keyframe when changing target spatial layer.
533
+ if (this->encodingContext->IsKSvc())
534
+ {
535
+ MS_DEBUG_DEV("K-SVC: requesting keyframe to target spatial change");
536
+
537
+ RequestKeyFrame();
538
+ }
539
+ // In full SVC just ask for a keyframe when upgrading target spatial layer.
540
+ // NOTE: This is because nobody implements RTCP LRR yet.
541
+ else if (newTargetSpatialLayer > this->encodingContext->GetCurrentSpatialLayer())
542
+ {
543
+ MS_DEBUG_DEV("full SVC: requesting keyframe to target spatial upgrade");
544
+
545
+ RequestKeyFrame();
546
+ }
547
+ }
548
+ }
549
+
550
+ bool SvcProducerStreamManager::RecalculateTargetLayers(
551
+ RTC::ConsumerTypes::VideoLayers& newTargetLayers) const
552
+ {
553
+ MS_TRACE();
554
+
555
+ // Start with no layers.
556
+ newTargetLayers.Reset();
557
+
558
+ auto nowMs = this->shared->GetTimeMs();
559
+ int16_t spatialLayer{ 0 };
560
+
561
+ if (!this->producerRtpStream)
562
+ {
563
+ goto done;
564
+ }
565
+
566
+ if (this->producerRtpStream->GetScore() == 0u)
567
+ {
568
+ goto done;
569
+ }
570
+
571
+ for (; std::cmp_less(spatialLayer, this->producerRtpStream->GetSpatialLayers()); ++spatialLayer)
572
+ {
573
+ // If this is higher than current spatial layer and we moved to current
574
+ // spatial layer due to BWE limitations, check how much it has elapsed
575
+ // since then.
576
+ if (nowMs - this->lastBweDowngradeAtMs < BweDowngradeConservativeMs)
577
+ {
578
+ if (newTargetLayers.spatial > -1 && spatialLayer > this->encodingContext->GetCurrentSpatialLayer())
579
+ {
580
+ continue;
581
+ }
582
+ }
583
+
584
+ if (!this->producerRtpStream->GetSpatialLayerBitrate(nowMs, spatialLayer))
585
+ {
586
+ continue;
587
+ }
588
+
589
+ newTargetLayers.spatial = spatialLayer;
590
+
591
+ // If this is the preferred or higher spatial layer and has bitrate,
592
+ // take it and exit.
593
+ if (spatialLayer >= this->preferredLayers.spatial)
594
+ {
595
+ break;
596
+ }
597
+ }
598
+
599
+ if (newTargetLayers.spatial != -1)
600
+ {
601
+ if (newTargetLayers.spatial == this->preferredLayers.spatial)
602
+ {
603
+ newTargetLayers.temporal = this->preferredLayers.temporal;
604
+ }
605
+ else if (newTargetLayers.spatial < this->preferredLayers.spatial)
606
+ {
607
+ newTargetLayers.temporal =
608
+ static_cast<int16_t>(this->encodingContext->GetTemporalLayers() - 1);
609
+ }
610
+ else
611
+ {
612
+ newTargetLayers.temporal = 0;
613
+ }
614
+ }
615
+
616
+ done:
617
+
618
+ // Return true if any target layer changed.
619
+ return newTargetLayers != this->encodingContext->GetTargetLayers();
620
+ }
621
+
622
+ void SvcProducerStreamManager::OnTransportConnected()
623
+ {
624
+ MS_TRACE();
625
+
626
+ this->syncRequired = true;
627
+
628
+ if (IsActive())
629
+ {
630
+ MayChangeLayers(/*force*/ false);
631
+ }
632
+ }
633
+
634
+ void SvcProducerStreamManager::OnTransportDisconnected()
635
+ {
636
+ MS_TRACE();
637
+
638
+ this->lastBweDowngradeAtMs = 0u;
639
+
640
+ UpdateTargetLayers(-1, -1);
641
+ }
642
+
643
+ void SvcProducerStreamManager::OnPaused()
644
+ {
645
+ MS_TRACE();
646
+
647
+ this->lastBweDowngradeAtMs = 0u;
648
+
649
+ UpdateTargetLayers(-1, -1);
650
+ }
651
+
652
+ void SvcProducerStreamManager::OnResumed()
653
+ {
654
+ MS_TRACE();
655
+
656
+ this->syncRequired = true;
657
+
658
+ if (IsActive())
659
+ {
660
+ MayChangeLayers(/*force*/ false);
661
+ }
662
+ }
663
+
664
+ } // namespace RTC