mediasoup 3.9.13 → 3.9.16

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 (79) hide show
  1. package/node/lib/ActiveSpeakerObserver.d.ts +1 -1
  2. package/node/lib/ActiveSpeakerObserver.d.ts.map +1 -1
  3. package/node/lib/AudioLevelObserver.d.ts +1 -1
  4. package/node/lib/AudioLevelObserver.d.ts.map +1 -1
  5. package/node/lib/Consumer.d.ts +4 -4
  6. package/node/lib/Consumer.d.ts.map +1 -1
  7. package/node/lib/Consumer.js +1 -1
  8. package/node/lib/DataConsumer.d.ts +4 -4
  9. package/node/lib/DataConsumer.d.ts.map +1 -1
  10. package/node/lib/DataConsumer.js +1 -1
  11. package/node/lib/DataProducer.d.ts +4 -4
  12. package/node/lib/DataProducer.d.ts.map +1 -1
  13. package/node/lib/DataProducer.js +1 -1
  14. package/node/lib/DirectTransport.d.ts +1 -1
  15. package/node/lib/DirectTransport.d.ts.map +1 -1
  16. package/node/lib/PipeTransport.d.ts +2 -2
  17. package/node/lib/PipeTransport.d.ts.map +1 -1
  18. package/node/lib/PipeTransport.js +1 -1
  19. package/node/lib/PlainTransport.d.ts +1 -1
  20. package/node/lib/PlainTransport.d.ts.map +1 -1
  21. package/node/lib/Producer.d.ts +4 -4
  22. package/node/lib/Producer.d.ts.map +1 -1
  23. package/node/lib/Producer.js +1 -1
  24. package/node/lib/Router.d.ts +4 -4
  25. package/node/lib/Router.d.ts.map +1 -1
  26. package/node/lib/Router.js +7 -7
  27. package/node/lib/RtpObserver.d.ts +3 -3
  28. package/node/lib/RtpObserver.d.ts.map +1 -1
  29. package/node/lib/RtpObserver.js +1 -1
  30. package/node/lib/Transport.d.ts +3 -3
  31. package/node/lib/Transport.d.ts.map +1 -1
  32. package/node/lib/Transport.js +5 -5
  33. package/node/lib/WebRtcTransport.d.ts +1 -1
  34. package/node/lib/WebRtcTransport.d.ts.map +1 -1
  35. package/node/lib/Worker.d.ts +3 -3
  36. package/node/lib/Worker.d.ts.map +1 -1
  37. package/node/lib/Worker.js +3 -3
  38. package/node/lib/index.d.ts +1 -1
  39. package/node/lib/index.d.ts.map +1 -1
  40. package/node/lib/index.js +2 -2
  41. package/node/lib/ortc.js +1 -0
  42. package/node/lib/supportedRtpCapabilities.d.ts.map +1 -1
  43. package/node/lib/supportedRtpCapabilities.js +15 -0
  44. package/package.json +6 -6
  45. package/worker/include/RTC/Codecs/H264_SVC.hpp +115 -0
  46. package/worker/include/RTC/Codecs/Tools.hpp +11 -0
  47. package/worker/include/RTC/Consumer.hpp +5 -4
  48. package/worker/include/RTC/DirectTransport.hpp +4 -0
  49. package/worker/include/RTC/NackGenerator.hpp +5 -2
  50. package/worker/include/RTC/PipeConsumer.hpp +1 -0
  51. package/worker/include/RTC/RTCP/CompoundPacket.hpp +2 -0
  52. package/worker/include/RTC/RtpDictionaries.hpp +1 -0
  53. package/worker/include/RTC/RtpStream.hpp +2 -0
  54. package/worker/include/RTC/RtpStreamRecv.hpp +7 -1
  55. package/worker/include/RTC/RtpStreamSend.hpp +7 -0
  56. package/worker/include/RTC/SimpleConsumer.hpp +1 -0
  57. package/worker/include/RTC/SimulcastConsumer.hpp +4 -0
  58. package/worker/include/RTC/SvcConsumer.hpp +1 -0
  59. package/worker/meson.build +4 -0
  60. package/worker/src/RTC/Codecs/H264_SVC.cpp +428 -0
  61. package/worker/src/RTC/DirectTransport.cpp +10 -1
  62. package/worker/src/RTC/NackGenerator.cpp +27 -9
  63. package/worker/src/RTC/PipeConsumer.cpp +20 -0
  64. package/worker/src/RTC/Producer.cpp +5 -1
  65. package/worker/src/RTC/RTCP/CompoundPacket.cpp +7 -0
  66. package/worker/src/RTC/RtpDictionaries/RtpCodecMimeType.cpp +2 -0
  67. package/worker/src/RTC/RtpStreamRecv.cpp +4 -3
  68. package/worker/src/RTC/RtpStreamSend.cpp +32 -0
  69. package/worker/src/RTC/SimpleConsumer.cpp +17 -0
  70. package/worker/src/RTC/SimulcastConsumer.cpp +45 -4
  71. package/worker/src/RTC/SvcConsumer.cpp +17 -0
  72. package/worker/src/RTC/Transport.cpp +14 -0
  73. package/worker/src/RTC/TransportCongestionControlClient.cpp +0 -3
  74. package/worker/test/include/helpers.hpp +119 -0
  75. package/worker/test/src/RTC/Codecs/TestH264.cpp +30 -0
  76. package/worker/test/src/RTC/Codecs/TestH264_SVC.cpp +181 -0
  77. package/worker/test/src/RTC/TestNackGenerator.cpp +3 -1
  78. package/worker/test/src/RTC/TestRtpPacketH264Svc.cpp +455 -0
  79. package/worker/test/src/RTC/TestRtpStreamRecv.cpp +4 -3
