mediasoup 3.13.3 → 3.13.5

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/node/lib/ortc.js CHANGED
@@ -656,7 +656,7 @@ function getConsumableRtpParameters(kind, params, caps, rtpMapping) {
656
656
  payloadType: matchedCapCodec.preferredPayloadType,
657
657
  clockRate: matchedCapCodec.clockRate,
658
658
  channels: matchedCapCodec.channels,
659
- parameters: codec.parameters,
659
+ parameters: codec.parameters, // Keep the Producer codec parameters.
660
660
  rtcpFeedback: matchedCapCodec.rtcpFeedback
661
661
  };
662
662
  consumableParams.codecs.push(consumableCodec);
@@ -185,13 +185,13 @@ const consumerDeviceCapabilities = {
185
185
  },
186
186
  {
187
187
  kind: 'audio',
188
- uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time',
188
+ uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time', // eslint-disable-line max-len
189
189
  preferredId: 4,
190
190
  preferredEncrypt: false
191
191
  },
192
192
  {
193
193
  kind: 'video',
194
- uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time',
194
+ uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time', // eslint-disable-line max-len
195
195
  preferredId: 4,
196
196
  preferredEncrypt: false
197
197
  },
@@ -73,7 +73,7 @@ const consumerDeviceCapabilities = {
73
73
  },
74
74
  {
75
75
  kind: 'audio',
76
- uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time',
76
+ uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time', // eslint-disable-line max-len
77
77
  preferredId: 4,
78
78
  preferredEncrypt: false
79
79
  },
