mediasoup-client 3.6.90 → 3.6.91

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 (125) hide show
  1. package/lib/Consumer.d.ts +115 -0
  2. package/lib/Consumer.d.ts.map +1 -0
  3. package/lib/Consumer.js +190 -0
  4. package/lib/DataConsumer.d.ts +93 -0
  5. package/lib/DataConsumer.d.ts.map +1 -0
  6. package/lib/DataConsumer.js +162 -0
  7. package/lib/DataProducer.d.ts +97 -0
  8. package/lib/DataProducer.d.ts.map +1 -0
  9. package/lib/DataProducer.js +180 -0
  10. package/lib/Device.d.ts +92 -0
  11. package/lib/Device.d.ts.map +1 -0
  12. package/lib/Device.js +463 -0
  13. package/lib/EnhancedEventEmitter.d.ts +24 -0
  14. package/lib/EnhancedEventEmitter.d.ts.map +1 -0
  15. package/lib/EnhancedEventEmitter.js +70 -0
  16. package/lib/Logger.d.ts +11 -0
  17. package/lib/Logger.d.ts.map +1 -0
  18. package/lib/Logger.js +37 -0
  19. package/lib/Producer.d.ts +169 -0
  20. package/lib/Producer.d.ts.map +1 -0
  21. package/lib/Producer.js +287 -0
  22. package/lib/RtpParameters.d.ts +306 -0
  23. package/lib/RtpParameters.d.ts.map +1 -0
  24. package/lib/RtpParameters.js +6 -0
  25. package/lib/SctpParameters.d.ts +68 -0
  26. package/lib/SctpParameters.d.ts.map +1 -0
  27. package/lib/SctpParameters.js +2 -0
  28. package/lib/Transport.d.ts +243 -0
  29. package/lib/Transport.d.ts.map +1 -0
  30. package/lib/Transport.js +824 -0
  31. package/lib/errors.d.ts +13 -0
  32. package/lib/errors.d.ts.map +1 -0
  33. package/lib/errors.js +39 -0
  34. package/lib/handlers/Chrome111.d.ts +49 -0
  35. package/lib/handlers/Chrome111.d.ts.map +1 -0
  36. package/lib/handlers/Chrome111.js +654 -0
  37. package/lib/handlers/Chrome55.d.ts +51 -0
  38. package/lib/handlers/Chrome55.d.ts.map +1 -0
  39. package/lib/handlers/Chrome55.js +538 -0
  40. package/lib/handlers/Chrome67.d.ts +51 -0
  41. package/lib/handlers/Chrome67.d.ts.map +1 -0
  42. package/lib/handlers/Chrome67.js +594 -0
  43. package/lib/handlers/Chrome70.d.ts +49 -0
  44. package/lib/handlers/Chrome70.d.ts.map +1 -0
  45. package/lib/handlers/Chrome70.js +623 -0
  46. package/lib/handlers/Chrome74.d.ts +49 -0
  47. package/lib/handlers/Chrome74.d.ts.map +1 -0
  48. package/lib/handlers/Chrome74.js +671 -0
  49. package/lib/handlers/Edge11.d.ts +55 -0
  50. package/lib/handlers/Edge11.d.ts.map +1 -0
  51. package/lib/handlers/Edge11.js +447 -0
  52. package/lib/handlers/FakeHandler.d.ts +49 -0
  53. package/lib/handlers/FakeHandler.d.ts.map +1 -0
  54. package/lib/handlers/FakeHandler.js +276 -0
  55. package/lib/handlers/Firefox60.d.ts +48 -0
  56. package/lib/handlers/Firefox60.d.ts.map +1 -0
  57. package/lib/handlers/Firefox60.js +681 -0
  58. package/lib/handlers/HandlerInterface.d.ts +97 -0
  59. package/lib/handlers/HandlerInterface.d.ts.map +1 -0
  60. package/lib/handlers/HandlerInterface.js +10 -0
  61. package/lib/handlers/ReactNative.d.ts +51 -0
  62. package/lib/handlers/ReactNative.d.ts.map +1 -0
  63. package/lib/handlers/ReactNative.js +554 -0
  64. package/lib/handlers/ReactNativeUnifiedPlan.d.ts +49 -0
  65. package/lib/handlers/ReactNativeUnifiedPlan.d.ts.map +1 -0
  66. package/lib/handlers/ReactNativeUnifiedPlan.js +690 -0
  67. package/lib/handlers/Safari11.d.ts +51 -0
  68. package/lib/handlers/Safari11.d.ts.map +1 -0
  69. package/lib/handlers/Safari11.js +588 -0
  70. package/lib/handlers/Safari12.d.ts +49 -0
  71. package/lib/handlers/Safari12.d.ts.map +1 -0
  72. package/lib/handlers/Safari12.js +644 -0
  73. package/lib/handlers/ortc/edgeUtils.d.ts +11 -0
  74. package/lib/handlers/ortc/edgeUtils.d.ts.map +1 -0
  75. package/lib/handlers/ortc/edgeUtils.js +86 -0
  76. package/lib/handlers/ortc/utils.d.ts +6 -0
  77. package/lib/handlers/ortc/utils.d.ts.map +1 -0
  78. package/lib/handlers/ortc/utils.js +19 -0
  79. package/lib/handlers/sdp/MediaSection.d.ts +68 -0
  80. package/lib/handlers/sdp/MediaSection.d.ts.map +1 -0
  81. package/lib/handlers/sdp/MediaSection.js +588 -0
  82. package/lib/handlers/sdp/RemoteSdp.d.ts +75 -0
  83. package/lib/handlers/sdp/RemoteSdp.d.ts.map +1 -0
  84. package/lib/handlers/sdp/RemoteSdp.js +303 -0
  85. package/lib/handlers/sdp/commonUtils.d.ts +24 -0
  86. package/lib/handlers/sdp/commonUtils.d.ts.map +1 -0
  87. package/lib/handlers/sdp/commonUtils.js +224 -0
  88. package/lib/handlers/sdp/plainRtpUtils.d.ts +14 -0
  89. package/lib/handlers/sdp/plainRtpUtils.d.ts.map +1 -0
  90. package/lib/handlers/sdp/plainRtpUtils.js +33 -0
  91. package/lib/handlers/sdp/planBUtils.d.ts +14 -0
  92. package/lib/handlers/sdp/planBUtils.d.ts.map +1 -0
  93. package/lib/handlers/sdp/planBUtils.js +155 -0
  94. package/lib/handlers/sdp/unifiedPlanUtils.d.ts +12 -0
  95. package/lib/handlers/sdp/unifiedPlanUtils.d.ts.map +1 -0
  96. package/lib/handlers/sdp/unifiedPlanUtils.js +131 -0
  97. package/lib/index.d.ts +14 -1435
  98. package/lib/index.d.ts.map +1 -0
  99. package/lib/index.js +43 -11884
  100. package/lib/ortc.d.ts +123 -0
  101. package/lib/ortc.d.ts.map +1 -0
  102. package/lib/ortc.js +943 -0
  103. package/lib/scalabilityModes.d.ts +6 -0
  104. package/lib/scalabilityModes.d.ts.map +1 -0
  105. package/lib/scalabilityModes.js +20 -0
  106. package/lib/tests/fakeParameters.d.ts +20 -0
  107. package/lib/tests/fakeParameters.d.ts.map +1 -0
  108. package/lib/tests/fakeParameters.js +659 -0
  109. package/lib/tests/test.d.ts +6 -0
  110. package/lib/tests/test.d.ts.map +1 -0
  111. package/lib/tests/test.js +1287 -0
  112. package/lib/tests/uaTestCases.d.ts +9 -0
  113. package/lib/tests/uaTestCases.d.ts.map +1 -0
  114. package/lib/tests/uaTestCases.js +85 -0
  115. package/lib/types.d.ts +15 -0
  116. package/lib/types.d.ts.map +1 -0
  117. package/lib/types.js +26 -0
  118. package/lib/utils.d.ts +9 -0
  119. package/lib/utils.d.ts.map +1 -0
  120. package/lib/utils.js +20 -0
  121. package/npm-scripts.mjs +2 -3
  122. package/package.json +1 -6
  123. package/lib/index.js.map +0 -1
  124. package/lib/index.mjs +0 -11860
  125. package/lib/index.mjs.map +0 -1