@@ -0,0 +1,428 @@
1
+ #define MS_CLASS "RTC::Codecs::H264_SVC"
2
+
3
+ #include "RTC/Codecs/H264_SVC.hpp"
4
+ #include "Logger.hpp"
5
+ #include "Utils.hpp"
6
+
7
+ namespace RTC
8
+ {
9
+ namespace Codecs
10
+ {
11
+ /* Class methods. */
12
+
13
+ H264_SVC::PayloadDescriptor* H264_SVC::Parse(
14
+ const uint8_t* data, size_t len, RTC::RtpPacket::FrameMarking* frameMarking, uint8_t frameMarkingLen)
15
+ {
16
+ MS_TRACE();
17
+
18
+ if (len < 2)
19
+ return nullptr;
20
+
21
+ std::unique_ptr<PayloadDescriptor> payloadDescriptor(new PayloadDescriptor());
22
+
23
+ // Use frame-marking.
24
+ if (frameMarking)
25
+ {
26
+ // Read fields.
27
+ payloadDescriptor->s = frameMarking->start;
28
+ payloadDescriptor->e = frameMarking->end;
29
+ payloadDescriptor->i = frameMarking->independent;
30
+ payloadDescriptor->d = frameMarking->discardable;
31
+ payloadDescriptor->b = frameMarking->base;
32
+ payloadDescriptor->tlIndex = frameMarking->tid;
33
+
34
+ payloadDescriptor->hasTlIndex = true;
35
+
36
+ if (frameMarkingLen >= 2)
37
+ {
38
+ payloadDescriptor->hasSlIndex = true;
39
+ payloadDescriptor->slIndex = frameMarking->lid >> 4 & 0x07;
40
+ }
41
+
42
+ if (frameMarkingLen == 3)
43
+ {
44
+ payloadDescriptor->hasTl0picidx = true;
45
+ payloadDescriptor->tl0picidx = frameMarking->tl0picidx;
46
+ }
47
+
48
+ // Detect key frame.
49
+ if (frameMarking->start && frameMarking->independent)
50
+ payloadDescriptor->isKeyFrame = true;
51
+ }
52
+
53
+ // NOTE: Unfortunately libwebrtc produces wrong Frame-Marking (without i=1 in
54
+ // keyframes) when it uses H264 hardware encoder (at least in Mac):
55
+ // https://bugs.chromium.org/p/webrtc/issues/detail?id=10746
56
+ //
57
+ // As a temporal workaround, always do payload parsing to detect keyframes if
58
+ // there is no frame-marking or if there is but keyframe was not detected above.
59
+ if (!frameMarking || !payloadDescriptor->isKeyFrame)
60
+ {
61
+ uint8_t nal = *data & 0x1F;
62
+
63
+ switch (nal)
64
+ {
65
+ // Single NAL unit packet.
66
+ // IDR (instantaneous decoding picture).
67
+ case 1:
68
+ case 5:
69
+ case 7:
70
+ case 14:
71
+ case 20:
72
+ {
73
+ payloadDescriptor =
74
+ H264_SVC::ParseSingleNalu(data, len, std::move(payloadDescriptor), true);
75
+
76
+ if (payloadDescriptor == nullptr)
77
+ return nullptr;
78
+
79
+ break;
80
+ }
81
+
82
+ // Aggreation packet.
83
+ // STAP-A.
84
+ case 24:
85
+ {
86
+ size_t offset{ 1 };
87
+
88
+ len -= 1;
89
+
90
+ // Iterate NAL units.
91
+ while (len >= 3)
92
+ {
93
+ auto naluSize = Utils::Byte::Get2Bytes(data, offset);
94
+
95
+ payloadDescriptor = H264_SVC::ParseSingleNalu(
96
+ (data + offset + sizeof(naluSize)),
97
+ (len - sizeof(naluSize)),
98
+ std::move(payloadDescriptor),
99
+ true);
100
+ if (payloadDescriptor == nullptr)
101
+ return nullptr;
102
+
103
+ if (payloadDescriptor->isKeyFrame)
104
+ {
105
+ break;
106
+ }
107
+
108
+ // Check if there is room for the indicated NAL unit size.
109
+ if (len < (naluSize + sizeof(naluSize)))
110
+ break;
111
+
112
+ offset += naluSize + sizeof(naluSize);
113
+ len -= naluSize + sizeof(naluSize);
114
+ }
115
+
116
+ break;
117
+ }
118
+
119
+ // Aggreation packet.
120
+ // FU-A, FU-B.
121
+ case 28:
122
+ case 29:
123
+ {
124
+ uint8_t startBit = *(data + 1) & 0x80;
125
+
126
+ if (startBit == 128)
127
+ {
128
+ payloadDescriptor = H264_SVC::ParseSingleNalu(
129
+ (data + 1), (len - 1), std::move(payloadDescriptor), (startBit == 128 ? true : false));
130
+ }
131
+ if (payloadDescriptor == nullptr)
132
+ return nullptr;
133
+
134
+ break;
135
+ }
136
+ }
137
+ }
138
+
139
+ return payloadDescriptor.release();
140
+ }
141
+
142
+ std::unique_ptr<H264_SVC::PayloadDescriptor> H264_SVC::ParseSingleNalu(
143
+ const uint8_t* data,
144
+ size_t len,
145
+ std::unique_ptr<H264_SVC::PayloadDescriptor> payloadDescriptor,
146
+ bool isStartBit)
147
+ {
148
+ uint8_t nal = *data & 0x1F;
149
+
150
+ switch (nal)
151
+ {
152
+ // Single NAL unit packet.
153
+ // IDR (instantaneous decoding picture).
154
+ case 5:
155
+ payloadDescriptor->isKeyFrame = true;
156
+ case 1:
157
+ {
158
+ payloadDescriptor->slIndex = 0;
159
+ payloadDescriptor->tlIndex = 0;
160
+
161
+ payloadDescriptor->hasSlIndex = false;
162
+ payloadDescriptor->hasTlIndex = false;
163
+
164
+ break;
165
+ }
166
+ case 14:
167
+ case 20:
168
+ {
169
+ size_t offset{ 1 };
170
+ uint8_t byte = data[offset];
171
+
172
+ payloadDescriptor->idr = byte >> 6 & 0x01;
173
+ payloadDescriptor->priorityId = byte & 0x06;
174
+ payloadDescriptor->isKeyFrame = (isStartBit && payloadDescriptor->idr) ? true : false;
175
+
176
+ if (len < ++offset + 1)
177
+ return nullptr;
178
+
179
+ byte = data[offset];
180
+ payloadDescriptor->noIntLayerPredFlag = byte >> 7 & 0x01;
181
+ payloadDescriptor->slIndex = byte >> 4 & 0x03;
182
+
183
+ if (len < ++offset + 1)
184
+ return nullptr;
185
+
186
+ byte = data[offset];
187
+
188
+ payloadDescriptor->tlIndex = byte >> 5 & 0x03;
189
+
190
+ payloadDescriptor->hasSlIndex = payloadDescriptor->slIndex ? true : false;
191
+ payloadDescriptor->hasTlIndex = payloadDescriptor->tlIndex ? true : false;
192
+
193
+ break;
194
+ }
195
+ case 7:
196
+ {
197
+ payloadDescriptor->isKeyFrame = isStartBit ? true : false;
198
+
199
+ break;
200
+ }
201
+ }
202
+ return payloadDescriptor;
203
+ }
204
+
205
+ void H264_SVC::ProcessRtpPacket(RTC::RtpPacket* packet)
206
+ {
207
+ MS_TRACE();
208
+
209
+ auto* data = packet->GetPayload();
210
+ auto len = packet->GetPayloadLength();
211
+ RtpPacket::FrameMarking* frameMarking{ nullptr };
212
+ uint8_t frameMarkingLen{ 0 };
213
+
214
+ // Read frame-marking.
215
+ packet->ReadFrameMarking(&frameMarking, frameMarkingLen);
216
+
217
+ PayloadDescriptor* payloadDescriptor =
218
+ H264_SVC::Parse(data, len, frameMarking, frameMarkingLen);
219
+
220
+ if (!payloadDescriptor)
221
+ return;
222
+
223
+ auto* payloadDescriptorHandler = new PayloadDescriptorHandler(payloadDescriptor);
224
+
225
+ packet->SetPayloadDescriptorHandler(payloadDescriptorHandler);
226
+ }
227
+
228
+ /* Instance methods. */
229
+
230
+ void H264_SVC::PayloadDescriptor::Dump() const
231
+ {
232
+ MS_TRACE();
233
+
234
+ MS_DUMP("<PayloadDescriptor>");
235
+ MS_DUMP(
236
+ " s:%" PRIu8 "|e:%" PRIu8 "|i:%" PRIu8 "|d:%" PRIu8 "|b:%" PRIu8,
237
+ this->s,
238
+ this->e,
239
+ this->i,
240
+ this->d,
241
+ this->b);
242
+ MS_DUMP(" hasSlIndex : %s", this->hasSlIndex ? "true" : "false");
243
+ MS_DUMP(" hasTlIndex : %s", this->hasTlIndex ? "true" : "false");
244
+ MS_DUMP(" tl0picidx : %" PRIu8, this->tl0picidx);
245
+ MS_DUMP(" noIntLayerPredFlag : %" PRIu8, this->noIntLayerPredFlag);
246
+ MS_DUMP(" isKeyFrame : %s", this->isKeyFrame ? "true" : "false");
247
+ MS_DUMP("</PayloadDescriptor>");
248
+ }
249
+
250
+ H264_SVC::PayloadDescriptorHandler::PayloadDescriptorHandler(
251
+ H264_SVC::PayloadDescriptor* payloadDescriptor)
252
+ {
253
+ MS_TRACE();
254
+
255
+ this->payloadDescriptor.reset(payloadDescriptor);
256
+ }
257
+
258
+ bool H264_SVC::PayloadDescriptorHandler::Process(
259
+ RTC::Codecs::EncodingContext* encodingContext, uint8_t* /*data*/, bool& marker)
260
+ {
261
+ MS_TRACE();
262
+
263
+ auto* context = static_cast<RTC::Codecs::H264_SVC::EncodingContext*>(encodingContext);
264
+
265
+ MS_ASSERT(context->GetTargetSpatialLayer() >= 0, "target spatial layer cannot be -1");
266
+ MS_ASSERT(context->GetTargetTemporalLayer() >= 0, "target temporal layer cannot be -1");
267
+
268
+ auto packetSpatialLayer = GetSpatialLayer();
269
+ auto packetTemporalLayer = GetTemporalLayer();
270
+ auto tmpSpatialLayer = context->GetCurrentSpatialLayer();
271
+ auto tmpTemporalLayer = context->GetCurrentTemporalLayer();
272
+
273
+ // If packet spatial or temporal layer is higher than maximum announced
274
+ // one, drop the packet.
275
+ // clang-format off
276
+ if (
277
+ packetSpatialLayer >= context->GetSpatialLayers() ||
278
+ packetTemporalLayer >= context->GetTemporalLayers()
279
+ )
280
+ // clang-format on
281
+ {
282
+ MS_WARN_TAG(
283
+ rtp, "too high packet layers %" PRIu8 ":%" PRIu8, packetSpatialLayer, packetTemporalLayer);
284
+
285
+ return false;
286
+ }
287
+
288
+ // clang-format off
289
+ bool isOldPacket = false;
290
+
291
+ // Upgrade current spatial layer if needed.
292
+ if (context->GetTargetSpatialLayer() > context->GetCurrentSpatialLayer())
293
+ {
294
+ if (this->payloadDescriptor->isKeyFrame)
295
+ {
296
+ MS_DEBUG_DEV(
297
+ "upgrading tmpSpatialLayer from %" PRIu16 " to %" PRIu16 " (packet:%" PRIu8 ":%" PRIu8
298
+ ")",
299
+ context->GetCurrentSpatialLayer(),
300
+ context->GetTargetSpatialLayer(),
301
+ packetSpatialLayer,
302
+ packetTemporalLayer);
303
+
304
+ tmpSpatialLayer = context->GetTargetSpatialLayer();
305
+ tmpTemporalLayer = 0; // Just in case.
306
+ }
307
+ }
308
+ // Downgrade current spatial layer if needed.
309
+ else if (context->GetTargetSpatialLayer() < context->GetCurrentSpatialLayer())
310
+ {
311
+ // In K-SVC we must wait for a keyframe.
312
+ if (context->IsKSvc())
313
+ {
314
+ if (this->payloadDescriptor->isKeyFrame)
315
+ // clang-format on
316
+ {
317
+ MS_DEBUG_DEV(
318
+ "downgrading tmpSpatialLayer from %" PRIu16 " to %" PRIu16 " (packet:%" PRIu8
319
+ ":%" PRIu8 ") after keyframe (K-SVC)",
320
+ context->GetCurrentSpatialLayer(),
321
+ context->GetTargetSpatialLayer(),
322
+ packetSpatialLayer,
323
+ packetTemporalLayer);
324
+
325
+ tmpSpatialLayer = context->GetTargetSpatialLayer();
326
+ tmpTemporalLayer = 0; // Just in case.
327
+ }
328
+ }
329
+ // In full SVC we do not need a keyframe.
330
+ else
331
+ {
332
+ // clang-format off
333
+ if (
334
+ packetSpatialLayer == context->GetTargetSpatialLayer() &&
335
+ this->payloadDescriptor->e
336
+ )
337
+ // clang-format on
338
+ {
339
+ MS_DEBUG_DEV(
340
+ "downgrading tmpSpatialLayer from %" PRIu16 " to %" PRIu16 " (packet:%" PRIu8
341
+ ":%" PRIu8 ") without keyframe (full SVC)",
342
+ context->GetCurrentSpatialLayer(),
343
+ context->GetTargetSpatialLayer(),
344
+ packetSpatialLayer,
345
+ packetTemporalLayer);
346
+
347
+ tmpSpatialLayer = context->GetTargetSpatialLayer();
348
+ tmpTemporalLayer = 0; // Just in case.
349
+ }
350
+ }
351
+ }
352
+
353
+ // Filter spatial layers higher than current one (unless old packet).
354
+ if (packetSpatialLayer > tmpSpatialLayer && !isOldPacket)
355
+ return false;
356
+
357
+ // Check and handle temporal layer (unless old packet).
358
+ if (!isOldPacket)
359
+ {
360
+ // Upgrade current temporal layer if needed.
361
+ if (context->GetTargetTemporalLayer() > context->GetCurrentTemporalLayer())
362
+ {
363
+ // clang-format off
364
+ if (
365
+ packetTemporalLayer >= context->GetCurrentTemporalLayer() + 1 &&
366
+ this->payloadDescriptor->s
367
+ )
368
+ // clang-format on
369
+ {
370
+ MS_DEBUG_DEV(
371
+ "upgrading tmpTemporalLayer from %" PRIu16 " to %" PRIu8 " (packet:%" PRIu8 ":%" PRIu8
372
+ ")",
373
+ context->GetCurrentTemporalLayer(),
374
+ packetTemporalLayer,
375
+ packetSpatialLayer,
376
+ packetTemporalLayer);
377
+
378
+ tmpTemporalLayer = packetTemporalLayer;
379
+ }
380
+ }
381
+ // Downgrade current temporal layer if needed.
382
+ else if (context->GetTargetTemporalLayer() < context->GetCurrentTemporalLayer())
383
+ {
384
+ // clang-format off
385
+ if (
386
+ packetTemporalLayer == context->GetTargetTemporalLayer() &&
387
+ this->payloadDescriptor->e
388
+ )
389
+ // clang-format on
390
+ {
391
+ MS_DEBUG_DEV(
392
+ "downgrading tmpTemporalLayer from %" PRIu16 " to %" PRIu16 " (packet:%" PRIu8
393
+ ":%" PRIu8 ")",
394
+ context->GetCurrentTemporalLayer(),
395
+ context->GetTargetTemporalLayer(),
396
+ packetSpatialLayer,
397
+ packetTemporalLayer);
398
+
399
+ tmpTemporalLayer = context->GetTargetTemporalLayer();
400
+ }
401
+ }
402
+
403
+ // Filter temporal layers higher than current one.
404
+ if (packetTemporalLayer > tmpTemporalLayer)
405
+ return false;
406
+ }
407
+
408
+ // Set marker bit if needed.
409
+ if (packetSpatialLayer == tmpSpatialLayer && this->payloadDescriptor->e)
410
+ marker = true;
411
+
412
+ // Update current spatial layer if needed.
413
+ if (tmpSpatialLayer != context->GetCurrentSpatialLayer())
414
+ context->SetCurrentSpatialLayer(tmpSpatialLayer);
415
+
416
+ // Update current temporal layer if needed.
417
+ if (tmpTemporalLayer != context->GetCurrentTemporalLayer())
418
+ context->SetCurrentTemporalLayer(tmpTemporalLayer);
419
+
420
+ return true;
421
+ }
422
+
423
+ void H264_SVC::PayloadDescriptorHandler::Restore(uint8_t* /*data*/)
424
+ {
425
+ MS_TRACE();
426
+ }
427
+ } // namespace Codecs
428
+ } // namespace RTC
@@ -20,6 +20,8 @@ namespace RTC
20
20
  DirectTransport::~DirectTransport()