@@ -19,8 +19,8 @@ beforeAll(async () => {
19
19
  worker = await mediasoup.createWorker();
20
20
  router = await worker.createRouter();
21
21
  transport = await router.createPlainTransport({
22
- listenIp: '127.0.0.1',
23
- comedia: true,
22
+ listenIp: '127.0.0.1', // https://github.com/nodejs/node/issues/14900
23
+ comedia: true, // So we don't need to call transport.connect().
24
24
  enableSctp: true,
25
25
  numSctpStreams: { OS: 256, MIS: 256 }
26
26
  });
@@ -40,8 +40,8 @@ beforeAll(async () => {
40
40
  return;
41
41
  }
42
42
  sctpSocket = sctp.connect({
43
- localPort: 5000,
44
- port: 5000,
43
+ localPort: 5000, // Required for SCTP over UDP in mediasoup.
44
+ port: 5000, // Required for SCTP over UDP in mediasoup.
45
45
  OS: OS,
46
46
  MIS: MIS,
47
47
  udpTransport: udpSocket
@@ -53,8 +53,8 @@ beforeAll(async () => {
53
53
  // Use UDP disconnected socket if Node < 12.
54
54
  else {
55
55
  sctpSocket = sctp.connect({
56
- localPort: 5000,
57
- port: 5000,
56
+ localPort: 5000, // Required for SCTP over UDP in mediasoup.
57
+ port: 5000, // Required for SCTP over UDP in mediasoup.
58
58
  OS: OS,
59
59
  MIS: MIS,
60
60
  udpTransport: udpSocket,
@@ -17,7 +17,7 @@ test('generateRouterRtpCapabilities() succeeds', () => {
17
17
  {
18
18
  kind: 'video',
19
19
  mimeType: 'video/VP8',
20
- preferredPayloadType: 125,
20
+ preferredPayloadType: 125, // Let's force it.
21
21
  clockRate: 90000
22
22
  },
23
23
  {
@@ -38,7 +38,7 @@ test('generateRouterRtpCapabilities() succeeds', () => {
38
38
  expect(rtpCapabilities.codecs?.[0]).toEqual({
39
39
  kind: 'audio',
40
40
  mimeType: 'audio/opus',
41
- preferredPayloadType: 100,
41
+ preferredPayloadType: 100, // 100 is the first available dynamic PT.
42
42
  clockRate: 48000,
43
43
  channels: 2,
44
44
  parameters: {
@@ -69,7 +69,7 @@ test('generateRouterRtpCapabilities() succeeds', () => {
69
69
  expect(rtpCapabilities.codecs?.[2]).toEqual({
70
70
  kind: 'video',
71
71
  mimeType: 'video/rtx',
72
- preferredPayloadType: 101,
72
+ preferredPayloadType: 101, // 101 is the second available dynamic PT.
73
73
  clockRate: 90000,
74
74
  parameters: {
75
75
  apt: 125
@@ -80,7 +80,7 @@ test('generateRouterRtpCapabilities() succeeds', () => {
80
80
  expect(rtpCapabilities.codecs?.[3]).toEqual({
81
81
  kind: 'video',
82
82
  mimeType: 'video/H264',
83
- preferredPayloadType: 102,
83
+ preferredPayloadType: 102, // 102 is the third available dynamic PT.
84
84
  clockRate: 90000,
85
85
  parameters: {
86
86
  // Since packetization-mode param was not included in the H264 codec
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mediasoup",
3
- "version": "3.13.3",
3
+ "version": "3.13.5",
4
4
  "description": "Cutting Edge WebRTC Video Conferencing",
5
5
  "contributors": [
6
6
  "Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)",
@@ -26,7 +26,7 @@
26
26
  "worker/fuzzer/include",
27
27
  "worker/fuzzer/src",
28
28
  "worker/include",
29
- "worker/scripts/*.js",
29
+ "worker/scripts/*.mjs",
30
30
  "worker/scripts/*.json",
31
31
  "worker/scripts/*.py",
32
32
  "worker/scripts/*.sh",
@@ -105,10 +105,10 @@
105
105
  "devDependencies": {
106
106
  "@octokit/rest": "^20.0.2",
107
107
  "@types/debug": "^4.1.12",
108
- "@types/jest": "^29.5.8",
109
- "@types/node": "^20.9.2",
110
- "@typescript-eslint/eslint-plugin": "^6.11.0",
111
- "@typescript-eslint/parser": "^6.11.0",
108
+ "@types/jest": "^29.5.10",
109
+ "@types/node": "^20.9.4",
110
+ "@typescript-eslint/eslint-plugin": "^6.12.0",
111
+ "@typescript-eslint/parser": "^6.12.0",
112
112
  "eslint": "^8.54.0",
113
113
  "eslint-plugin-jest": "^27.6.0",
114
114
  "jest": "^29.7.0",
@@ -117,6 +117,6 @@
117
117
  "pick-port": "^1.0.1",
118
118
  "sctp": "^1.0.0",
119
119
  "ts-jest": "^29.1.1",
120
- "typescript": "^5.2.2"
120
+ "typescript": "^5.3.2"
121
121
  }
122
122
  }
package/worker/Makefile CHANGED
@@ -213,7 +213,7 @@ libmediasoup-worker: setup flatc
213
213
  flatc: setup
214
214
  $(MESON) compile -C $(BUILD_DIR) flatbuffers-generator
215
215
 
216
- xcode: setup
216
+ xcode: setup flatc
217
217
  $(MESON) setup --buildtype debug --backend xcode $(MEDIASOUP_OUT_DIR)/xcode
218
218
 
219
219
  lint:
@@ -234,7 +234,7 @@ else
234
234
  $(BUILD_DIR)/mediasoup-worker-test --invisibles --use-colour=yes $(MEDIASOUP_TEST_TAGS)
235
235
  endif
236
236
 
237
- test-asan: setup
237
+ test-asan: setup flatc
238
238
  $(MESON) compile -C $(BUILD_DIR) -j $(CORES) mediasoup-worker-test-asan
239
239
  $(MESON) install -C $(BUILD_DIR) --no-rebuild --tags mediasoup-worker-test-asan
240
240
  ASAN_OPTIONS=detect_leaks=1 $(BUILD_DIR)/mediasoup-worker-test-asan --invisibles --use-colour=yes $(MEDIASOUP_TEST_TAGS)
@@ -249,7 +249,7 @@ tidy:
249
249
  -checks=$(MEDIASOUP_TIDY_CHECKS) \
250
250
  -quiet
251
251
 
252
- fuzzer: setup
252
+ fuzzer: setup flatc
253
253
  $(MESON) compile -C $(BUILD_DIR) -j $(CORES) mediasoup-worker-fuzzer
254
254
  $(MESON) install -C $(BUILD_DIR) --no-rebuild --tags mediasoup-worker-fuzzer
255
255
 
@@ -289,6 +289,8 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
289
289
  if (payload_size > kMinProbePacketSize &&
290
290
  (!remote_rate_.ValidEstimate() ||
291
291
  now_ms - first_packet_time_ms_ < kInitialProbingIntervalMs)) {
292
+
293
+ #if MS_LOG_DEV_LEVEL == 3
292
294
  // TODO(holmer): Use a map instead to get correct order?
293
295
  if (total_probes_received_ < kMaxProbePackets) {
294
296
  int send_delta_ms = -1;
@@ -306,6 +308,8 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
306
308
  send_delta_ms,
307
309
  recv_delta_ms);
308
310
  }
311
+ #endif
312
+
309
313
  probes_.push_back(Probe(send_time_ms, arrival_time_ms, payload_size));
310
314
  ++total_probes_received_;
311
315
  // Make sure that a probe which updated the bitrate immediately has an
@@ -48,14 +48,16 @@ namespace RTC
48
48
  // Adds the given data and returns true if there is enough space to hold it,
49
49
  // false otherwise.
50
50
  bool Add(
51
- SenderReport* senderReport, SdesChunk* sdesChunk, DelaySinceLastRr* delaySinceLastRrReport);
51
+ SenderReport* senderReport,
52
+ SdesChunk* sdesChunk,
53
+ DelaySinceLastRr::SsrcInfo* delaySinceLastRrSsrcInfo);
52
54
  // RTCP additions per Consumer (pipe).
53
55
  // Adds the given data and returns true if there is enough space to hold it,
54
56
  // false otherwise.
55
57
  bool Add(
56
58
  std::vector<SenderReport*>& senderReports,
57
59
  std::vector<SdesChunk*>& sdesChunks,
58
- std::vector<DelaySinceLastRr*>& delaySinceLastRrReports);
60
+ std::vector<DelaySinceLastRr::SsrcInfo*>& delaySinceLastRrSsrcInfos);
59
61
  // RTCP additions per Producer.
60
62
  // Adds the given data and returns true if there is enough space to hold it,
61
63
  // false otherwise.
@@ -63,8 +65,6 @@ namespace RTC
63
65
  void AddSenderReport(SenderReport* report);
64
66
  void AddReceiverReport(ReceiverReport* report);
65
67
  void AddSdesChunk(SdesChunk* chunk);
66
- void AddReceiverReferenceTime(ReceiverReferenceTime* report);
67
- void AddDelaySinceLastRr(DelaySinceLastRr* report);
68
68
  bool HasSenderReport()
69
69
  {
70
70
  return this->senderReportPacket.Begin() != this->senderReportPacket.End();
@@ -77,6 +77,14 @@ namespace RTC
77
77
  [](const ExtendedReportBlock* report)
78
78
  { return report->GetType() == ExtendedReportBlock::Type::RRT; });
79
79
  }
80
+ bool HasDelaySinceLastRr()
81
+ {
82
+ return std::any_of(
83
+ this->xrPacket.Begin(),
84
+ this->xrPacket.End(),
85
+ [](const ExtendedReportBlock* report)
86
+ { return report->GetType() == ExtendedReportBlock::Type::DLRR; });
87
+ }
80
88
  void Serialize(uint8_t* data);
81
89
 
82
90
  private:
@@ -85,6 +93,7 @@ namespace RTC
85
93
  ReceiverReportPacket receiverReportPacket;
86
94
  SdesPacket sdesPacket;
87
95
  ExtendedReportPacket xrPacket;
96
+ DelaySinceLastRr* delaySinceLastRr{ nullptr };
88
97
  };
89
98
  } // namespace RTCP
90
99
  } // namespace RTC
@@ -214,7 +214,7 @@ namespace RTC
214
214
  // A serialized packet can contain a maximum of 31 chunks.
215
215
  // If number of chunks exceeds 31 then the required number of packets
216
216
  // will be serialized which will take the size calculated below.
217
- size_t size = Packet::CommonHeaderSize * ((this->GetCount() / MaxChunksPerPacket) + 1);
217
+ size_t size = Packet::CommonHeaderSize * ((this->GetCount() / (MaxChunksPerPacket + 1)) + 1);
218
218
 
219
219
  for (auto* chunk : this->chunks)
220
220
  {
@@ -119,6 +119,19 @@ namespace RTC
119
119
  {
120
120
  this->ssrcInfos.push_back(ssrcInfo);
121
121
  }
122
+ // NOTE: This method not only removes given number of ssrc info sub-blocks
123
+ // but also deletes their SsrcInfo instances.
124
+ void RemoveLastSsrcInfos(size_t number)
125
+ {
126
+ while (!this->ssrcInfos.empty() && number-- > 0)
127
+ {
128
+ auto* ssrcInfo = this->ssrcInfos.back();
129
+
130
+ this->ssrcInfos.pop_back();
131
+
132
+ delete ssrcInfo;
133
+ }
134
+ }
122
135
  Iterator Begin()
123
136
  {
124
137
  return this->ssrcInfos.begin();
@@ -37,7 +37,7 @@ namespace RTC
37
37
  void ReceiveRtcpReceiverReport(RTC::RTCP::ReceiverReport* report);
38
38
  void ReceiveRtcpXrReceiverReferenceTime(RTC::RTCP::ReceiverReferenceTime* report);
39
39
  RTC::RTCP::SenderReport* GetRtcpSenderReport(uint64_t nowMs);
40
- RTC::RTCP::DelaySinceLastRr::SsrcInfo* GetRtcpXrDelaySinceLastRr(uint64_t nowMs);
40
+ RTC::RTCP::DelaySinceLastRr::SsrcInfo* GetRtcpXrDelaySinceLastRrSsrcInfo(uint64_t nowMs);
41
41
  RTC::RTCP::SdesChunk* GetRtcpSdesChunk();
42
42
  void Pause() override;
43
43
  void Resume() override;
@@ -0,0 +1,89 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { glob } from 'glob';
3
+ import clangFormat from 'clang-format';
4
+
5
+ const task = process.argv.slice(2).join(' ');
6
+
7
+ run();
8
+
9
+ async function run()
10
+ {
11
+ const clangFormatNativeBinary = clangFormat.getNativeBinary();
12
+ const workerFiles = await glob(
13
+ [
14
+ '../src/**/*.cpp',
15
+ '../include/**/*.hpp',
16
+ '../test/src/**/*.cpp',
17
+ '../test/include/helpers.hpp',
18
+ '../fuzzer/src/**/*.cpp',
19
+ '../fuzzer/include/**/*.hpp'
20
+ ]
21
+ );
22
+
23
+ switch (task)
24
+ {
25
+ case 'lint':
26
+ {
27
+ executeCmd(
28
+ `${clangFormatNativeBinary} --Werror --dry-run ${workerFiles.join(' ')}`
29
+ );
30
+
31
+ break;
32
+ }
33
+
34
+ case 'format':
35
+ {
36
+ executeCmd(
37
+ `${clangFormatNativeBinary} --Werror -i ${workerFiles.join(' ')}`
38
+ );
39
+
40
+ break;
41
+ }
42
+
43
+ default:
44
+ {
45
+ logError('unknown task');
46
+
47
+ exitWithError();
48
+ }
49
+ }
50
+ }
51
+
52
+ function executeCmd(command)
53
+ {
54
+ try
55
+ {
56
+ execSync(command, { stdio: [ 'ignore', process.stdout, process.stderr ] });
57
+ }
58
+ catch (error)
59
+ {
60
+ logError('executeCmd() failed');
61
+
62
+ exitWithError();
63
+ }
64
+ }
65
+
66
+ // eslint-disable-next-line no-unused-vars
67
+ function logInfo(message)
68
+ {
69
+ // eslint-disable-next-line no-console
70
+ console.log(`clang-format.mjs \x1b[36m[INFO] [${task}]\x1b\[0m`, message);
71
+ }
72
+
73
+ // eslint-disable-next-line no-unused-vars
74
+ function logWarn(message)
75
+ {
76
+ // eslint-disable-next-line no-console
77
+ console.warn(`clang-format.mjs \x1b[33m[WARN] [${task}]\x1b\[0m`, message);
78
+ }
79
+
80
+ function logError(message)
81
+ {
82
+ // eslint-disable-next-line no-console
83
+ console.error(`clang-format.mjs \x1b[31m[ERROR] [${task}]\x1b\[0m`, message);
84
+ }
85
+
86
+ function exitWithError()
87
+ {
88
+ process.exit(1);
89
+ }
@@ -345,7 +345,7 @@ namespace RTC
345
345
 
346
346
  std::vector<RTCP::SenderReport*> senderReports;
347
347
  std::vector<RTCP::SdesChunk*> sdesChunks;
348
- std::vector<RTCP::DelaySinceLastRr*> xrReports;
348
+ std::vector<RTCP::DelaySinceLastRr::SsrcInfo*> delaySinceLastRrSsrcInfos;
349
349
 
350
350
  for (auto* rtpStream : this->rtpStreams)
351
351
  {
@@ -362,19 +362,16 @@ namespace RTC
362
362
  auto* sdesChunk = rtpStream->GetRtcpSdesChunk();
363
363
  sdesChunks.push_back(sdesChunk);
364
364
 
365
- auto* dlrr = rtpStream->GetRtcpXrDelaySinceLastRr(nowMs);
365
+ auto* delaySinceLastRrSsrcInfo = rtpStream->GetRtcpXrDelaySinceLastRrSsrcInfo(nowMs);
366
366
 
367
- if (dlrr)
367
+ if (delaySinceLastRrSsrcInfo)
368
368
  {
369
- auto* report = new RTC::RTCP::DelaySinceLastRr();
370
- report->AddSsrcInfo(dlrr);
371
-
372
- xrReports.push_back(report);
369
+ delaySinceLastRrSsrcInfos.push_back(delaySinceLastRrSsrcInfo);
373
370
  }
374
371
  }
375
372
 
376
373
  // RTCP Compound packet buffer cannot hold the data.
377
- if (!packet->Add(senderReports, sdesChunks, xrReports))
374
+ if (!packet->Add(senderReports, sdesChunks, delaySinceLastRrSsrcInfos))
378
375
  {
379
376
  return false;
380
377
  }
@@ -72,7 +72,9 @@ namespace RTC
72
72
  }
73
73
 
74
74
  bool CompoundPacket::Add(
75
- SenderReport* senderReport, SdesChunk* sdesChunk, DelaySinceLastRr* delaySinceLastRrReport)
75
+ SenderReport* senderReport,
76
+ SdesChunk* sdesChunk,
77
+ DelaySinceLastRr::SsrcInfo* delaySinceLastRrSsrcInfo)
76
78
  {
77
79
  // Add the items into the packet.
78
80
 
@@ -86,9 +88,16 @@ namespace RTC
86
88
  this->sdesPacket.AddChunk(sdesChunk);
87
89
  }
88
90
 
89
- if (delaySinceLastRrReport)
91
+ if (delaySinceLastRrSsrcInfo)
90
92
  {
91
- this->xrPacket.AddReport(delaySinceLastRrReport);
93
+ // Add a DLRR block into the XR packet if no present.
94
+ if (!this->delaySinceLastRr)
95
+ {
96
+ this->delaySinceLastRr = new RTC::RTCP::DelaySinceLastRr();
97
+ this->xrPacket.AddReport(this->delaySinceLastRr);
98
+ }
99
+
100
+ this->delaySinceLastRr->AddSsrcInfo(delaySinceLastRrSsrcInfo);
92
101
  }
93
102
 
94
103
  // New items can hold in the packet, report it.
@@ -112,10 +121,10 @@ namespace RTC
112
121
  delete sdesChunk;
113
122
  }
114
123
 
115
- if (delaySinceLastRrReport)
124
+ if (delaySinceLastRrSsrcInfo)
116
125
  {
117
- this->xrPacket.RemoveReport(delaySinceLastRrReport);
118
- delete delaySinceLastRrReport;
126
+ // NOTE: This method deletes the removed instances in place.
127
+ this->delaySinceLastRr->RemoveLastSsrcInfos(1);
119
128
  }
120
129
 
121
130
  return false;
@@ -124,7 +133,7 @@ namespace RTC
124
133
  bool CompoundPacket::Add(
125
134
  std::vector<SenderReport*>& senderReports,
126
135
  std::vector<SdesChunk*>& sdesChunks,
127
- std::vector<DelaySinceLastRr*>& delaySinceLastRrReports)
136
+ std::vector<DelaySinceLastRr::SsrcInfo*>& delaySinceLastRrSsrcInfos)
128
137
  {
129
138
  // Add the items into the packet.
130
139
 
@@ -138,9 +147,16 @@ namespace RTC
138
147
  this->sdesPacket.AddChunk(chunk);
139
148
  }
140
149
 
141
- for (auto* report : delaySinceLastRrReports)
150
+ // Add a DLRR block into the XR packet if no present.
151
+ if (!delaySinceLastRrSsrcInfos.empty() && !this->delaySinceLastRr)
142
152
  {
143
- this->xrPacket.AddReport(report);
153
+ this->delaySinceLastRr = new RTC::RTCP::DelaySinceLastRr();
154
+ this->xrPacket.AddReport(this->delaySinceLastRr);
155
+ }
156
+
157
+ for (auto* ssrcInfo : delaySinceLastRrSsrcInfos)
158
+ {
159
+ this->delaySinceLastRr->AddSsrcInfo(ssrcInfo);
144
160
  }
145
161
 
146
162
  // New items can hold in the packet, report it.
@@ -164,10 +180,10 @@ namespace RTC
164
180
  delete chunk;
165
181
  }
166
182
 
167
- for (auto* report : delaySinceLastRrReports)
183
+ if (!delaySinceLastRrSsrcInfos.empty())
168
184
  {
169
- this->xrPacket.RemoveReport(report);
170
- delete report;
185
+ // NOTE: This method deletes the instances in place.
186
+ this->delaySinceLastRr->RemoveLastSsrcInfos(delaySinceLastRrSsrcInfos.size());
171
187
  }
172
188
 
173
189
  return false;
@@ -266,19 +282,5 @@ namespace RTC
266
282
 
267
283
  this->sdesPacket.AddChunk(chunk);
268
284
  }
269
-
270
- void CompoundPacket::AddReceiverReferenceTime(ReceiverReferenceTime* report)
271
- {
272
- MS_TRACE();
273
-
274
- this->xrPacket.AddReport(report);
275
- }
276
-
277
- void CompoundPacket::AddDelaySinceLastRr(DelaySinceLastRr* report)
278
- {
279
- MS_TRACE();
280
-
281
- this->xrPacket.AddReport(report);
282
- }
283
285
  } // namespace RTCP
284
286
  } // namespace RTC
@@ -75,14 +75,12 @@ namespace RTC
75
75
  {
76
76
  report->AddSsrcInfo(ssrcInfo);
77
77
  offset += ssrcInfo->GetSize();
78
+ reportLength -= ssrcInfo->GetSize();
78
79
  }
79
80
  else
80
81
  {
81
82
  return report.release();
82
83
  }
83
-
84
- offset += ssrcInfo->GetSize();
85
- reportLength -= DelaySinceLastRr::SsrcInfo::BodySize;
86
84
  }
87
85
 
88
86
  return report.release();
@@ -274,7 +274,7 @@ namespace RTC
274
274
  return report;
275
275
  }
276
276
 
277
- RTC::RTCP::DelaySinceLastRr::SsrcInfo* RtpStreamSend::GetRtcpXrDelaySinceLastRr(uint64_t nowMs)
277
+ RTC::RTCP::DelaySinceLastRr::SsrcInfo* RtpStreamSend::GetRtcpXrDelaySinceLastRrSsrcInfo(uint64_t nowMs)
278
278
  {
279
279
  MS_TRACE();
280
280
 
@@ -439,18 +439,10 @@ namespace RTC
439
439
  // Build SDES chunk for this sender.
440
440
  auto* sdesChunk = this->rtpStream->GetRtcpSdesChunk();
441
441
 
442
- RTC::RTCP::DelaySinceLastRr* delaySinceLastRrReport{ nullptr };
443
-
444
- auto* dlrr = this->rtpStream->GetRtcpXrDelaySinceLastRr(nowMs);
445
-
446
- if (dlrr)
447
- {
448
- delaySinceLastRrReport = new RTC::RTCP::DelaySinceLastRr();
449
- delaySinceLastRrReport->AddSsrcInfo(dlrr);
450
- }
442
+ auto* delaySinceLastRrSsrcInfo = this->rtpStream->GetRtcpXrDelaySinceLastRrSsrcInfo(nowMs);
451
443
 
452
444
  // RTCP Compound packet buffer cannot hold the data.
453
- if (!packet->Add(senderReport, sdesChunk, delaySinceLastRrReport))
445
+ if (!packet->Add(senderReport, sdesChunk, delaySinceLastRrSsrcInfo))
454
446
  {
455
447
  return false;
456
448
  }
@@ -1081,18 +1081,10 @@ namespace RTC
1081
1081
  // Build SDES chunk for this sender.
1082
1082
  auto* sdesChunk = this->rtpStream->GetRtcpSdesChunk();
1083
1083
 
1084
- RTC::RTCP::DelaySinceLastRr* delaySinceLastRrReport{ nullptr };
1085
-
1086
- auto* dlrr = this->rtpStream->GetRtcpXrDelaySinceLastRr(nowMs);
1087
-
1088
- if (dlrr)
1089
- {
1090
- delaySinceLastRrReport = new RTC::RTCP::DelaySinceLastRr();
1091
- delaySinceLastRrReport->AddSsrcInfo(dlrr);
1092
- }
1084
+ auto* delaySinceLastRrSsrcInfo = this->rtpStream->GetRtcpXrDelaySinceLastRrSsrcInfo(nowMs);
1093
1085
 
1094
1086
  // RTCP Compound packet buffer cannot hold the data.
1095
- if (!packet->Add(senderReport, sdesChunk, delaySinceLastRrReport))
1087
+ if (!packet->Add(senderReport, sdesChunk, delaySinceLastRrSsrcInfo))
1096
1088
  {
1097
1089
  return false;
1098
1090
  }
@@ -795,18 +795,10 @@ namespace RTC
795
795
  // Build SDES chunk for this sender.
796
796
  auto* sdesChunk = this->rtpStream->GetRtcpSdesChunk();
797
797
 
798
- RTC::RTCP::DelaySinceLastRr* delaySinceLastRrReport{ nullptr };
799
-
800
- auto* dlrr = this->rtpStream->GetRtcpXrDelaySinceLastRr(nowMs);
801
-
802
- if (dlrr)
803
- {
804
- delaySinceLastRrReport = new RTC::RTCP::DelaySinceLastRr();
805
- delaySinceLastRrReport->AddSsrcInfo(dlrr);
806
- }
798
+ auto* delaySinceLastRrSsrcInfo = this->rtpStream->GetRtcpXrDelaySinceLastRrSsrcInfo(nowMs);
807
799
 
808
800
  // RTCP Compound packet buffer cannot hold the data.
809
- if (!packet->Add(senderReport, sdesChunk, delaySinceLastRrReport))
801
+ if (!packet->Add(senderReport, sdesChunk, delaySinceLastRrSsrcInfo))
810
802
  {
811
803
  return false;
812
804
  }
@@ -1,7 +1,7 @@
1
1
  #include "common.hpp"
2
2
  #include "RTC/Codecs/VP8.hpp"
3
3
  #include <catch2/catch.hpp>
4
- #include <cstring> // std::memcmp()
4
+ #include <cstring> // std::memcmp(), std::memcpy()
5
5
 
6
6
  using namespace RTC;
7
7
 
@@ -1,4 +1,5 @@
1
1
  #include "common.hpp"
2
+ #include "RTC/RTCP/Packet.hpp"
2
3
  #include "RTC/RTCP/Sdes.hpp"
3
4
  #include <catch2/catch.hpp>
4
5
  #include <cstring> // std::memcmp()
@@ -383,40 +384,118 @@ SCENARIO("RTCP SDES parsing", "[parser][rtcp][sdes]")
383
384
  REQUIRE(!packet);
384
385
  }
385
386
 
387
+ SECTION("create SDES packet with 31 chunks")
388
+ {
389
+ const size_t count = 31;
390
+
391
+ SdesPacket packet;
392
+ // Create a chunk and an item to obtain their size.
393
+ SdesChunk* chunk = new SdesChunk(1234 /*ssrc*/);
394
+ auto* item1 =
395
+ new RTC::RTCP::SdesItem(SdesItem::Type::CNAME, item1Value.size(), item1Value.c_str());
396
+
397
+ chunk->AddItem(item1);
398
+
399
+ auto chunkSize = chunk->GetSize();
400
+
401
+ delete chunk;
402
+
403
+ for (auto i{ 1 }; i <= count; ++i)
404
+ {
405
+ // Create chunk and add to packet.
406
+ SdesChunk* chunk = new SdesChunk(i /*ssrc*/);
407
+
408
+ auto* item1 =
409
+ new RTC::RTCP::SdesItem(SdesItem::Type::CNAME, item1Value.size(), item1Value.c_str());
410
+
411
+ chunk->AddItem(item1);
412
+
413
+ packet.AddChunk(chunk);
414
+ }
415
+
416
+ REQUIRE(packet.GetCount() == count);
417
+ REQUIRE(packet.GetSize() == Packet::CommonHeaderSize + (count * chunkSize));
418
+
419
+ uint8_t buffer1[1500] = { 0 };
420
+
421
+ // Serialization must contain 1 SDES packet since report count doesn't
422
+ // exceed 31.
423
+ packet.Serialize(buffer1);
424
+
425
+ auto* packet2 = static_cast<SdesPacket*>(Packet::Parse(buffer1, sizeof(buffer1)));
426
+
427
+ REQUIRE(packet2 != nullptr);
428
+ REQUIRE(packet2->GetCount() == count);
429
+ REQUIRE(packet2->GetSize() == Packet::CommonHeaderSize + (count * chunkSize));
430
+
431
+ auto reportIt = packet2->Begin();
432
+
433
+ for (auto i{ 1 }; i <= 31; ++i, reportIt++)
434
+ {
435
+ auto* chunk = *reportIt;
436
+
437
+ REQUIRE(chunk->GetSsrc() == i);
438
+
439
+ auto* item = *(chunk->Begin());
440
+
441
+ REQUIRE(item->GetType() == SdesItem::Type::CNAME);
442
+ REQUIRE(item->GetSize() == 2 + item1Value.size());
443
+ REQUIRE(std::string(item->GetValue()) == item1Value);
444
+ }
445
+
446
+ SdesPacket* packet3 = static_cast<SdesPacket*>(packet2->GetNext());
447
+
448
+ REQUIRE(packet3 == nullptr);
449
+
450
+ delete packet3;
451
+ }
452
+
386
453
  SECTION("create SDES packet with more than 31 chunks")
387
454
  {
388
455
  const size_t count = 33;
389
456
 
390
457
  SdesPacket packet;
458
+ // Create a chunk and an item to obtain their size.
459
+ SdesChunk* chunk = new SdesChunk(1234 /*ssrc*/);
460
+ auto* item1 =
461
+ new RTC::RTCP::SdesItem(SdesItem::Type::CNAME, item1Value.size(), item1Value.c_str());
462
+
463
+ chunk->AddItem(item1);
464
+
465
+ auto chunkSize = chunk->GetSize();
466
+
467
+ delete chunk;
391
468
 
392
- for (auto i = 1; i <= count; i++)
469
+ for (auto i{ 1 }; i <= count; ++i)
393
470
  {
394
471
  // Create chunk and add to packet.
395
- SdesChunk* chunk1 = new SdesChunk(i /*ssrc*/);
472
+ SdesChunk* chunk = new SdesChunk(i /*ssrc*/);
396
473
 
397
474
  auto* item1 =
398
475
  new RTC::RTCP::SdesItem(SdesItem::Type::CNAME, item1Value.size(), item1Value.c_str());
399
476
 
400
- chunk1->AddItem(item1);
477
+ chunk->AddItem(item1);
401
478
 
402
- packet.AddChunk(chunk1);
479
+ packet.AddChunk(chunk);
403
480
  }
404
481
 
405
482
  REQUIRE(packet.GetCount() == count);
483
+ REQUIRE(packet.GetSize() == Packet::CommonHeaderSize + (31 * chunkSize) + Packet::CommonHeaderSize + ((count - 31) * chunkSize));
406
484
 
407
485
  uint8_t buffer1[1500] = { 0 };
408
486
 
409
- // Serialization must contain 2 RR packets since report count exceeds 31.
487
+ // Serialization must contain 2 SDES packets since report count exceeds 31.
410
488
  packet.Serialize(buffer1);
411
489
 
412
490
  auto* packet2 = static_cast<SdesPacket*>(Packet::Parse(buffer1, sizeof(buffer1)));
413
491
 
414
492
  REQUIRE(packet2 != nullptr);
415
493
  REQUIRE(packet2->GetCount() == 31);
494
+ REQUIRE(packet2->GetSize() == Packet::CommonHeaderSize + (31 * chunkSize));
416
495
 
417
496
  auto reportIt = packet2->Begin();
418
497
 
419
- for (auto i = 1; i <= 31; i++, reportIt++)
498
+ for (auto i{ 1 }; i <= 31; ++i, reportIt++)
420
499
  {
421
500
  auto* chunk = *reportIt;
422
501
 
@@ -432,11 +511,12 @@ SCENARIO("RTCP SDES parsing", "[parser][rtcp][sdes]")
432
511
  SdesPacket* packet3 = static_cast<SdesPacket*>(packet2->GetNext());
433
512
 
434
513
  REQUIRE(packet3 != nullptr);
435
- REQUIRE(packet3->GetCount() == 2);
514
+ REQUIRE(packet3->GetCount() == count - 31);
515
+ REQUIRE(packet3->GetSize() == Packet::CommonHeaderSize + ((count - 31) * chunkSize));
436
516
 
437
517
  reportIt = packet3->Begin();
438
518
 
439
- for (auto i = 1; i <= 2; i++, reportIt++)
519
+ for (auto i{ 1 }; i <= 2; ++i, reportIt++)
440
520
  {
441
521
  auto* chunk = *reportIt;
442
522
 
@@ -1,11 +1,133 @@
1
1
  #include "common.hpp"
2
+ #include "RTC/RTCP/XR.hpp"
2
3
  #include "RTC/RTCP/XrDelaySinceLastRr.hpp"
3
4
  #include "RTC/RTCP/XrReceiverReferenceTime.hpp"
4
5
  #include <catch2/catch.hpp>
5
- #include <cstring> // std::memcmp
6
+ #include <cstring> // std::memcmp(), std::memcpy()
6
7
 
7
8
  using namespace RTC::RTCP;
8
9
 
10
+ SCENARIO("RTCP XR parsing", "[parser][rtcp][xr]")
11
+ {
12
+ // clang-format off
13
+ uint8_t buffer[] =
14
+ {
15
+ 0xa0, 0xcf, 0x00, 0x09, // Padding, Type: 207 (XR), Length: 9
16
+ 0x5d, 0x93, 0x15, 0x34, // Sender SSRC: 0x5d931534
17
+ // Extended Report DLRR
18
+ 0x05, 0x00, 0x00, 0x06, // BT: 5 (DLRR), Block Length: 6
19
+ 0x11, 0x12, 0x13, 0x14, // SSRC 1
20
+ 0x00, 0x11, 0x00, 0x11, // LRR 1
21
+ 0x11, 0x00, 0x11, 0x00, // DLRR 1
22
+ 0x21, 0x22, 0x23, 0x24, // SSRC 2
23
+ 0x00, 0x22, 0x00, 0x22, // LRR 2
24
+ 0x22, 0x00, 0x22, 0x00, // DLRR 2
25
+ 0x00, 0x00, 0x00, 0x04 // Padding (4 bytes)
26
+ };
27
+ // clang-format on
28
+
29
+ SECTION("parse XR packet")
30
+ {
31
+ auto* packet = ExtendedReportPacket::Parse(buffer, sizeof(buffer));
32
+
33
+ REQUIRE(packet);
34
+ // Despite total buffer size is 40 bytes, our GetSize() method doesn't not
35
+ // consider RTCP padding (4 bytes in this case).
36
+ // https://github.com/versatica/mediasoup/issues/1233
37
+ REQUIRE(packet->GetSize() == 36);
38
+ REQUIRE(packet->GetCount() == 0);
39
+ REQUIRE(packet->GetSsrc() == 0x5d931534);
40
+
41
+ size_t blockIdx{ 0u };
42
+
43
+ for (auto it = packet->Begin(); it != packet->End(); ++it, ++blockIdx)
44
+ {
45
+ auto* block = *it;
46
+
47
+ switch (blockIdx)
48
+ {
49
+ case 0:
50
+ {
51
+ REQUIRE(block->GetSize() == 28);
52
+
53
+ size_t ssrcInfoIdx{ 0u };
54
+ auto* dlrrBlock = reinterpret_cast<DelaySinceLastRr*>(block);
55
+
56
+ for (auto it2 = dlrrBlock->Begin(); it2 != dlrrBlock->End(); ++it2, ++ssrcInfoIdx)
57
+ {
58
+ auto* ssrcInfo = *it2;
59
+
60
+ switch (ssrcInfoIdx)
61
+ {
62
+ case 0:
63
+ {
64
+ REQUIRE(ssrcInfo->GetSsrc() == 0x11121314);
65
+ REQUIRE(ssrcInfo->GetLastReceiverReport() == 0x00110011);
66
+ REQUIRE(ssrcInfo->GetDelaySinceLastReceiverReport() == 0x11001100);
67
+
68
+ break;
69
+ }
70
+
71
+ case 1:
72
+ {
73
+ REQUIRE(ssrcInfo->GetSsrc() == 0x21222324);
74
+ REQUIRE(ssrcInfo->GetLastReceiverReport() == 0x00220022);
75
+ REQUIRE(ssrcInfo->GetDelaySinceLastReceiverReport() == 0x22002200);
76
+
77
+ break;
78
+ }
79
+ }
80
+ }
81
+
82
+ // There are 2 SSRC infos.
83
+ REQUIRE(ssrcInfoIdx == 2);
84
+
85
+ break;
86
+ }
87
+ }
88
+ }
89
+
90
+ // There are 1 block (the DLRR block).
91
+ REQUIRE(blockIdx == 1);
92
+
93
+ SECTION("serialize packet instance")
94
+ {
95
+ // NOTE: Padding in RTCP is removed (if not needed) when serializing the
96
+ // packet, so we must mangle the buffer content (padding bit) and the
97
+ // buffer length before comparing the serialized packet with and original
98
+ // buffer.
99
+
100
+ const size_t paddingBytes{ 4 };
101
+ const size_t serializedBufferLength = sizeof(buffer) - paddingBytes;
102
+ uint8_t serialized[serializedBufferLength] = { 0 };
103
+
104
+ // Clone the original buffer into a new buffer without padding.
105
+ uint8_t clonedBuffer[serializedBufferLength] = { 0 };
106
+ std::memcpy(clonedBuffer, buffer, serializedBufferLength);
107
+
108
+ // Remove the padding bit in the first byte of the cloned buffer.
109
+ clonedBuffer[0] = 0x80;
110
+
111
+ // Change RTCP length field in the cloned buffer.
112
+ clonedBuffer[3] = clonedBuffer[3] - 1;
113
+
114
+ packet->Serialize(serialized);
115
+
116
+ auto* packet2 = ExtendedReportPacket::Parse(serialized, serializedBufferLength);
117
+
118
+ REQUIRE(packet2->GetType() == Type::XR);
119
+ REQUIRE(packet2->GetCount() == 0);
120
+ REQUIRE(packet2->GetSize() == 36);
121
+
122
+ REQUIRE(std::memcmp(clonedBuffer, serialized, serializedBufferLength) == 0);
123
+
124
+ delete packet2;
125
+ }
126
+
127
+ delete packet;
128
+ }
129
+ }
130
+
9
131
  SCENARIO("RTCP XrDelaySinceLastRt parsing", "[parser][rtcp][xr-dlrr]")
10
132
  {
11
133
  SECTION("create RRT")