package/lib/ortc.js ADDED
@@ -0,0 +1,943 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.canReceive = exports.canSend = exports.generateProbatorRtpParameters = exports.reduceCodecs = exports.getSendingRemoteRtpParameters = exports.getSendingRtpParameters = exports.getRecvRtpCapabilities = exports.getExtendedRtpCapabilities = exports.validateSctpStreamParameters = exports.validateSctpParameters = exports.validateNumSctpStreams = exports.validateSctpCapabilities = exports.validateRtcpParameters = exports.validateRtpEncodingParameters = exports.validateRtpHeaderExtensionParameters = exports.validateRtpCodecParameters = exports.validateRtpParameters = exports.validateRtpHeaderExtension = exports.validateRtcpFeedback = exports.validateRtpCodecCapability = exports.validateRtpCapabilities = void 0;
27
+ const h264 = __importStar(require("h264-profile-level-id"));
28
+ const utils = __importStar(require("./utils"));
29
+ const RTP_PROBATOR_MID = 'probator';
30
+ const RTP_PROBATOR_SSRC = 1234;
31
+ const RTP_PROBATOR_CODEC_PAYLOAD_TYPE = 127;
32
+ /**
33
+ * Validates RtpCapabilities. It may modify given data by adding missing
34
+ * fields with default values.
35
+ * It throws if invalid.
36
+ */
37
+ function validateRtpCapabilities(caps) {
38
+ if (typeof caps !== 'object') {
39
+ throw new TypeError('caps is not an object');
40
+ }
41
+ // codecs is optional. If unset, fill with an empty array.
42
+ if (caps.codecs && !Array.isArray(caps.codecs)) {
43
+ throw new TypeError('caps.codecs is not an array');
44
+ }
45
+ else if (!caps.codecs) {
46
+ caps.codecs = [];
47
+ }
48
+ for (const codec of caps.codecs) {
49
+ validateRtpCodecCapability(codec);
50
+ }
51
+ // headerExtensions is optional. If unset, fill with an empty array.
52
+ if (caps.headerExtensions && !Array.isArray(caps.headerExtensions)) {
53
+ throw new TypeError('caps.headerExtensions is not an array');
54
+ }
55
+ else if (!caps.headerExtensions) {
56
+ caps.headerExtensions = [];
57
+ }
58
+ for (const ext of caps.headerExtensions) {
59
+ validateRtpHeaderExtension(ext);
60
+ }
61
+ }
62
+ exports.validateRtpCapabilities = validateRtpCapabilities;
63
+ /**
64
+ * Validates RtpCodecCapability. It may modify given data by adding missing
65
+ * fields with default values.
66
+ * It throws if invalid.
67
+ */
68
+ function validateRtpCodecCapability(codec) {
69
+ const MimeTypeRegex = new RegExp('^(audio|video)/(.+)', 'i');
70
+ if (typeof codec !== 'object') {
71
+ throw new TypeError('codec is not an object');
72
+ }
73
+ // mimeType is mandatory.
74
+ if (!codec.mimeType || typeof codec.mimeType !== 'string') {
75
+ throw new TypeError('missing codec.mimeType');
76
+ }
77
+ const mimeTypeMatch = MimeTypeRegex.exec(codec.mimeType);
78
+ if (!mimeTypeMatch) {
79
+ throw new TypeError('invalid codec.mimeType');
80
+ }
81
+ // Just override kind with media component of mimeType.
82
+ codec.kind = mimeTypeMatch[1].toLowerCase();
83
+ // preferredPayloadType is optional.
84
+ if (codec.preferredPayloadType && typeof codec.preferredPayloadType !== 'number') {
85
+ throw new TypeError('invalid codec.preferredPayloadType');
86
+ }
87
+ // clockRate is mandatory.
88
+ if (typeof codec.clockRate !== 'number') {
89
+ throw new TypeError('missing codec.clockRate');
90
+ }
91
+ // channels is optional. If unset, set it to 1 (just if audio).
92
+ if (codec.kind === 'audio') {
93
+ if (typeof codec.channels !== 'number') {
94
+ codec.channels = 1;
95
+ }
96
+ }
97
+ else {
98
+ delete codec.channels;
99
+ }
100
+ // parameters is optional. If unset, set it to an empty object.
101
+ if (!codec.parameters || typeof codec.parameters !== 'object') {
102
+ codec.parameters = {};
103
+ }
104
+ for (const key of Object.keys(codec.parameters)) {
105
+ let value = codec.parameters[key];
106
+ if (value === undefined) {
107
+ codec.parameters[key] = '';
108
+ value = '';
109
+ }
110
+ if (typeof value !== 'string' && typeof value !== 'number') {
111
+ throw new TypeError(`invalid codec parameter [key:${key}s, value:${value}]`);
112
+ }
113
+ // Specific parameters validation.
114
+ if (key === 'apt') {
115
+ if (typeof value !== 'number') {
116
+ throw new TypeError('invalid codec apt parameter');
117
+ }
118
+ }
119
+ }
120
+ // rtcpFeedback is optional. If unset, set it to an empty array.
121
+ if (!codec.rtcpFeedback || !Array.isArray(codec.rtcpFeedback)) {
122
+ codec.rtcpFeedback = [];
123
+ }
124
+ for (const fb of codec.rtcpFeedback) {
125
+ validateRtcpFeedback(fb);
126
+ }
127
+ }
128
+ exports.validateRtpCodecCapability = validateRtpCodecCapability;
129
+ /**
130
+ * Validates RtcpFeedback. It may modify given data by adding missing
131
+ * fields with default values.
132
+ * It throws if invalid.
133
+ */
134
+ function validateRtcpFeedback(fb) {
135
+ if (typeof fb !== 'object') {
136
+ throw new TypeError('fb is not an object');
137
+ }
138
+ // type is mandatory.
139
+ if (!fb.type || typeof fb.type !== 'string') {
140
+ throw new TypeError('missing fb.type');
141
+ }
142
+ // parameter is optional. If unset set it to an empty string.
143
+ if (!fb.parameter || typeof fb.parameter !== 'string') {
144
+ fb.parameter = '';
145
+ }
146
+ }
147
+ exports.validateRtcpFeedback = validateRtcpFeedback;
148
+ /**
149
+ * Validates RtpHeaderExtension. It may modify given data by adding missing
150
+ * fields with default values.
151
+ * It throws if invalid.
152
+ */
153
+ function validateRtpHeaderExtension(ext) {
154
+ if (typeof ext !== 'object') {
155
+ throw new TypeError('ext is not an object');
156
+ }
157
+ // kind is mandatory.
158
+ if (ext.kind !== 'audio' && ext.kind !== 'video') {
159
+ throw new TypeError('invalid ext.kind');
160
+ }
161
+ // uri is mandatory.
162
+ if (!ext.uri || typeof ext.uri !== 'string') {
163
+ throw new TypeError('missing ext.uri');
164
+ }
165
+ // preferredId is mandatory.
166
+ if (typeof ext.preferredId !== 'number') {
167
+ throw new TypeError('missing ext.preferredId');
168
+ }
169
+ // preferredEncrypt is optional. If unset set it to false.
170
+ if (ext.preferredEncrypt && typeof ext.preferredEncrypt !== 'boolean') {
171
+ throw new TypeError('invalid ext.preferredEncrypt');
172
+ }
173
+ else if (!ext.preferredEncrypt) {
174
+ ext.preferredEncrypt = false;
175
+ }
176
+ // direction is optional. If unset set it to sendrecv.
177
+ if (ext.direction && typeof ext.direction !== 'string') {
178
+ throw new TypeError('invalid ext.direction');
179
+ }
180
+ else if (!ext.direction) {
181
+ ext.direction = 'sendrecv';
182
+ }
183
+ }
184
+ exports.validateRtpHeaderExtension = validateRtpHeaderExtension;
185
+ /**
186
+ * Validates RtpParameters. It may modify given data by adding missing
187
+ * fields with default values.
188
+ * It throws if invalid.
189
+ */
190
+ function validateRtpParameters(params) {
191
+ if (typeof params !== 'object') {
192
+ throw new TypeError('params is not an object');
193
+ }
194
+ // mid is optional.
195
+ if (params.mid && typeof params.mid !== 'string') {
196
+ throw new TypeError('params.mid is not a string');
197
+ }
198
+ // codecs is mandatory.
199
+ if (!Array.isArray(params.codecs)) {
200
+ throw new TypeError('missing params.codecs');
201
+ }
202
+ for (const codec of params.codecs) {
203
+ validateRtpCodecParameters(codec);
204
+ }
205
+ // headerExtensions is optional. If unset, fill with an empty array.
206
+ if (params.headerExtensions && !Array.isArray(params.headerExtensions)) {
207
+ throw new TypeError('params.headerExtensions is not an array');
208
+ }
209
+ else if (!params.headerExtensions) {
210
+ params.headerExtensions = [];
211
+ }
212
+ for (const ext of params.headerExtensions) {
213
+ validateRtpHeaderExtensionParameters(ext);
214
+ }
215
+ // encodings is optional. If unset, fill with an empty array.
216
+ if (params.encodings && !Array.isArray(params.encodings)) {
217
+ throw new TypeError('params.encodings is not an array');
218
+ }
219
+ else if (!params.encodings) {
220
+ params.encodings = [];
221
+ }
222
+ for (const encoding of params.encodings) {
223
+ validateRtpEncodingParameters(encoding);
224
+ }
225
+ // rtcp is optional. If unset, fill with an empty object.
226
+ if (params.rtcp && typeof params.rtcp !== 'object') {
227
+ throw new TypeError('params.rtcp is not an object');
228
+ }
229
+ else if (!params.rtcp) {
230
+ params.rtcp = {};
231
+ }
232
+ validateRtcpParameters(params.rtcp);
233
+ }
234
+ exports.validateRtpParameters = validateRtpParameters;
235
+ /**
236
+ * Validates RtpCodecParameters. It may modify given data by adding missing
237
+ * fields with default values.
238
+ * It throws if invalid.
239
+ */
240
+ function validateRtpCodecParameters(codec) {
241
+ const MimeTypeRegex = new RegExp('^(audio|video)/(.+)', 'i');
242
+ if (typeof codec !== 'object') {
243
+ throw new TypeError('codec is not an object');
244
+ }
245
+ // mimeType is mandatory.
246
+ if (!codec.mimeType || typeof codec.mimeType !== 'string') {
247
+ throw new TypeError('missing codec.mimeType');
248
+ }
249
+ const mimeTypeMatch = MimeTypeRegex.exec(codec.mimeType);
250
+ if (!mimeTypeMatch) {
251
+ throw new TypeError('invalid codec.mimeType');
252
+ }
253
+ // payloadType is mandatory.
254
+ if (typeof codec.payloadType !== 'number') {
255
+ throw new TypeError('missing codec.payloadType');
256
+ }
257
+ // clockRate is mandatory.
258
+ if (typeof codec.clockRate !== 'number') {
259
+ throw new TypeError('missing codec.clockRate');
260
+ }
261
+ const kind = mimeTypeMatch[1].toLowerCase();
262
+ // channels is optional. If unset, set it to 1 (just if audio).
263
+ if (kind === 'audio') {
264
+ if (typeof codec.channels !== 'number') {
265
+ codec.channels = 1;
266
+ }
267
+ }
268
+ else {
269
+ delete codec.channels;
270
+ }
271
+ // parameters is optional. If unset, set it to an empty object.
272
+ if (!codec.parameters || typeof codec.parameters !== 'object') {
273
+ codec.parameters = {};
274
+ }
275
+ for (const key of Object.keys(codec.parameters)) {
276
+ let value = codec.parameters[key];
277
+ if (value === undefined) {
278
+ codec.parameters[key] = '';
279
+ value = '';
280
+ }
281
+ if (typeof value !== 'string' && typeof value !== 'number') {
282
+ throw new TypeError(`invalid codec parameter [key:${key}s, value:${value}]`);
283
+ }
284
+ // Specific parameters validation.
285
+ if (key === 'apt') {
286
+ if (typeof value !== 'number') {
287
+ throw new TypeError('invalid codec apt parameter');
288
+ }
289
+ }
290
+ }
291
+ // rtcpFeedback is optional. If unset, set it to an empty array.
292
+ if (!codec.rtcpFeedback || !Array.isArray(codec.rtcpFeedback)) {
293
+ codec.rtcpFeedback = [];
294
+ }
295
+ for (const fb of codec.rtcpFeedback) {
296
+ validateRtcpFeedback(fb);
297
+ }
298
+ }
299
+ exports.validateRtpCodecParameters = validateRtpCodecParameters;
300
+ /**
301
+ * Validates RtpHeaderExtensionParameteters. It may modify given data by adding missing
302
+ * fields with default values.
303
+ * It throws if invalid.
304
+ */
305
+ function validateRtpHeaderExtensionParameters(ext) {
306
+ if (typeof ext !== 'object') {
307
+ throw new TypeError('ext is not an object');
308
+ }
309
+ // uri is mandatory.
310
+ if (!ext.uri || typeof ext.uri !== 'string') {
311
+ throw new TypeError('missing ext.uri');
312
+ }
313
+ // id is mandatory.
314
+ if (typeof ext.id !== 'number') {
315
+ throw new TypeError('missing ext.id');
316
+ }
317
+ // encrypt is optional. If unset set it to false.
318
+ if (ext.encrypt && typeof ext.encrypt !== 'boolean') {
319
+ throw new TypeError('invalid ext.encrypt');
320
+ }
321
+ else if (!ext.encrypt) {
322
+ ext.encrypt = false;
323
+ }
324
+ // parameters is optional. If unset, set it to an empty object.
325
+ if (!ext.parameters || typeof ext.parameters !== 'object') {
326
+ ext.parameters = {};
327
+ }
328
+ for (const key of Object.keys(ext.parameters)) {
329
+ let value = ext.parameters[key];
330
+ if (value === undefined) {
331
+ ext.parameters[key] = '';
332
+ value = '';
333
+ }
334
+ if (typeof value !== 'string' && typeof value !== 'number') {
335
+ throw new TypeError('invalid header extension parameter');
336
+ }
337
+ }
338
+ }
339
+ exports.validateRtpHeaderExtensionParameters = validateRtpHeaderExtensionParameters;
340
+ /**
341
+ * Validates RtpEncodingParameters. It may modify given data by adding missing
342
+ * fields with default values.
343
+ * It throws if invalid.
344
+ */
345
+ function validateRtpEncodingParameters(encoding) {
346
+ if (typeof encoding !== 'object') {
347
+ throw new TypeError('encoding is not an object');
348
+ }
349
+ // ssrc is optional.
350
+ if (encoding.ssrc && typeof encoding.ssrc !== 'number') {
351
+ throw new TypeError('invalid encoding.ssrc');
352
+ }
353
+ // rid is optional.
354
+ if (encoding.rid && typeof encoding.rid !== 'string') {
355
+ throw new TypeError('invalid encoding.rid');
356
+ }
357
+ // rtx is optional.
358
+ if (encoding.rtx && typeof encoding.rtx !== 'object') {
359
+ throw new TypeError('invalid encoding.rtx');
360
+ }
361
+ else if (encoding.rtx) {
362
+ // RTX ssrc is mandatory if rtx is present.
363
+ if (typeof encoding.rtx.ssrc !== 'number') {
364
+ throw new TypeError('missing encoding.rtx.ssrc');
365
+ }
366
+ }
367
+ // dtx is optional. If unset set it to false.
368
+ if (!encoding.dtx || typeof encoding.dtx !== 'boolean') {
369
+ encoding.dtx = false;
370
+ }
371
+ // scalabilityMode is optional.
372
+ if (encoding.scalabilityMode && typeof encoding.scalabilityMode !== 'string') {
373
+ throw new TypeError('invalid encoding.scalabilityMode');
374
+ }
375
+ }
376
+ exports.validateRtpEncodingParameters = validateRtpEncodingParameters;
377
+ /**
378
+ * Validates RtcpParameters. It may modify given data by adding missing
379
+ * fields with default values.
380
+ * It throws if invalid.
381
+ */
382
+ function validateRtcpParameters(rtcp) {
383
+ if (typeof rtcp !== 'object') {
384
+ throw new TypeError('rtcp is not an object');
385
+ }
386
+ // cname is optional.
387
+ if (rtcp.cname && typeof rtcp.cname !== 'string') {
388
+ throw new TypeError('invalid rtcp.cname');
389
+ }
390
+ // reducedSize is optional. If unset set it to true.
391
+ if (!rtcp.reducedSize || typeof rtcp.reducedSize !== 'boolean') {
392
+ rtcp.reducedSize = true;
393
+ }
394
+ }
395
+ exports.validateRtcpParameters = validateRtcpParameters;
396
+ /**
397
+ * Validates SctpCapabilities. It may modify given data by adding missing
398
+ * fields with default values.
399
+ * It throws if invalid.
400
+ */
401
+ function validateSctpCapabilities(caps) {
402
+ if (typeof caps !== 'object') {
403
+ throw new TypeError('caps is not an object');
404
+ }
405
+ // numStreams is mandatory.
406
+ if (!caps.numStreams || typeof caps.numStreams !== 'object') {
407
+ throw new TypeError('missing caps.numStreams');
408
+ }
409
+ validateNumSctpStreams(caps.numStreams);
410
+ }
411
+ exports.validateSctpCapabilities = validateSctpCapabilities;
412
+ /**
413
+ * Validates NumSctpStreams. It may modify given data by adding missing
414
+ * fields with default values.
415
+ * It throws if invalid.
416
+ */
417
+ function validateNumSctpStreams(numStreams) {
418
+ if (typeof numStreams !== 'object') {
419
+ throw new TypeError('numStreams is not an object');
420
+ }
421
+ // OS is mandatory.
422
+ if (typeof numStreams.OS !== 'number') {
423
+ throw new TypeError('missing numStreams.OS');
424
+ }
425
+ // MIS is mandatory.
426
+ if (typeof numStreams.MIS !== 'number') {
427
+ throw new TypeError('missing numStreams.MIS');
428
+ }
429
+ }
430
+ exports.validateNumSctpStreams = validateNumSctpStreams;
431
+ /**
432
+ * Validates SctpParameters. It may modify given data by adding missing
433
+ * fields with default values.
434
+ * It throws if invalid.
435
+ */
436
+ function validateSctpParameters(params) {
437
+ if (typeof params !== 'object') {
438
+ throw new TypeError('params is not an object');
439
+ }
440
+ // port is mandatory.
441
+ if (typeof params.port !== 'number') {
442
+ throw new TypeError('missing params.port');
443
+ }
444
+ // OS is mandatory.
445
+ if (typeof params.OS !== 'number') {
446
+ throw new TypeError('missing params.OS');
447
+ }
448
+ // MIS is mandatory.
449
+ if (typeof params.MIS !== 'number') {
450
+ throw new TypeError('missing params.MIS');
451
+ }
452
+ // maxMessageSize is mandatory.
453
+ if (typeof params.maxMessageSize !== 'number') {
454
+ throw new TypeError('missing params.maxMessageSize');
455
+ }
456
+ }
457
+ exports.validateSctpParameters = validateSctpParameters;
458
+ /**
459
+ * Validates SctpStreamParameters. It may modify given data by adding missing
460
+ * fields with default values.
461
+ * It throws if invalid.
462
+ */
463
+ function validateSctpStreamParameters(params) {
464
+ if (typeof params !== 'object') {
465
+ throw new TypeError('params is not an object');
466
+ }
467
+ // streamId is mandatory.
468
+ if (typeof params.streamId !== 'number') {
469
+ throw new TypeError('missing params.streamId');
470
+ }
471
+ // ordered is optional.
472
+ let orderedGiven = false;
473
+ if (typeof params.ordered === 'boolean') {
474
+ orderedGiven = true;
475
+ }
476
+ else {
477
+ params.ordered = true;
478
+ }
479
+ // maxPacketLifeTime is optional.
480
+ if (params.maxPacketLifeTime && typeof params.maxPacketLifeTime !== 'number') {
481
+ throw new TypeError('invalid params.maxPacketLifeTime');
482
+ }
483
+ // maxRetransmits is optional.
484
+ if (params.maxRetransmits && typeof params.maxRetransmits !== 'number') {
485
+ throw new TypeError('invalid params.maxRetransmits');
486
+ }
487
+ if (params.maxPacketLifeTime && params.maxRetransmits) {
488
+ throw new TypeError('cannot provide both maxPacketLifeTime and maxRetransmits');
489
+ }
490
+ if (orderedGiven &&
491
+ params.ordered &&
492
+ (params.maxPacketLifeTime || params.maxRetransmits)) {
493
+ throw new TypeError('cannot be ordered with maxPacketLifeTime or maxRetransmits');
494
+ }
495
+ else if (!orderedGiven && (params.maxPacketLifeTime || params.maxRetransmits)) {
496
+ params.ordered = false;
497
+ }
498
+ // label is optional.
499
+ if (params.label && typeof params.label !== 'string') {
500
+ throw new TypeError('invalid params.label');
501
+ }
502
+ // protocol is optional.
503
+ if (params.protocol && typeof params.protocol !== 'string') {
504
+ throw new TypeError('invalid params.protocol');
505
+ }
506
+ }
507
+ exports.validateSctpStreamParameters = validateSctpStreamParameters;
508
+ /**
509
+ * Generate extended RTP capabilities for sending and receiving.
510
+ */
511
+ function getExtendedRtpCapabilities(localCaps, remoteCaps) {
512
+ const extendedRtpCapabilities = {
513
+ codecs: [],
514
+ headerExtensions: []
515
+ };
516
+ // Match media codecs and keep the order preferred by remoteCaps.
517
+ for (const remoteCodec of remoteCaps.codecs || []) {
518
+ if (isRtxCodec(remoteCodec)) {
519
+ continue;
520
+ }
521
+ const matchingLocalCodec = (localCaps.codecs || [])
522
+ .find((localCodec) => (matchCodecs(localCodec, remoteCodec, { strict: true, modify: true })));
523
+ if (!matchingLocalCodec) {
524
+ continue;
525
+ }
526
+ const extendedCodec = {
527
+ mimeType: matchingLocalCodec.mimeType,
528
+ kind: matchingLocalCodec.kind,
529
+ clockRate: matchingLocalCodec.clockRate,
530
+ channels: matchingLocalCodec.channels,
531
+ localPayloadType: matchingLocalCodec.preferredPayloadType,
532
+ localRtxPayloadType: undefined,
533
+ remotePayloadType: remoteCodec.preferredPayloadType,
534
+ remoteRtxPayloadType: undefined,
535
+ localParameters: matchingLocalCodec.parameters,
536
+ remoteParameters: remoteCodec.parameters,
537
+ rtcpFeedback: reduceRtcpFeedback(matchingLocalCodec, remoteCodec)
538
+ };
539
+ extendedRtpCapabilities.codecs.push(extendedCodec);
540
+ }
541
+ // Match RTX codecs.
542
+ for (const extendedCodec of extendedRtpCapabilities.codecs) {
543
+ const matchingLocalRtxCodec = localCaps.codecs
544
+ .find((localCodec) => (isRtxCodec(localCodec) &&
545
+ localCodec.parameters.apt === extendedCodec.localPayloadType));
546
+ const matchingRemoteRtxCodec = remoteCaps.codecs
547
+ .find((remoteCodec) => (isRtxCodec(remoteCodec) &&
548
+ remoteCodec.parameters.apt === extendedCodec.remotePayloadType));
549
+ if (matchingLocalRtxCodec && matchingRemoteRtxCodec) {
550
+ extendedCodec.localRtxPayloadType = matchingLocalRtxCodec.preferredPayloadType;
551
+ extendedCodec.remoteRtxPayloadType = matchingRemoteRtxCodec.preferredPayloadType;
552
+ }
553
+ }
554
+ // Match header extensions.
555
+ for (const remoteExt of remoteCaps.headerExtensions) {
556
+ const matchingLocalExt = localCaps.headerExtensions
557
+ .find((localExt) => (matchHeaderExtensions(localExt, remoteExt)));
558
+ if (!matchingLocalExt) {
559
+ continue;
560
+ }
561
+ const extendedExt = {
562
+ kind: remoteExt.kind,
563
+ uri: remoteExt.uri,
564
+ sendId: matchingLocalExt.preferredId,
565
+ recvId: remoteExt.preferredId,
566
+ encrypt: matchingLocalExt.preferredEncrypt,
567
+ direction: 'sendrecv'
568
+ };
569
+ switch (remoteExt.direction) {
570
+ case 'sendrecv':
571
+ extendedExt.direction = 'sendrecv';
572
+ break;
573
+ case 'recvonly':
574
+ extendedExt.direction = 'sendonly';
575
+ break;
576
+ case 'sendonly':
577
+ extendedExt.direction = 'recvonly';
578
+ break;
579
+ case 'inactive':
580
+ extendedExt.direction = 'inactive';
581
+ break;
582
+ }
583
+ extendedRtpCapabilities.headerExtensions.push(extendedExt);
584
+ }
585
+ return extendedRtpCapabilities;
586
+ }
587
+ exports.getExtendedRtpCapabilities = getExtendedRtpCapabilities;
588
+ /**
589
+ * Generate RTP capabilities for receiving media based on the given extended
590
+ * RTP capabilities.
591
+ */
592
+ function getRecvRtpCapabilities(extendedRtpCapabilities) {
593
+ const rtpCapabilities = {
594
+ codecs: [],
595
+ headerExtensions: []
596
+ };
597
+ for (const extendedCodec of extendedRtpCapabilities.codecs) {
598
+ const codec = {
599
+ mimeType: extendedCodec.mimeType,
600
+ kind: extendedCodec.kind,
601
+ preferredPayloadType: extendedCodec.remotePayloadType,
602
+ clockRate: extendedCodec.clockRate,
603
+ channels: extendedCodec.channels,
604
+ parameters: extendedCodec.localParameters,
605
+ rtcpFeedback: extendedCodec.rtcpFeedback
606
+ };
607
+ rtpCapabilities.codecs.push(codec);
608
+ // Add RTX codec.
609
+ if (!extendedCodec.remoteRtxPayloadType) {
610
+ continue;
611
+ }
612
+ const rtxCodec = {
613
+ mimeType: `${extendedCodec.kind}/rtx`,
614
+ kind: extendedCodec.kind,
615
+ preferredPayloadType: extendedCodec.remoteRtxPayloadType,
616
+ clockRate: extendedCodec.clockRate,
617
+ parameters: {
618
+ apt: extendedCodec.remotePayloadType
619
+ },
620
+ rtcpFeedback: []
621
+ };
622
+ rtpCapabilities.codecs.push(rtxCodec);
623
+ // TODO: In the future, we need to add FEC, CN, etc, codecs.
624
+ }
625
+ for (const extendedExtension of extendedRtpCapabilities.headerExtensions) {
626
+ // Ignore RTP extensions not valid for receiving.
627
+ if (extendedExtension.direction !== 'sendrecv' &&
628
+ extendedExtension.direction !== 'recvonly') {
629
+ continue;
630
+ }
631
+ const ext = {
632
+ kind: extendedExtension.kind,
633
+ uri: extendedExtension.uri,
634
+ preferredId: extendedExtension.recvId,
635
+ preferredEncrypt: extendedExtension.encrypt,
636
+ direction: extendedExtension.direction
637
+ };
638
+ rtpCapabilities.headerExtensions.push(ext);
639
+ }
640
+ return rtpCapabilities;
641
+ }
642
+ exports.getRecvRtpCapabilities = getRecvRtpCapabilities;
643
+ /**
644
+ * Generate RTP parameters of the given kind for sending media.
645
+ * NOTE: mid, encodings and rtcp fields are left empty.
646
+ */
647
+ function getSendingRtpParameters(kind, extendedRtpCapabilities) {
648
+ const rtpParameters = {
649
+ mid: undefined,
650
+ codecs: [],
651
+ headerExtensions: [],
652
+ encodings: [],
653
+ rtcp: {}
654
+ };
655
+ for (const extendedCodec of extendedRtpCapabilities.codecs) {
656
+ if (extendedCodec.kind !== kind) {
657
+ continue;
658
+ }
659
+ const codec = {
660
+ mimeType: extendedCodec.mimeType,
661
+ payloadType: extendedCodec.localPayloadType,
662
+ clockRate: extendedCodec.clockRate,
663
+ channels: extendedCodec.channels,
664
+ parameters: extendedCodec.localParameters,
665
+ rtcpFeedback: extendedCodec.rtcpFeedback
666
+ };
667
+ rtpParameters.codecs.push(codec);
668
+ // Add RTX codec.
669
+ if (extendedCodec.localRtxPayloadType) {
670
+ const rtxCodec = {
671
+ mimeType: `${extendedCodec.kind}/rtx`,
672
+ payloadType: extendedCodec.localRtxPayloadType,
673
+ clockRate: extendedCodec.clockRate,
674
+ parameters: {
675
+ apt: extendedCodec.localPayloadType
676
+ },
677
+ rtcpFeedback: []
678
+ };
679
+ rtpParameters.codecs.push(rtxCodec);
680
+ }
681
+ }
682
+ for (const extendedExtension of extendedRtpCapabilities.headerExtensions) {
683
+ // Ignore RTP extensions of a different kind and those not valid for sending.
684
+ if ((extendedExtension.kind && extendedExtension.kind !== kind) ||
685
+ (extendedExtension.direction !== 'sendrecv' &&
686
+ extendedExtension.direction !== 'sendonly')) {
687
+ continue;
688
+ }
689
+ const ext = {
690
+ uri: extendedExtension.uri,
691
+ id: extendedExtension.sendId,
692
+ encrypt: extendedExtension.encrypt,
693
+ parameters: {}
694
+ };
695
+ rtpParameters.headerExtensions.push(ext);
696
+ }
697
+ return rtpParameters;
698
+ }
699
+ exports.getSendingRtpParameters = getSendingRtpParameters;
700
+ /**
701
+ * Generate RTP parameters of the given kind suitable for the remote SDP answer.
702
+ */
703
+ function getSendingRemoteRtpParameters(kind, extendedRtpCapabilities) {
704
+ const rtpParameters = {
705
+ mid: undefined,
706
+ codecs: [],
707
+ headerExtensions: [],
708
+ encodings: [],
709
+ rtcp: {}
710
+ };
711
+ for (const extendedCodec of extendedRtpCapabilities.codecs) {
712
+ if (extendedCodec.kind !== kind) {
713
+ continue;
714
+ }
715
+ const codec = {
716
+ mimeType: extendedCodec.mimeType,
717
+ payloadType: extendedCodec.localPayloadType,
718
+ clockRate: extendedCodec.clockRate,
719
+ channels: extendedCodec.channels,
720
+ parameters: extendedCodec.remoteParameters,
721
+ rtcpFeedback: extendedCodec.rtcpFeedback
722
+ };
723
+ rtpParameters.codecs.push(codec);
724
+ // Add RTX codec.
725
+ if (extendedCodec.localRtxPayloadType) {
726
+ const rtxCodec = {
727
+ mimeType: `${extendedCodec.kind}/rtx`,
728
+ payloadType: extendedCodec.localRtxPayloadType,
729
+ clockRate: extendedCodec.clockRate,
730
+ parameters: {
731
+ apt: extendedCodec.localPayloadType
732
+ },
733
+ rtcpFeedback: []
734
+ };
735
+ rtpParameters.codecs.push(rtxCodec);
736
+ }
737
+ }
738
+ for (const extendedExtension of extendedRtpCapabilities.headerExtensions) {
739
+ // Ignore RTP extensions of a different kind and those not valid for sending.
740
+ if ((extendedExtension.kind && extendedExtension.kind !== kind) ||
741
+ (extendedExtension.direction !== 'sendrecv' &&
742
+ extendedExtension.direction !== 'sendonly')) {
743
+ continue;
744
+ }
745
+ const ext = {
746
+ uri: extendedExtension.uri,
747
+ id: extendedExtension.sendId,
748
+ encrypt: extendedExtension.encrypt,
749
+ parameters: {}
750
+ };
751
+ rtpParameters.headerExtensions.push(ext);
752
+ }
753
+ // Reduce codecs' RTCP feedback. Use Transport-CC if available, REMB otherwise.
754
+ if (rtpParameters.headerExtensions.some((ext) => (ext.uri === 'http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01'))) {
755
+ for (const codec of rtpParameters.codecs) {
756
+ codec.rtcpFeedback = (codec.rtcpFeedback || [])
757
+ .filter((fb) => fb.type !== 'goog-remb');
758
+ }
759
+ }
760
+ else if (rtpParameters.headerExtensions.some((ext) => (ext.uri === 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time'))) {
761
+ for (const codec of rtpParameters.codecs) {
762
+ codec.rtcpFeedback = (codec.rtcpFeedback || [])
763
+ .filter((fb) => fb.type !== 'transport-cc');
764
+ }
765
+ }
766
+ else {
767
+ for (const codec of rtpParameters.codecs) {
768
+ codec.rtcpFeedback = (codec.rtcpFeedback || [])
769
+ .filter((fb) => (fb.type !== 'transport-cc' &&
770
+ fb.type !== 'goog-remb'));
771
+ }
772
+ }
773
+ return rtpParameters;
774
+ }
775
+ exports.getSendingRemoteRtpParameters = getSendingRemoteRtpParameters;
776
+ /**
777
+ * Reduce given codecs by returning an array of codecs "compatible" with the
778
+ * given capability codec. If no capability codec is given, take the first
779
+ * one(s).
780
+ *
781
+ * Given codecs must be generated by ortc.getSendingRtpParameters() or
782
+ * ortc.getSendingRemoteRtpParameters().
783
+ *
784
+ * The returned array of codecs also include a RTX codec if available.
785
+ */
786
+ function reduceCodecs(codecs, capCodec) {
787
+ const filteredCodecs = [];
788
+ // If no capability codec is given, take the first one (and RTX).
789
+ if (!capCodec) {
790
+ filteredCodecs.push(codecs[0]);
791
+ if (isRtxCodec(codecs[1])) {
792
+ filteredCodecs.push(codecs[1]);
793
+ }
794
+ }
795
+ // Otherwise look for a compatible set of codecs.
796
+ else {
797
+ for (let idx = 0; idx < codecs.length; ++idx) {
798
+ if (matchCodecs(codecs[idx], capCodec)) {
799
+ filteredCodecs.push(codecs[idx]);
800
+ if (isRtxCodec(codecs[idx + 1])) {
801
+ filteredCodecs.push(codecs[idx + 1]);
802
+ }
803
+ break;
804
+ }
805
+ }
806
+ if (filteredCodecs.length === 0) {
807
+ throw new TypeError('no matching codec found');
808
+ }
809
+ }
810
+ return filteredCodecs;
811
+ }
812
+ exports.reduceCodecs = reduceCodecs;
813
+ /**
814
+ * Create RTP parameters for a Consumer for the RTP probator.
815
+ */
816
+ function generateProbatorRtpParameters(videoRtpParameters) {
817
+ // Clone given reference video RTP parameters.
818
+ videoRtpParameters = utils.clone(videoRtpParameters, {});
819
+ // This may throw.
820
+ validateRtpParameters(videoRtpParameters);
821
+ const rtpParameters = {
822
+ mid: RTP_PROBATOR_MID,
823
+ codecs: [],
824
+ headerExtensions: [],
825
+ encodings: [{ ssrc: RTP_PROBATOR_SSRC }],
826
+ rtcp: { cname: 'probator' }
827
+ };
828
+ rtpParameters.codecs.push(videoRtpParameters.codecs[0]);
829
+ rtpParameters.codecs[0].payloadType = RTP_PROBATOR_CODEC_PAYLOAD_TYPE;
830
+ rtpParameters.headerExtensions = videoRtpParameters.headerExtensions;
831
+ return rtpParameters;
832
+ }
833
+ exports.generateProbatorRtpParameters = generateProbatorRtpParameters;
834
+ /**
835
+ * Whether media can be sent based on the given RTP capabilities.
836
+ */
837
+ function canSend(kind, extendedRtpCapabilities) {
838
+ return extendedRtpCapabilities.codecs.
839
+ some((codec) => codec.kind === kind);
840
+ }
841
+ exports.canSend = canSend;
842
+ /**
843
+ * Whether the given RTP parameters can be received with the given RTP
844
+ * capabilities.
845
+ */
846
+ function canReceive(rtpParameters, extendedRtpCapabilities) {
847
+ // This may throw.
848
+ validateRtpParameters(rtpParameters);
849
+ if (rtpParameters.codecs.length === 0) {
850
+ return false;
851
+ }
852
+ const firstMediaCodec = rtpParameters.codecs[0];
853
+ return extendedRtpCapabilities.codecs
854
+ .some((codec) => codec.remotePayloadType === firstMediaCodec.payloadType);
855
+ }
856
+ exports.canReceive = canReceive;
857
+ function isRtxCodec(codec) {
858
+ if (!codec) {
859
+ return false;
860
+ }
861
+ return /.+\/rtx$/i.test(codec.mimeType);
862
+ }
863
+ function matchCodecs(aCodec, bCodec, { strict = false, modify = false } = {}) {
864
+ const aMimeType = aCodec.mimeType.toLowerCase();
865
+ const bMimeType = bCodec.mimeType.toLowerCase();
866
+ if (aMimeType !== bMimeType) {
867
+ return false;
868
+ }
869
+ if (aCodec.clockRate !== bCodec.clockRate) {
870
+ return false;
871
+ }
872
+ if (aCodec.channels !== bCodec.channels) {
873
+ return false;
874
+ }
875
+ // Per codec special checks.
876
+ switch (aMimeType) {
877
+ case 'video/h264':
878
+ {
879
+ if (strict) {
880
+ const aPacketizationMode = aCodec.parameters['packetization-mode'] || 0;
881
+ const bPacketizationMode = bCodec.parameters['packetization-mode'] || 0;
882
+ if (aPacketizationMode !== bPacketizationMode) {
883
+ return false;
884
+ }
885
+ if (!h264.isSameProfile(aCodec.parameters, bCodec.parameters)) {
886
+ return false;
887
+ }
888
+ let selectedProfileLevelId;
889
+ try {
890
+ selectedProfileLevelId =
891
+ h264.generateProfileLevelIdForAnswer(aCodec.parameters, bCodec.parameters);
892
+ }
893
+ catch (error) {
894
+ return false;
895
+ }
896
+ if (modify) {
897
+ if (selectedProfileLevelId) {
898
+ aCodec.parameters['profile-level-id'] = selectedProfileLevelId;
899
+ bCodec.parameters['profile-level-id'] = selectedProfileLevelId;
900
+ }
901
+ else {
902
+ delete aCodec.parameters['profile-level-id'];
903
+ delete bCodec.parameters['profile-level-id'];
904
+ }
905
+ }
906
+ }
907
+ break;
908
+ }
909
+ case 'video/vp9':
910
+ {
911
+ if (strict) {
912
+ const aProfileId = aCodec.parameters['profile-id'] || 0;
913
+ const bProfileId = bCodec.parameters['profile-id'] || 0;
914
+ if (aProfileId !== bProfileId) {
915
+ return false;
916
+ }
917
+ }
918
+ break;
919
+ }
920
+ }
921
+ return true;
922
+ }
923
+ function matchHeaderExtensions(aExt, bExt) {
924
+ if (aExt.kind && bExt.kind && aExt.kind !== bExt.kind) {
925
+ return false;
926
+ }
927
+ if (aExt.uri !== bExt.uri) {
928
+ return false;
929
+ }
930
+ return true;
931
+ }
932
+ function reduceRtcpFeedback(codecA, codecB) {
933
+ const reducedRtcpFeedback = [];
934
+ for (const aFb of codecA.rtcpFeedback || []) {
935
+ const matchingBFb = (codecB.rtcpFeedback || [])
936
+ .find((bFb) => (bFb.type === aFb.type &&
937
+ (bFb.parameter === aFb.parameter || (!bFb.parameter && !aFb.parameter))));
938
+ if (matchingBFb) {
939
+ reducedRtcpFeedback.push(matchingBFb);
940
+ }
941
+ }
942
+ return reducedRtcpFeedback;
943
+ }