21
21
  {
22
22
  MS_TRACE();
23
+
24
+ delete[] this->buffer;
23
25
  }
24
26
 
25
27
  void DirectTransport::FillJson(json& jsonObject) const
@@ -102,7 +104,14 @@ namespace RTC
102
104
  return;
103
105
  }
104
106
 
105
- RTC::RtpPacket* packet = RTC::RtpPacket::Parse(data, len);
107
+ // If this is the first time to reveive a RTP packet then allocate the receiving buffer now.
108
+ if (!this->buffer)
109
+ this->buffer = new uint8_t[RTC::MtuSize + 100];
110
+
111
+ // Copy the received packet into this buffer so it can be expanded later.
112
+ std::memcpy(this->buffer, data, static_cast<size_t>(len));
113
+
114
+ RTC::RtpPacket* packet = RTC::RtpPacket::Parse(this->buffer, len);
106
115
 
107
116
  if (!packet)
108
117
  {
@@ -12,15 +12,16 @@ namespace RTC
12
12
  {
13
13
  /* Static. */
14
14
 
15
- constexpr size_t MaxPacketAge{ 10000u };
16
- constexpr size_t MaxNackPackets{ 1000u };
17
- constexpr uint32_t DefaultRtt{ 100u };
18
- constexpr uint8_t MaxNackRetries{ 10u };
19
- constexpr uint64_t TimerInterval{ 40u };
15
+ static constexpr size_t MaxPacketAge{ 10000u };
16
+ static constexpr size_t MaxNackPackets{ 1000u };
17
+ static constexpr uint32_t DefaultRtt{ 100u };
18
+ static constexpr uint8_t MaxNackRetries{ 10u };
19
+ static constexpr uint64_t TimerInterval{ 40u };
20
20
 
21
21
  /* Instance methods. */
22
22
 
23
- NackGenerator::NackGenerator(Listener* listener) : listener(listener), rtt(DefaultRtt)
23
+ NackGenerator::NackGenerator(Listener* listener, unsigned int sendNackDelayMs)
24
+ : listener(listener), sendNackDelayMs(sendNackDelayMs), rtt(DefaultRtt)
24
25
  {
25
26
  MS_TRACE();
26
27
 
@@ -74,9 +75,14 @@ namespace RTC
74
75
  packet->GetSequenceNumber(),
75
76
  isRecovered ? "true" : "false");
76
77
 
78
+ auto retries = it->second.retries;
79
+
77
80
  this->nackList.erase(it);
78
81
 
79
- return true;
82
+ if (retries != 0)
83
+ return true;
84
+ else
85
+ return false;
80
86
  }
81
87
 
82
88
  // Out of order packet or already handled NACKed packet.
@@ -183,7 +189,13 @@ namespace RTC
183
189
  if (this->recoveredList.find(seq) != this->recoveredList.end())
184
190
  continue;
185
191
 
186
- this->nackList.emplace(std::make_pair(seq, NackInfo{ seq, seq }));
192
+ this->nackList.emplace(std::make_pair(
193
+ seq,
194
+ NackInfo{
195
+ DepLibUV::GetTimeMs(),
196
+ seq,
197
+ seq,
198
+ }));
187
199
  }
188
200
  }
189
201
 
@@ -226,6 +238,12 @@ namespace RTC
226
238
  NackInfo& nackInfo = it->second;
227
239
  uint16_t seq = nackInfo.seq;
228
240
 
241
+ if (this->sendNackDelayMs > 0 && nowMs - nackInfo.createdAtMs < this->sendNackDelayMs)
242
+ {
243
+ ++it;
244
+ continue;
245
+ }
246
+
229
247
  // clang-format off
230
248
  if (
231
249
  filter == NackFilter::SEQ &&
@@ -259,7 +277,7 @@ namespace RTC
259
277
  continue;
260
278
  }
261
279
 
262
- if (filter == NackFilter::TIME && nowMs - nackInfo.sentAtMs >= this->rtt)
280
+ if (filter == NackFilter::TIME && (nackInfo.sentAtMs == 0 || nowMs - nackInfo.sentAtMs >= this->rtt))
263
281
  {
264
282
  nackBatch.emplace_back(seq);
265
283
  nackInfo.retries++;
@@ -312,6 +312,16 @@ namespace RTC
312
312
 
313
313
  packet->AddSdesChunk(sdesChunk);
314
314
 
315
+ auto* dlrr = rtpStream->GetRtcpXrDelaySinceLastRr(nowMs);
316
+
317
+ if (dlrr)
318
+ {
319
+ auto* report = new RTC::RTCP::DelaySinceLastRr();
320
+
321
+ report->AddSsrcInfo(dlrr);
322
+ packet->AddDelaySinceLastRr(report);
323
+ }
324
+
315
325
  this->lastRtcpSentTime = nowMs;
316
326
  }
317
327
 
@@ -388,6 +398,16 @@ namespace RTC
388
398
  rtpStream->ReceiveRtcpReceiverReport(report);
389
399
  }
390
400
 
401
+ void PipeConsumer::ReceiveRtcpXrReceiverReferenceTime(RTC::RTCP::ReceiverReferenceTime* report)
402
+ {
403
+ MS_TRACE();
404
+
405
+ for (auto* rtpStream : this->rtpStreams)
406
+ {
407
+ rtpStream->ReceiveRtcpXrReceiverReferenceTime(report);
408
+ }
409
+ }
410
+
391
411
  uint32_t PipeConsumer::GetTransmissionRate(uint64_t nowMs)
392
412
  {
393
413
  MS_TRACE();
@@ -18,6 +18,10 @@
18
18
 
19
19
  namespace RTC
20
20
  {
21
+ /* Static. */
22
+
23
+ static constexpr unsigned int SendNackDelay{ 10u }; // In ms.
24
+
21
25
  /* Instance methods. */
22
26
 
23
27
  Producer::Producer(const std::string& id, RTC::Producer::Listener* listener, json& data)
@@ -1139,7 +1143,7 @@ namespace RTC
1139
1143
  }
1140
1144
 
1141
1145
  // Create a RtpStreamRecv for receiving a media stream.
1142
- auto* rtpStream = new RTC::RtpStreamRecv(this, params);
1146
+ auto* rtpStream = new RTC::RtpStreamRecv(this, params, SendNackDelay);
1143
1147
 
1144
1148
  // Insert into the maps.
1145
1149
  this->mapSsrcRtpStream[ssrc] = rtpStream;
@@ -145,5 +145,12 @@ namespace RTC
145
145
 
146
146
  this->xrPacket.AddReport(report);
147
147
  }
148
+
149
+ void CompoundPacket::AddDelaySinceLastRr(DelaySinceLastRr* report)
150
+ {
151
+ MS_TRACE();
152
+
153
+ this->xrPacket.AddReport(report);
154
+ }
148
155
  } // namespace RTCP
149
156
  } // namespace RTC
@@ -36,6 +36,7 @@ namespace RTC
36
36
  { "vp8", RtpCodecMimeType::Subtype::VP8 },
37
37
  { "vp9", RtpCodecMimeType::Subtype::VP9 },
38
38
  { "h264", RtpCodecMimeType::Subtype::H264 },
39
+ { "h264-svc", RtpCodecMimeType::Subtype::H264_SVC },
39
40
  { "x-h264uc", RtpCodecMimeType::Subtype::X_H264UC },
40
41
  { "h265", RtpCodecMimeType::Subtype::H265 },
41
42
  // Complementary codecs:
@@ -63,6 +64,7 @@ namespace RTC
63
64
  { RtpCodecMimeType::Subtype::VP8, "VP8" },
64
65
  { RtpCodecMimeType::Subtype::VP9, "VP9" },
65
66
  { RtpCodecMimeType::Subtype::H264, "H264" },
67
+ { RtpCodecMimeType::Subtype::H264_SVC, "H264-SVC" },
66
68
  { RtpCodecMimeType::Subtype::X_H264UC, "X-H264UC" },
67
69
  { RtpCodecMimeType::Subtype::H265, "H265" },
68
70
  // Complementary codecs:
@@ -182,15 +182,16 @@ namespace RTC
182
182
 
183
183
  /* Instance methods. */
184
184
 
185
- RtpStreamRecv::RtpStreamRecv(RTC::RtpStreamRecv::Listener* listener, RTC::RtpStream::Params& params)
186
- : RTC::RtpStream::RtpStream(listener, params, 10),
185
+ RtpStreamRecv::RtpStreamRecv(
186
+ RTC::RtpStreamRecv::Listener* listener, RTC::RtpStream::Params& params, unsigned int sendNackDelayMs)
187
+ : RTC::RtpStream::RtpStream(listener, params, 10), sendNackDelayMs(sendNackDelayMs),
187
188
  transmissionCounter(
188
189
  params.spatialLayers, params.temporalLayers, this->params.useDtx ? 6000 : 2500)
189
190
  {
190
191
  MS_TRACE();
191
192
 
192
193
  if (this->params.useNack)
193
- this->nackGenerator.reset(new RTC::NackGenerator(this));
194
+ this->nackGenerator.reset(new RTC::NackGenerator(this, this->sendNackDelayMs));
194
195
 
195
196
  // Run the RTP inactivity periodic timer (use a different timeout if DTX is
196
197
  // enabled).
@@ -186,6 +186,15 @@ namespace RTC
186
186
  UpdateScore(report);
187
187
  }
188
188
 
189
+ void RtpStreamSend::ReceiveRtcpXrReceiverReferenceTime(RTC::RTCP::ReceiverReferenceTime* report)
190
+ {
191
+ MS_TRACE();
192
+
193
+ this->lastRrReceivedMs = DepLibUV::GetTimeMs();
194
+ this->lastRrTimestamp = report->GetNtpSec() << 16;
195
+ this->lastRrTimestamp += report->GetNtpFrac() >> 16;
196
+ }
197
+
189
198
  RTC::RTCP::SenderReport* RtpStreamSend::GetRtcpSenderReport(uint64_t nowMs)
190
199
  {
191
200
  MS_TRACE();
@@ -214,6 +223,29 @@ namespace RTC
214
223
  return report;
215
224
  }
216
225
 
226
+ RTC::RTCP::DelaySinceLastRr::SsrcInfo* RtpStreamSend::GetRtcpXrDelaySinceLastRr(uint64_t nowMs)
227
+ {
228
+ MS_TRACE();
229
+
230
+ if (this->lastRrReceivedMs == 0u)
231
+ return nullptr;
232
+
233
+ // Get delay in milliseconds.
234
+ auto delayMs = static_cast<uint32_t>(nowMs - this->lastRrReceivedMs);
235
+ // Express delay in units of 1/65536 seconds.
236
+ uint32_t dlrr = (delayMs / 1000) << 16;
237
+
238
+ dlrr |= uint32_t{ (delayMs % 1000) * 65536 / 1000 };
239
+
240
+ auto* ssrcInfo = new RTC::RTCP::DelaySinceLastRr::SsrcInfo();
241
+
242
+ ssrcInfo->SetSsrc(GetSsrc());
243
+ ssrcInfo->SetDelaySinceLastReceiverReport(dlrr);
244
+ ssrcInfo->SetLastReceiverReport(this->lastRrTimestamp);
245
+
246
+ return ssrcInfo;
247
+ }
248
+
217
249
  RTC::RTCP::SdesChunk* RtpStreamSend::GetRtcpSdesChunk()
218
250
  {
219
251
  MS_TRACE();