@voicenter-team/opensips-js 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +75 -0
  2. package/build/enum/call.event.listener.type.d.ts +7 -0
  3. package/build/enum/call.event.listener.type.js +10 -0
  4. package/build/enum/metric.keys.to.include.d.ts +2 -0
  5. package/build/enum/metric.keys.to.include.js +4 -0
  6. package/build/helpers/UA/index.d.ts +6 -0
  7. package/build/helpers/UA/index.js +9 -0
  8. package/build/helpers/audio.helper.d.ts +9 -0
  9. package/build/helpers/audio.helper.js +60 -0
  10. package/build/helpers/filter.helper.d.ts +2 -0
  11. package/build/helpers/filter.helper.js +14 -0
  12. package/build/helpers/time.helper.d.ts +16 -0
  13. package/build/helpers/time.helper.js +28 -0
  14. package/build/helpers/volume.helper.d.ts +2 -0
  15. package/build/helpers/volume.helper.js +76 -0
  16. package/build/helpers/webrtcmetrics/collector.d.ts +32 -0
  17. package/build/helpers/webrtcmetrics/collector.js +282 -0
  18. package/build/helpers/webrtcmetrics/engine.d.ts +20 -0
  19. package/build/helpers/webrtcmetrics/engine.js +164 -0
  20. package/build/helpers/webrtcmetrics/exporter.d.ts +116 -0
  21. package/build/helpers/webrtcmetrics/exporter.js +528 -0
  22. package/build/helpers/webrtcmetrics/extractor.d.ts +1 -0
  23. package/build/helpers/webrtcmetrics/extractor.js +976 -0
  24. package/build/helpers/webrtcmetrics/index.d.ts +63 -0
  25. package/build/helpers/webrtcmetrics/index.js +93 -0
  26. package/build/helpers/webrtcmetrics/metrics.d.ts +2 -0
  27. package/build/helpers/webrtcmetrics/metrics.js +8 -0
  28. package/build/helpers/webrtcmetrics/probe.d.ts +76 -0
  29. package/build/helpers/webrtcmetrics/probe.js +153 -0
  30. package/build/helpers/webrtcmetrics/utils/config.d.ts +12 -0
  31. package/build/helpers/webrtcmetrics/utils/config.js +28 -0
  32. package/build/helpers/webrtcmetrics/utils/helper.d.ts +13 -0
  33. package/build/helpers/webrtcmetrics/utils/helper.js +134 -0
  34. package/build/helpers/webrtcmetrics/utils/log.d.ts +7 -0
  35. package/build/helpers/webrtcmetrics/utils/log.js +71 -0
  36. package/build/helpers/webrtcmetrics/utils/models.d.ts +309 -0
  37. package/build/helpers/webrtcmetrics/utils/models.js +298 -0
  38. package/build/helpers/webrtcmetrics/utils/score.d.ts +4 -0
  39. package/build/helpers/webrtcmetrics/utils/score.js +235 -0
  40. package/build/helpers/webrtcmetrics/utils/shortUUId.d.ts +1 -0
  41. package/build/helpers/webrtcmetrics/utils/shortUUId.js +7 -0
  42. package/build/index.d.ts +170 -0
  43. package/build/index.js +849 -0
  44. package/package.json +61 -0
  45. package/src/types/declarations.d.ts +6 -0
  46. package/src/types/generic.d.ts +1 -0
  47. package/src/types/listeners.d.ts +42 -0
  48. package/src/types/rtc.d.ts +133 -0
  49. package/src/types/webrtcmetrics.d.ts +64 -0
@@ -0,0 +1,976 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extract = void 0;
4
+ const models_1 = require("./utils/models");
5
+ const helper_1 = require("./utils/helper");
6
+ const log_1 = require("./utils/log");
7
+ const moduleName = "extractor ";
8
+ const extractRTTBasedOnRTCP = (bunch, kind, referenceReport, previousBunch) => {
9
+ let supportOfMeasure = false;
10
+ const previousRTT = previousBunch[kind].total_rtt_ms_out;
11
+ const previousNbMeasure = previousBunch[kind].total_rtt_measure_out;
12
+ const referenceRTT = referenceReport
13
+ ? referenceReport[kind].total_rtt_ms_out
14
+ : 0;
15
+ const referenceNbMeasure = referenceReport
16
+ ? referenceReport[kind].total_rtt_measure_out
17
+ : 0;
18
+ const returnedValuesByDefault = {
19
+ rtt: null,
20
+ totalRTT: previousRTT,
21
+ totalRTTMeasurements: previousNbMeasure,
22
+ };
23
+ if (bunch[models_1.PROPERTY.TIMESTAMP] === previousBunch[kind].timestamp_out) {
24
+ return returnedValuesByDefault;
25
+ }
26
+ // If RTT is not part of the stat - return
27
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.ROUND_TRIP_TIME)) {
28
+ return returnedValuesByDefault;
29
+ }
30
+ // If no measure yet or no new measure - return
31
+ if (Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.TOTAL_ROUND_TRIP_TIME_MEASUREMENTS)) {
32
+ supportOfMeasure = true;
33
+ if (Number(bunch[models_1.PROPERTY.TOTAL_ROUND_TRIP_TIME_MEASUREMENTS]) === 0 ||
34
+ Number(bunch[models_1.PROPERTY.TOTAL_ROUND_TRIP_TIME_MEASUREMENTS]) -
35
+ referenceNbMeasure ===
36
+ previousNbMeasure) {
37
+ return returnedValuesByDefault;
38
+ }
39
+ }
40
+ const currentRTT = Number(1000) * Number(bunch[models_1.PROPERTY.ROUND_TRIP_TIME]);
41
+ let currentTotalRTT = previousRTT + currentRTT;
42
+ let currentTotalMeasurements = previousNbMeasure + 1;
43
+ // If support of totalRoundTripTime
44
+ if (supportOfMeasure) {
45
+ currentTotalRTT =
46
+ Number(1000) * Number(bunch[models_1.PROPERTY.TOTAL_ROUND_TRIP_TIME]) -
47
+ referenceRTT;
48
+ currentTotalMeasurements =
49
+ Number(bunch[models_1.PROPERTY.TOTAL_ROUND_TRIP_TIME_MEASUREMENTS]) -
50
+ referenceNbMeasure;
51
+ }
52
+ return {
53
+ rtt: currentRTT,
54
+ totalRTT: currentTotalRTT,
55
+ totalRTTMeasurements: currentTotalMeasurements,
56
+ };
57
+ };
58
+ const extractRTTBasedOnSTUNConnectivityCheck = (bunch, kind, referenceReport, previousBunch) => {
59
+ // If RTT is not part of the stat - return null value
60
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.CURRENT_ROUND_TRIP_TIME)) {
61
+ return {
62
+ rtt: null,
63
+ totalRTT: previousBunch[kind].total_rtt_connectivity_ms,
64
+ totalRTTMeasurements: previousBunch[kind].total_rtt_connectivity_measure,
65
+ };
66
+ }
67
+ const currentRTT = Number(1000) * Number(bunch[models_1.PROPERTY.CURRENT_ROUND_TRIP_TIME]);
68
+ let currentTotalRTT = previousBunch[kind].total_rtt_connectivity_ms + currentRTT;
69
+ let currentTotalMeasurements = previousBunch[kind].total_rtt_connectivity_measure + 1;
70
+ // If support of totalRoundTripTime
71
+ if (Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.TOTAL_ROUND_TRIP_TIME)) {
72
+ currentTotalRTT =
73
+ Number(1000) * Number(bunch[models_1.PROPERTY.TOTAL_ROUND_TRIP_TIME]) -
74
+ (referenceReport
75
+ ? referenceReport[kind].total_rtt_connectivity_ms
76
+ : 0);
77
+ }
78
+ // If support of responsesReceived
79
+ if (Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.RESPONSES_RECEIVED)) {
80
+ currentTotalMeasurements =
81
+ Number(bunch[models_1.PROPERTY.RESPONSES_RECEIVED]) -
82
+ (referenceReport
83
+ ? referenceReport[kind].total_rtt_connectivity_measure
84
+ : 0);
85
+ }
86
+ return {
87
+ rtt: currentRTT,
88
+ totalRTT: currentTotalRTT,
89
+ totalRTTMeasurements: currentTotalMeasurements,
90
+ };
91
+ };
92
+ const extractLastJitter = (bunch, kind, previousBunch) => {
93
+ if (bunch[models_1.PROPERTY.TIMESTAMP] === previousBunch[kind].timestamp_out) {
94
+ return null;
95
+ }
96
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.JITTER)) {
97
+ return null;
98
+ }
99
+ return Number(1000) * (Number(bunch[models_1.PROPERTY.JITTER]) || 0);
100
+ };
101
+ const extractDecodeTime = (bunch, previousBunch) => {
102
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.FRAMES_DECODED) ||
103
+ !Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.TOTAL_DECODE_TIME)) {
104
+ return {
105
+ delta_ms_decode_frame: previousBunch[models_1.VALUE.VIDEO].delta_ms_decode_frame_in,
106
+ frames_decoded: previousBunch[models_1.VALUE.VIDEO].total_frames_decoded_in,
107
+ total_decode_time: previousBunch[models_1.VALUE.VIDEO].total_time_decoded_in,
108
+ };
109
+ }
110
+ const decodedFrames = bunch[models_1.PROPERTY.FRAMES_DECODED];
111
+ const totalDecodeTime = bunch[models_1.PROPERTY.TOTAL_DECODE_TIME];
112
+ const decodeTimeDelta = totalDecodeTime - previousBunch[models_1.VALUE.VIDEO].total_time_decoded_in;
113
+ const frameDelta = decodedFrames - previousBunch[models_1.VALUE.VIDEO].total_frames_decoded_in;
114
+ return {
115
+ delta_ms_decode_frame: frameDelta > 0 ? (decodeTimeDelta * 1000) / frameDelta : 0,
116
+ frames_decoded: decodedFrames,
117
+ total_decode_time: totalDecodeTime,
118
+ };
119
+ };
120
+ const extractEncodeTime = (bunch, previousBunch) => {
121
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.FRAMES_ENCODED) ||
122
+ !Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.TOTAL_ENCODE_TIME)) {
123
+ return {
124
+ delta_ms_encode_frame: previousBunch[models_1.VALUE.VIDEO].delta_ms_encode_frame_out,
125
+ frames_encoded: previousBunch[models_1.VALUE.VIDEO].total_frames_encoded_out,
126
+ total_encode_time: previousBunch[models_1.VALUE.VIDEO].total_time_encoded_out,
127
+ };
128
+ }
129
+ const encodedFrames = bunch[models_1.PROPERTY.FRAMES_ENCODED];
130
+ const totalEncodeTime = bunch[models_1.PROPERTY.TOTAL_ENCODE_TIME];
131
+ const encodeTimeDelta = totalEncodeTime - previousBunch[models_1.VALUE.VIDEO].total_time_encoded_out;
132
+ const frameDelta = encodedFrames - previousBunch[models_1.VALUE.VIDEO].total_frames_encoded_out;
133
+ const framesEncodedDelta = frameDelta > 0 && encodeTimeDelta
134
+ ? (encodeTimeDelta * 1000) / frameDelta
135
+ : 0;
136
+ return {
137
+ delta_ms_encode_frame: framesEncodedDelta,
138
+ frames_encoded: encodedFrames,
139
+ total_encode_time: totalEncodeTime,
140
+ };
141
+ };
142
+ const extractAudioVideoPacketSent = (bunch, kind, previousBunch, referenceReport) => {
143
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.PACKETS_SENT) ||
144
+ !Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.BYTES_SENT)) {
145
+ return {
146
+ packetsSent: previousBunch[kind].total_packets_out,
147
+ packetsLost: previousBunch[kind].total_packets_lost_out,
148
+ bytesSent: previousBunch[kind].total_KBytes_out,
149
+ };
150
+ }
151
+ const packetsSent = Number(bunch[models_1.PROPERTY.PACKETS_SENT]) ||
152
+ 0 - (referenceReport ? referenceReport[kind].total_packets_out : 0);
153
+ const deltaPacketsSent = packetsSent - previousBunch[kind].total_packets_out;
154
+ const KBytesSent = (Number(bunch[models_1.PROPERTY.BYTES_SENT]) / 1024) - (referenceReport ? referenceReport[kind].total_KBytes_out : 0);
155
+ const deltaKBytesSent = KBytesSent - previousBunch[kind].total_KBytes_out;
156
+ const timestamp = bunch[models_1.PROPERTY.TIMESTAMP] || Date.now();
157
+ const referenceTimestamp = referenceReport ? referenceReport.timestamp : null;
158
+ let previousTimestamp = previousBunch.timestamp;
159
+ if (!previousTimestamp && referenceTimestamp) {
160
+ previousTimestamp = referenceTimestamp;
161
+ }
162
+ const deltaMs = previousTimestamp ? timestamp - previousTimestamp : 0;
163
+ const kbsSent = deltaMs > 0 ? ((deltaKBytesSent * 0.008 * 1024) / deltaMs) * 1000 : 0; // kbs = kilo bits per second
164
+ return {
165
+ packetsSent,
166
+ deltaPacketsSent,
167
+ KBytesSent,
168
+ deltaKBytesSent,
169
+ kbsSent,
170
+ };
171
+ };
172
+ const extractAudioVideoPacketLost = (bunch, kind, previousBunch, referenceReport) => {
173
+ let packetsLost = previousBunch[kind].total_packets_lost_out;
174
+ let deltaPacketsLost = 0;
175
+ let fractionLost = 0;
176
+ if (Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.PACKETS_LOST)) {
177
+ packetsLost = Number(bunch[models_1.PROPERTY.PACKETS_LOST]) || 0 - (referenceReport ? referenceReport[kind].total_packets_lost_out : 0);
178
+ deltaPacketsLost = packetsLost - previousBunch[kind].total_packets_lost_out;
179
+ }
180
+ if (Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.FRACTION_LOST)) {
181
+ fractionLost = Number(100 * bunch[models_1.PROPERTY.FRACTION_LOST]);
182
+ }
183
+ return {
184
+ packetsLost,
185
+ deltaPacketsLost,
186
+ fractionLost,
187
+ };
188
+ };
189
+ const extractAudioVideoPacketReceived = (bunch, kind, previousBunch, referenceReport) => {
190
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.PACKETS_RECEIVED) ||
191
+ !Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.PACKETS_LOST) ||
192
+ !Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.BYTES_RECEIVED)) {
193
+ return {
194
+ percent_packets_lost: previousBunch[kind].percent_packets_lost_in,
195
+ packetsReceived: previousBunch[kind].total_packets_in,
196
+ packetsLost: previousBunch[kind].total_packets_lost_in,
197
+ bytesReceived: previousBunch[kind].total_KBytes_in,
198
+ };
199
+ }
200
+ const packetsReceived = Number(bunch[models_1.PROPERTY.PACKETS_RECEIVED]) ||
201
+ 0 - (referenceReport ? referenceReport[kind].total_packets_in : 0);
202
+ const packetsLost = Number(bunch[models_1.PROPERTY.PACKETS_LOST]) ||
203
+ 0 - (referenceReport ? referenceReport[kind].total_packets_lost_in : 0);
204
+ const deltaPacketsLost = packetsLost - previousBunch[kind].total_packets_lost_in;
205
+ const deltaPacketsReceived = packetsReceived - previousBunch[kind].total_packets_in;
206
+ const percentPacketsLost = packetsReceived !== previousBunch[kind].total_packets_in
207
+ ? (deltaPacketsLost * 100) / (deltaPacketsLost + deltaPacketsReceived)
208
+ : 0.0;
209
+ const KBytesReceived = (Number(bunch[models_1.PROPERTY.BYTES_RECEIVED]) / 1024) - (referenceReport ? referenceReport[kind].total_KBytes_in : 0);
210
+ const deltaKBytesReceived = KBytesReceived - previousBunch[kind].total_KBytes_in;
211
+ const timestamp = bunch[models_1.PROPERTY.TIMESTAMP] || Date.now();
212
+ const referenceTimestamp = referenceReport ? referenceReport.timestamp : null;
213
+ let previousTimestamp = previousBunch.timestamp;
214
+ if (!previousTimestamp && referenceTimestamp) {
215
+ previousTimestamp = referenceTimestamp;
216
+ }
217
+ const deltaMs = previousTimestamp ? timestamp - previousTimestamp : 0;
218
+ const kbsReceived = deltaMs > 0 ? ((deltaKBytesReceived * 0.008 * 1024) / deltaMs) * 1000 : 0; // kbs = kilo bits per second
219
+ return {
220
+ percentPacketsLost,
221
+ packetsReceived,
222
+ deltaPacketsReceived,
223
+ packetsLost,
224
+ deltaPacketsLost,
225
+ KBytesReceived,
226
+ deltaKBytesReceived,
227
+ kbsReceived,
228
+ };
229
+ };
230
+ const extractRelayProtocolUsed = (bunch) => {
231
+ const candidateType = bunch[models_1.PROPERTY.CANDIDATE_TYPE];
232
+ if (candidateType !== "relay") {
233
+ return "";
234
+ }
235
+ return bunch[models_1.PROPERTY.RELAY_PROTOCOL] || "";
236
+ };
237
+ const extractInfrastructureValue = (bunch) => {
238
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.NETWORK_TYPE)) {
239
+ // Assuming Wifi when not provided (firefox/Safari at this time)
240
+ return models_1.INFRASTRUCTURE_VALUE.WIFI;
241
+ }
242
+ switch (bunch[models_1.PROPERTY.NETWORK_TYPE]) {
243
+ case models_1.INFRASTRUCTURE_LABEL.ETHERNET:
244
+ return models_1.INFRASTRUCTURE_VALUE.ETHERNET;
245
+ case models_1.INFRASTRUCTURE_LABEL.CELLULAR_4G:
246
+ return models_1.INFRASTRUCTURE_VALUE.CELLULAR_4G;
247
+ case models_1.INFRASTRUCTURE_LABEL.WIFI:
248
+ return models_1.INFRASTRUCTURE_VALUE.WIFI;
249
+ default:
250
+ return models_1.INFRASTRUCTURE_VALUE.CELLULAR;
251
+ }
252
+ };
253
+ const extractVideoSize = (bunch) => {
254
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.FRAME_HEIGHT) ||
255
+ !Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.FRAME_WIDTH)) {
256
+ return { width: null, height: null, framerate: null };
257
+ }
258
+ return {
259
+ width: bunch[models_1.PROPERTY.FRAME_WIDTH] || null,
260
+ height: bunch[models_1.PROPERTY.FRAME_HEIGHT] || null,
261
+ framerate: bunch[models_1.PROPERTY.FRAMES_PER_SECOND],
262
+ };
263
+ };
264
+ const extractQualityLimitation = (bunch) => {
265
+ const reason = Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.QUALITY_LIMITATION_REASON)
266
+ ? bunch[models_1.PROPERTY.QUALITY_LIMITATION_REASON]
267
+ : null;
268
+ const resolutionChanges = Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.QUALITY_LIMITATION_RESOLUTION_CHANGES)
269
+ ? bunch[models_1.PROPERTY.QUALITY_LIMITATION_RESOLUTION_CHANGES]
270
+ : null;
271
+ const durations = Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.QUALITY_LIMITATION_DURATIONS)
272
+ ? bunch[models_1.PROPERTY.QUALITY_LIMITATION_DURATIONS]
273
+ : null;
274
+ if (durations) {
275
+ Object.keys(durations).forEach((key) => {
276
+ if (durations[key] > 1000) {
277
+ durations[key] = Number(durations[key] / 1000);
278
+ }
279
+ });
280
+ }
281
+ return { reason, durations, resolutionChanges };
282
+ };
283
+ const extractNackAndPliCountSentWhenReceiving = (bunch, previousReport, referenceReport) => {
284
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.PLI) ||
285
+ !Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.NACK)) {
286
+ return {
287
+ pliCount: previousReport.total_pli_sent_in,
288
+ nackCount: previousReport.total_nack_sent_in,
289
+ deltaPliCount: 0,
290
+ deltaNackCount: 0,
291
+ };
292
+ }
293
+ const pliCount = (bunch[models_1.PROPERTY.PLI] || 0) - (referenceReport ? referenceReport[models_1.VALUE.VIDEO].total_pli_sent_in : 0);
294
+ const nackCount = (bunch[models_1.PROPERTY.NACK] || 0) - (referenceReport ? referenceReport[models_1.VALUE.VIDEO].total_nack_sent_in : 0);
295
+ return {
296
+ pliCount,
297
+ nackCount,
298
+ deltaPliCount: pliCount - previousReport[models_1.VALUE.VIDEO].total_pli_sent_in,
299
+ deltaNackCount: nackCount - previousReport[models_1.VALUE.VIDEO].total_nack_sent_in,
300
+ };
301
+ };
302
+ const extractNackAndPliCountReceivedWhenSending = (bunch, previousReport, referenceReport) => {
303
+ if (!Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.PLI) ||
304
+ !Object.prototype.hasOwnProperty.call(bunch, models_1.PROPERTY.NACK)) {
305
+ return {
306
+ pliCount: previousReport.total_pli_received_out,
307
+ nackCount: previousReport.total_nack_received_out,
308
+ deltaPliCount: 0,
309
+ deltaNackCount: 0,
310
+ };
311
+ }
312
+ const pliCount = (bunch[models_1.PROPERTY.PLI] || 0) - (referenceReport ? referenceReport[models_1.VALUE.VIDEO].total_pli_received_out : 0);
313
+ const nackCount = (bunch[models_1.PROPERTY.NACK] || 0) - (referenceReport ? referenceReport[models_1.VALUE.VIDEO].total_nack_received_out : 0);
314
+ return {
315
+ pliCount,
316
+ nackCount,
317
+ deltaPliCount: pliCount - previousReport[models_1.VALUE.VIDEO].total_pli_received_out,
318
+ deltaNackCount: nackCount - previousReport[models_1.VALUE.VIDEO].total_nack_received_out,
319
+ };
320
+ };
321
+ const extractAudioCodec = (bunch) => ({
322
+ channels: bunch[models_1.PROPERTY.CHANNELS] || null,
323
+ clock_rate: bunch[models_1.PROPERTY.CLOCK_RATE] || null,
324
+ mime_type: bunch[models_1.PROPERTY.MIME_TYPE] || null,
325
+ sdp_fmtp_line: bunch[models_1.PROPERTY.SDP_FMTP_LINE] || null,
326
+ });
327
+ const extractVideoCodec = (bunch) => ({
328
+ clock_rate: bunch[models_1.PROPERTY.CLOCK_RATE] || null,
329
+ mime_type: bunch[models_1.PROPERTY.MIME_TYPE] || null,
330
+ });
331
+ const extractBytesSentReceived = (bunch, previousBunch, referenceReport) => {
332
+ const totalKBytesReceived = (bunch[models_1.PROPERTY.BYTES_RECEIVED] || 0) / 1024 -
333
+ (referenceReport ? referenceReport.data.total_KBytes_in : 0);
334
+ const totalKBytesSent = (bunch[models_1.PROPERTY.BYTES_SENT] || 0) / 1024 -
335
+ (referenceReport ? referenceReport.data.total_KBytes_out : 0);
336
+ const timestamp = bunch[models_1.PROPERTY.TIMESTAMP] || Date.now();
337
+ const KBytesReceived = totalKBytesReceived - previousBunch.data.total_KBytes_in;
338
+ const KBytesSent = totalKBytesSent - previousBunch.data.total_KBytes_out;
339
+ const referenceTimestamp = referenceReport ? referenceReport.timestamp : null;
340
+ let previousTimestamp = previousBunch.timestamp;
341
+ if (!previousTimestamp && referenceTimestamp) {
342
+ previousTimestamp = referenceTimestamp;
343
+ }
344
+ const deltaMs = previousTimestamp ? timestamp - previousTimestamp : 0;
345
+ const kbsSpeedReceived = deltaMs > 0 ? ((KBytesReceived * 0.008 * 1024) / deltaMs) * 1000 : 0; // kbs = kilo bits per second
346
+ const kbsSpeedSent = deltaMs > 0 ? ((KBytesSent * 0.008 * 1024) / deltaMs) * 1000 : 0;
347
+ return {
348
+ total_KBytes_received: totalKBytesReceived,
349
+ total_KBytes_sent: totalKBytesSent,
350
+ delta_KBytes_received: KBytesReceived,
351
+ delta_KBytes_sent: KBytesSent,
352
+ kbs_speed_received: kbsSpeedReceived,
353
+ kbs_speed_sent: kbsSpeedSent,
354
+ };
355
+ };
356
+ const extractAvailableBandwidth = (bunch) => {
357
+ const kbsIncomingBandwidth = bunch[models_1.PROPERTY.AVAILABLE_INCOMING_BITRATE] / 1024 || 0;
358
+ const kbsOutgoingBandwidth = bunch[models_1.PROPERTY.AVAILABLE_OUTGOING_BITRATE] / 1024 || 0;
359
+ return {
360
+ kbs_incoming_bandwidth: kbsIncomingBandwidth,
361
+ kbs_outgoing_bandwidth: kbsOutgoingBandwidth,
362
+ };
363
+ };
364
+ const extract = (bunch, previousBunch, pname, referenceReport) => {
365
+ if (!bunch) {
366
+ return [];
367
+ }
368
+ switch (bunch[models_1.PROPERTY.TYPE]) {
369
+ case models_1.TYPE.CANDIDATE_PAIR:
370
+ let selectedPair = false;
371
+ if (bunch[models_1.PROPERTY.NOMINATED] &&
372
+ bunch[models_1.PROPERTY.STATE] === models_1.VALUE.SUCCEEDED) {
373
+ selectedPair = true;
374
+ (0, log_1.debug)(moduleName, `analyze() - got stats ${bunch[models_1.PROPERTY.TYPE]} for ${pname}`, bunch);
375
+ // FF: Do not use candidate-pair with selected=false
376
+ if (models_1.PROPERTY.SELECTED in bunch && !bunch[models_1.PROPERTY.SELECTED]) {
377
+ selectedPair = false;
378
+ }
379
+ }
380
+ if (selectedPair) {
381
+ const localCandidateId = bunch[models_1.PROPERTY.LOCAL_CANDIDATE_ID];
382
+ const remoteCandidateId = bunch[models_1.PROPERTY.REMOTE_CANDIDATE_ID];
383
+ const valueSentReceived = extractBytesSentReceived(bunch, previousBunch, referenceReport);
384
+ const bandwidth = extractAvailableBandwidth(bunch);
385
+ const rttConnectivity = extractRTTBasedOnSTUNConnectivityCheck(bunch, "data", referenceReport, previousBunch);
386
+ return [
387
+ {
388
+ type: models_1.STAT_TYPE.NETWORK,
389
+ value: { local_candidate_id: localCandidateId },
390
+ },
391
+ {
392
+ type: models_1.STAT_TYPE.NETWORK,
393
+ value: { remote_candidate_id: remoteCandidateId },
394
+ },
395
+ {
396
+ type: models_1.STAT_TYPE.DATA,
397
+ value: { total_KBytes_in: valueSentReceived.total_KBytes_received },
398
+ },
399
+ {
400
+ type: models_1.STAT_TYPE.DATA,
401
+ value: { total_KBytes_out: valueSentReceived.total_KBytes_sent },
402
+ },
403
+ {
404
+ type: models_1.STAT_TYPE.DATA,
405
+ value: { delta_KBytes_in: valueSentReceived.delta_KBytes_received },
406
+ },
407
+ {
408
+ type: models_1.STAT_TYPE.DATA,
409
+ value: { delta_KBytes_out: valueSentReceived.delta_KBytes_sent },
410
+ },
411
+ {
412
+ type: models_1.STAT_TYPE.DATA,
413
+ value: { delta_kbs_in: valueSentReceived.kbs_speed_received },
414
+ },
415
+ {
416
+ type: models_1.STAT_TYPE.DATA,
417
+ value: { delta_kbs_out: valueSentReceived.kbs_speed_sent },
418
+ },
419
+ {
420
+ type: models_1.STAT_TYPE.DATA,
421
+ value: { delta_kbs_bandwidth_in: bandwidth.kbs_incoming_bandwidth },
422
+ },
423
+ {
424
+ type: models_1.STAT_TYPE.DATA,
425
+ value: {
426
+ delta_kbs_bandwidth_out: bandwidth.kbs_outgoing_bandwidth,
427
+ },
428
+ },
429
+ {
430
+ type: models_1.STAT_TYPE.DATA,
431
+ value: { delta_rtt_connectivity_ms: rttConnectivity.rtt },
432
+ },
433
+ {
434
+ type: models_1.STAT_TYPE.DATA,
435
+ value: { total_rtt_connectivity_ms: rttConnectivity.totalRTT },
436
+ },
437
+ {
438
+ type: models_1.STAT_TYPE.DATA,
439
+ value: {
440
+ total_rtt_connectivity_measure: rttConnectivity.totalRTTMeasurements,
441
+ },
442
+ },
443
+ ];
444
+ }
445
+ break;
446
+ case models_1.TYPE.LOCAL_CANDIDATE:
447
+ if (bunch[models_1.PROPERTY.ID] === previousBunch.network.local_candidate_id) {
448
+ return [
449
+ {
450
+ type: models_1.STAT_TYPE.NETWORK,
451
+ value: { infrastructure: extractInfrastructureValue(bunch) },
452
+ },
453
+ {
454
+ type: models_1.STAT_TYPE.NETWORK,
455
+ value: {
456
+ local_candidate_type: bunch[models_1.PROPERTY.CANDIDATE_TYPE] || "",
457
+ },
458
+ },
459
+ {
460
+ type: models_1.STAT_TYPE.NETWORK,
461
+ value: { local_candidate_protocol: bunch[models_1.PROPERTY.PROTOCOL] || "" },
462
+ },
463
+ {
464
+ type: models_1.STAT_TYPE.NETWORK,
465
+ value: {
466
+ local_candidate_relay_protocol: extractRelayProtocolUsed(bunch),
467
+ },
468
+ },
469
+ ];
470
+ }
471
+ break;
472
+ case models_1.TYPE.REMOTE_CANDIDATE:
473
+ if (bunch[models_1.PROPERTY.ID] === previousBunch.network.remote_candidate_id) {
474
+ return [
475
+ {
476
+ type: models_1.STAT_TYPE.NETWORK,
477
+ value: {
478
+ remote_candidate_type: bunch[models_1.PROPERTY.CANDIDATE_TYPE] || "",
479
+ },
480
+ },
481
+ {
482
+ type: models_1.STAT_TYPE.NETWORK,
483
+ value: {
484
+ remote_candidate_protocol: bunch[models_1.PROPERTY.PROTOCOL] || "",
485
+ },
486
+ },
487
+ ];
488
+ }
489
+ break;
490
+ case models_1.TYPE.INBOUND_RTP: {
491
+ (0, log_1.debug)(moduleName, `analyze() - got stats ${bunch[models_1.PROPERTY.TYPE]} for ${pname}`, bunch);
492
+ // get SSRC and associated data
493
+ const ssrc = bunch[models_1.PROPERTY.SSRC];
494
+ const previousSSRCBunch = (0, helper_1.getSSRCDataFromBunch)(ssrc, previousBunch, models_1.DIRECTION.INBOUND);
495
+ if (previousSSRCBunch) {
496
+ previousSSRCBunch.timestamp = previousBunch.timestamp;
497
+ }
498
+ const referenceSSRCBunch = (0, helper_1.getSSRCDataFromBunch)(ssrc, referenceReport, models_1.DIRECTION.INBOUND);
499
+ if (referenceSSRCBunch) {
500
+ referenceSSRCBunch.timestamp = referenceReport.timestamp;
501
+ }
502
+ if (bunch[models_1.PROPERTY.MEDIA_TYPE] === models_1.VALUE.AUDIO) {
503
+ // Packets stats and Bytes
504
+ const data = extractAudioVideoPacketReceived(bunch, models_1.VALUE.AUDIO, previousSSRCBunch, referenceSSRCBunch);
505
+ // Jitter stats
506
+ const jitter = extractLastJitter(bunch, models_1.VALUE.AUDIO, previousSSRCBunch);
507
+ // Codec stats
508
+ const audioInputCodecId = bunch[models_1.PROPERTY.CODEC_ID] || "";
509
+ return [
510
+ {
511
+ ssrc,
512
+ type: models_1.STAT_TYPE.AUDIO,
513
+ value: { codec_id_in: audioInputCodecId },
514
+ },
515
+ {
516
+ ssrc,
517
+ type: models_1.STAT_TYPE.AUDIO,
518
+ value: { total_packets_in: data.packetsReceived },
519
+ },
520
+ {
521
+ ssrc,
522
+ type: models_1.STAT_TYPE.AUDIO,
523
+ value: { delta_packets_in: data.deltaPacketsReceived },
524
+ },
525
+ {
526
+ ssrc,
527
+ type: models_1.STAT_TYPE.AUDIO,
528
+ value: { total_packets_lost_in: data.packetsLost },
529
+ },
530
+ {
531
+ ssrc,
532
+ type: models_1.STAT_TYPE.AUDIO,
533
+ value: { delta_packets_lost_in: data.deltaPacketsLost },
534
+ },
535
+ {
536
+ ssrc,
537
+ type: models_1.STAT_TYPE.AUDIO,
538
+ value: { percent_packets_lost_in: data.percentPacketsLost },
539
+ },
540
+ {
541
+ ssrc,
542
+ type: models_1.STAT_TYPE.AUDIO,
543
+ value: { total_KBytes_in: data.KBytesReceived },
544
+ },
545
+ {
546
+ ssrc,
547
+ type: models_1.STAT_TYPE.AUDIO,
548
+ value: { delta_KBytes_in: data.deltaKBytesReceived },
549
+ },
550
+ {
551
+ ssrc,
552
+ type: models_1.STAT_TYPE.AUDIO,
553
+ value: { delta_kbs_in: data.kbsReceived },
554
+ },
555
+ {
556
+ ssrc,
557
+ type: models_1.STAT_TYPE.AUDIO,
558
+ value: { delta_jitter_ms_in: jitter },
559
+ },
560
+ ];
561
+ }
562
+ if (bunch[models_1.PROPERTY.MEDIA_TYPE] === models_1.VALUE.VIDEO) {
563
+ // Decode time stats
564
+ const data = extractDecodeTime(bunch, previousSSRCBunch);
565
+ // Packets stats and Bytes
566
+ const packetsData = extractAudioVideoPacketReceived(bunch, models_1.VALUE.VIDEO, previousSSRCBunch, referenceSSRCBunch);
567
+ // Jitter stats
568
+ const jitter = extractLastJitter(bunch, models_1.VALUE.VIDEO, previousSSRCBunch);
569
+ // Codec stats
570
+ const decoderImplementation = bunch[models_1.PROPERTY.DECODER_IMPLEMENTATION] || null;
571
+ const videoInputCodecId = bunch[models_1.PROPERTY.CODEC_ID] || null;
572
+ // Video size
573
+ const inputVideo = extractVideoSize(bunch);
574
+ // Nack & Pli stats
575
+ const nackPliData = extractNackAndPliCountSentWhenReceiving(bunch, previousSSRCBunch, referenceSSRCBunch);
576
+ return [
577
+ {
578
+ ssrc,
579
+ type: models_1.STAT_TYPE.VIDEO,
580
+ value: { codec_id_in: videoInputCodecId },
581
+ },
582
+ {
583
+ ssrc,
584
+ type: models_1.STAT_TYPE.VIDEO,
585
+ value: { total_packets_in: packetsData.packetsReceived },
586
+ },
587
+ {
588
+ ssrc,
589
+ type: models_1.STAT_TYPE.VIDEO,
590
+ value: { delta_packets_in: packetsData.deltaPacketsReceived },
591
+ },
592
+ {
593
+ ssrc,
594
+ type: models_1.STAT_TYPE.VIDEO,
595
+ value: { total_packets_lost_in: packetsData.packetsLost },
596
+ },
597
+ {
598
+ ssrc,
599
+ type: models_1.STAT_TYPE.VIDEO,
600
+ value: { delta_packets_lost_in: packetsData.deltaPacketsLost },
601
+ },
602
+ {
603
+ ssrc,
604
+ type: models_1.STAT_TYPE.VIDEO,
605
+ value: { percent_packets_lost_in: packetsData.percentPacketsLost },
606
+ },
607
+ {
608
+ ssrc,
609
+ type: models_1.STAT_TYPE.VIDEO,
610
+ value: { total_KBytes_in: packetsData.KBytesReceived },
611
+ },
612
+ {
613
+ ssrc,
614
+ type: models_1.STAT_TYPE.VIDEO,
615
+ value: { delta_KBytes_in: packetsData.deltaKBytesReceived },
616
+ },
617
+ {
618
+ ssrc,
619
+ type: models_1.STAT_TYPE.VIDEO,
620
+ value: { delta_kbs_in: packetsData.kbsReceived },
621
+ },
622
+ {
623
+ ssrc,
624
+ type: models_1.STAT_TYPE.VIDEO,
625
+ value: { delta_jitter_ms_in: jitter },
626
+ },
627
+ {
628
+ ssrc,
629
+ type: models_1.STAT_TYPE.VIDEO,
630
+ value: { decoder_in: decoderImplementation },
631
+ },
632
+ {
633
+ ssrc,
634
+ type: models_1.STAT_TYPE.VIDEO,
635
+ value: { delta_ms_decode_frame_in: data.delta_ms_decode_frame },
636
+ },
637
+ {
638
+ ssrc,
639
+ type: models_1.STAT_TYPE.VIDEO,
640
+ value: { total_frames_decoded_in: data.frames_decoded },
641
+ },
642
+ {
643
+ ssrc,
644
+ type: models_1.STAT_TYPE.VIDEO,
645
+ value: { total_time_decoded_in: data.total_decode_time },
646
+ },
647
+ {
648
+ ssrc,
649
+ type: models_1.STAT_TYPE.VIDEO,
650
+ value: { total_nack_sent_in: nackPliData.nackCount },
651
+ },
652
+ {
653
+ ssrc,
654
+ type: models_1.STAT_TYPE.VIDEO,
655
+ value: { delta_nack_sent_in: nackPliData.deltaNackCount },
656
+ },
657
+ {
658
+ ssrc,
659
+ type: models_1.STAT_TYPE.VIDEO,
660
+ value: { total_pli_sent_in: nackPliData.pliCount },
661
+ },
662
+ {
663
+ ssrc,
664
+ type: models_1.STAT_TYPE.VIDEO,
665
+ value: { delta_pli_sent_in: nackPliData.deltaPliCount },
666
+ },
667
+ {
668
+ ssrc,
669
+ type: models_1.STAT_TYPE.VIDEO,
670
+ value: { size_in: inputVideo },
671
+ },
672
+ ];
673
+ }
674
+ break;
675
+ }
676
+ case models_1.TYPE.OUTBOUND_RTP: {
677
+ (0, log_1.debug)(moduleName, `analyze() - got stats ${bunch[models_1.PROPERTY.TYPE]} for ${pname}`, bunch);
678
+ // get SSRC and associated data
679
+ const ssrc = bunch[models_1.PROPERTY.SSRC];
680
+ const previousSSRCBunch = (0, helper_1.getSSRCDataFromBunch)(ssrc, previousBunch, models_1.DIRECTION.OUTBOUND);
681
+ if (previousSSRCBunch) {
682
+ previousSSRCBunch.timestamp = previousBunch.timestamp;
683
+ }
684
+ const referenceSSRCBunch = (0, helper_1.getSSRCDataFromBunch)(ssrc, referenceReport, models_1.DIRECTION.OUTBOUND);
685
+ if (referenceSSRCBunch) {
686
+ referenceSSRCBunch.timestamp = referenceReport.timestamp;
687
+ }
688
+ if (bunch[models_1.PROPERTY.MEDIA_TYPE] === models_1.VALUE.AUDIO) {
689
+ const audioOutputCodecId = bunch[models_1.PROPERTY.CODEC_ID] || null;
690
+ // packets and bytes
691
+ const data = extractAudioVideoPacketSent(bunch, models_1.VALUE.AUDIO, previousSSRCBunch, referenceSSRCBunch);
692
+ return [
693
+ {
694
+ ssrc,
695
+ type: models_1.STAT_TYPE.AUDIO,
696
+ value: { codec_id_out: audioOutputCodecId },
697
+ },
698
+ {
699
+ ssrc,
700
+ type: models_1.STAT_TYPE.AUDIO,
701
+ value: { total_packets_out: data.packetsSent },
702
+ },
703
+ {
704
+ ssrc,
705
+ type: models_1.STAT_TYPE.AUDIO,
706
+ value: { delta_packets_out: data.deltaPacketsSent },
707
+ },
708
+ {
709
+ ssrc,
710
+ type: models_1.STAT_TYPE.AUDIO,
711
+ value: { total_KBytes_out: data.KBytesSent },
712
+ },
713
+ {
714
+ ssrc,
715
+ type: models_1.STAT_TYPE.AUDIO,
716
+ value: { delta_KBytes_out: data.deltaKBytesSent },
717
+ },
718
+ {
719
+ ssrc,
720
+ type: models_1.STAT_TYPE.AUDIO,
721
+ value: { delta_kbs_out: data.kbsSent },
722
+ },
723
+ ];
724
+ }
725
+ if (bunch[models_1.PROPERTY.MEDIA_TYPE] === models_1.VALUE.VIDEO) {
726
+ const encoderImplementation = bunch[models_1.PROPERTY.ENCODER_IMPLEMENTATION] || null;
727
+ const videoOutputCodecId = bunch[models_1.PROPERTY.CODEC_ID] || null;
728
+ // Encode time
729
+ const data = extractEncodeTime(bunch, previousSSRCBunch);
730
+ // Video size
731
+ const outputVideo = extractVideoSize(bunch);
732
+ // limitations
733
+ const limitationOut = extractQualityLimitation(bunch);
734
+ // Nack & Pli stats
735
+ const nackPliData = extractNackAndPliCountReceivedWhenSending(bunch, previousSSRCBunch, referenceSSRCBunch);
736
+ // packets and bytes
737
+ const dataSent = extractAudioVideoPacketSent(bunch, models_1.VALUE.VIDEO, previousSSRCBunch, referenceSSRCBunch);
738
+ return [
739
+ {
740
+ ssrc,
741
+ type: models_1.STAT_TYPE.VIDEO,
742
+ value: { codec_id_out: videoOutputCodecId },
743
+ },
744
+ {
745
+ ssrc,
746
+ type: models_1.STAT_TYPE.VIDEO,
747
+ value: { total_packets_out: dataSent.packetsSent },
748
+ },
749
+ {
750
+ ssrc,
751
+ type: models_1.STAT_TYPE.VIDEO,
752
+ value: { delta_packets_out: dataSent.deltaPacketsSent },
753
+ },
754
+ {
755
+ ssrc,
756
+ type: models_1.STAT_TYPE.VIDEO,
757
+ value: { total_KBytes_out: dataSent.KBytesSent },
758
+ },
759
+ {
760
+ ssrc,
761
+ type: models_1.STAT_TYPE.VIDEO,
762
+ value: { delta_KBytes_out: dataSent.deltaKBytesSent },
763
+ },
764
+ {
765
+ ssrc,
766
+ type: models_1.STAT_TYPE.VIDEO,
767
+ value: { delta_kbs_out: dataSent.kbsSent },
768
+ },
769
+ {
770
+ ssrc,
771
+ type: models_1.STAT_TYPE.VIDEO,
772
+ value: { encoder_out: encoderImplementation },
773
+ },
774
+ {
775
+ ssrc,
776
+ type: models_1.STAT_TYPE.VIDEO,
777
+ value: { delta_ms_encode_frame_out: data.delta_ms_encode_frame },
778
+ },
779
+ {
780
+ ssrc,
781
+ type: models_1.STAT_TYPE.VIDEO,
782
+ value: { total_frames_encoded_out: data.frames_encoded },
783
+ },
784
+ {
785
+ ssrc,
786
+ type: models_1.STAT_TYPE.VIDEO,
787
+ value: { total_time_encoded_out: data.total_encode_time },
788
+ },
789
+ {
790
+ ssrc,
791
+ type: models_1.STAT_TYPE.VIDEO,
792
+ value: { total_nack_received_out: nackPliData.nackCount },
793
+ },
794
+ {
795
+ ssrc,
796
+ type: models_1.STAT_TYPE.VIDEO,
797
+ value: { delta_nack_received_out: nackPliData.deltaNackCount },
798
+ },
799
+ {
800
+ ssrc,
801
+ type: models_1.STAT_TYPE.VIDEO,
802
+ value: { total_pli_received_out: nackPliData.pliCount },
803
+ },
804
+ {
805
+ ssrc,
806
+ type: models_1.STAT_TYPE.VIDEO,
807
+ value: { delta_pli_received_out: nackPliData.deltaPliCount },
808
+ },
809
+ {
810
+ ssrc,
811
+ type: models_1.STAT_TYPE.VIDEO,
812
+ value: { size_out: outputVideo },
813
+ },
814
+ {
815
+ ssrc,
816
+ type: models_1.STAT_TYPE.VIDEO,
817
+ value: { limitation_out: limitationOut },
818
+ },
819
+ ];
820
+ }
821
+ break;
822
+ }
823
+ case models_1.TYPE.MEDIA_SOURCE: {
824
+ (0, log_1.debug)(moduleName, `analyze() - got stats ${bunch[models_1.PROPERTY.TYPE]} for ${pname}`, bunch);
825
+ break;
826
+ }
827
+ case models_1.TYPE.TRACK: {
828
+ (0, log_1.debug)(moduleName, `analyze() - got stats ${bunch[models_1.PROPERTY.TYPE]} for ${pname}`, bunch);
829
+ break;
830
+ }
831
+ case models_1.TYPE.CODEC:
832
+ const result = [];
833
+ // Check for Audio codec
834
+ Object.keys(previousBunch[models_1.VALUE.AUDIO]).forEach((ssrc) => {
835
+ const ssrcAudioBunch = previousBunch[models_1.VALUE.AUDIO][ssrc];
836
+ if ((ssrcAudioBunch.codec_id_in === bunch[models_1.PROPERTY.ID]) || (ssrcAudioBunch.codec_id_out === bunch[models_1.PROPERTY.ID])) {
837
+ (0, log_1.debug)(moduleName, `analyze() - got stats ${bunch[models_1.PROPERTY.TYPE]} for ${pname}`, bunch);
838
+ const codec = extractAudioCodec(bunch);
839
+ if (bunch[models_1.PROPERTY.ID] === ssrcAudioBunch.codec_id_in) {
840
+ result.push({ ssrc: ssrcAudioBunch.ssrc, type: models_1.STAT_TYPE.AUDIO, value: { codec_in: codec } });
841
+ }
842
+ else {
843
+ result.push({ ssrc: ssrcAudioBunch.ssrc, type: models_1.STAT_TYPE.AUDIO, value: { codec_out: codec } });
844
+ }
845
+ }
846
+ });
847
+ // Check for Video codec
848
+ Object.keys(previousBunch[models_1.VALUE.VIDEO]).forEach((ssrc) => {
849
+ const ssrcVideoBunch = previousBunch[models_1.VALUE.VIDEO][ssrc];
850
+ if ((ssrcVideoBunch.codec_id_in === bunch[models_1.PROPERTY.ID]) || (ssrcVideoBunch.codec_id_out === bunch[models_1.PROPERTY.ID])) {
851
+ (0, log_1.debug)(moduleName, `analyze() - got stats ${bunch[models_1.PROPERTY.TYPE]} for ${pname}`, bunch);
852
+ const codec = extractVideoCodec(bunch);
853
+ if (bunch[models_1.PROPERTY.ID] === ssrcVideoBunch.codec_id_in) {
854
+ result.push({ ssrc: ssrcVideoBunch.ssrc, type: models_1.STAT_TYPE.VIDEO, value: { codec_in: codec } });
855
+ }
856
+ else {
857
+ result.push({ ssrc: ssrcVideoBunch.ssrc, type: models_1.STAT_TYPE.VIDEO, value: { codec_out: codec } });
858
+ }
859
+ }
860
+ });
861
+ return result;
862
+ case models_1.TYPE.REMOTE_INBOUND_RTP: {
863
+ (0, log_1.debug)(moduleName, `analyze() - got stats ${bunch[models_1.PROPERTY.TYPE]} for ${pname}`, bunch);
864
+ // get SSRC and associated data
865
+ const ssrc = bunch[models_1.PROPERTY.SSRC];
866
+ const previousSSRCBunch = (0, helper_1.getSSRCDataFromBunch)(ssrc, previousBunch, models_1.DIRECTION.OUTBOUND);
867
+ const referenceSSRCBunch = (0, helper_1.getSSRCDataFromBunch)(ssrc, referenceReport, models_1.DIRECTION.OUTBOUND);
868
+ if (bunch[models_1.PROPERTY.KIND] === models_1.VALUE.AUDIO) {
869
+ // Round Trip Time based on RTCP
870
+ const data = extractRTTBasedOnRTCP(bunch, models_1.VALUE.AUDIO, referenceSSRCBunch, previousSSRCBunch);
871
+ // Jitter (out)
872
+ const jitter = extractLastJitter(bunch, models_1.VALUE.AUDIO, previousSSRCBunch);
873
+ // Packets lost
874
+ const packets = extractAudioVideoPacketLost(bunch, models_1.VALUE.AUDIO, previousSSRCBunch, referenceSSRCBunch);
875
+ return [
876
+ {
877
+ ssrc,
878
+ type: models_1.STAT_TYPE.AUDIO,
879
+ value: { delta_rtt_ms_out: data.rtt },
880
+ },
881
+ {
882
+ ssrc,
883
+ type: models_1.STAT_TYPE.AUDIO,
884
+ value: { total_rtt_ms_out: data.totalRTT },
885
+ },
886
+ {
887
+ ssrc,
888
+ type: models_1.STAT_TYPE.AUDIO,
889
+ value: { total_rtt_measure_out: data.totalRTTMeasurements },
890
+ },
891
+ {
892
+ ssrc,
893
+ type: models_1.STAT_TYPE.AUDIO,
894
+ value: { delta_jitter_ms_out: jitter },
895
+ },
896
+ {
897
+ ssrc,
898
+ type: models_1.STAT_TYPE.AUDIO,
899
+ value: { timestamp_out: bunch[models_1.PROPERTY.TIMESTAMP] },
900
+ },
901
+ {
902
+ ssrc,
903
+ type: models_1.STAT_TYPE.AUDIO,
904
+ value: { total_packets_lost_out: packets.packetsLost },
905
+ },
906
+ {
907
+ ssrc,
908
+ type: models_1.STAT_TYPE.AUDIO,
909
+ value: { delta_packets_lost_out: packets.deltaPacketsLost },
910
+ },
911
+ {
912
+ ssrc,
913
+ type: models_1.STAT_TYPE.AUDIO,
914
+ value: { percent_packets_lost_out: packets.fractionLost },
915
+ },
916
+ ];
917
+ }
918
+ if (bunch[models_1.PROPERTY.KIND] === models_1.VALUE.VIDEO) {
919
+ // Round Trip Time based on RTCP
920
+ const data = extractRTTBasedOnRTCP(bunch, models_1.VALUE.VIDEO, referenceSSRCBunch, previousSSRCBunch);
921
+ // Jitter (out)
922
+ const jitter = extractLastJitter(bunch, models_1.VALUE.VIDEO, previousSSRCBunch);
923
+ // Packets lost
924
+ const packets = extractAudioVideoPacketLost(bunch, models_1.VALUE.VIDEO, previousSSRCBunch, referenceSSRCBunch);
925
+ return [
926
+ {
927
+ ssrc,
928
+ type: models_1.STAT_TYPE.VIDEO,
929
+ value: { delta_rtt_ms_out: data.rtt },
930
+ },
931
+ {
932
+ ssrc,
933
+ type: models_1.STAT_TYPE.VIDEO,
934
+ value: { total_rtt_ms_out: data.totalRTT },
935
+ },
936
+ {
937
+ ssrc,
938
+ type: models_1.STAT_TYPE.VIDEO,
939
+ value: { total_rtt_measure_out: data.totalRTTMeasurements },
940
+ },
941
+ {
942
+ ssrc,
943
+ type: models_1.STAT_TYPE.VIDEO,
944
+ value: { delta_jitter_ms_out: jitter },
945
+ },
946
+ {
947
+ ssrc,
948
+ type: models_1.STAT_TYPE.VIDEO,
949
+ value: { timestamp_out: bunch[models_1.PROPERTY.TIMESTAMP] },
950
+ },
951
+ {
952
+ ssrc,
953
+ type: models_1.STAT_TYPE.VIDEO,
954
+ value: { total_packets_lost_out: packets.packetsLost },
955
+ },
956
+ {
957
+ ssrc,
958
+ type: models_1.STAT_TYPE.VIDEO,
959
+ value: { delta_packets_lost_out: packets.deltaPacketsLost },
960
+ },
961
+ {
962
+ ssrc,
963
+ type: models_1.STAT_TYPE.VIDEO,
964
+ value: { percent_packets_lost_out: packets.fractionLost },
965
+ },
966
+ ];
967
+ }
968
+ break;
969
+ }
970
+ default:
971
+ break;
972
+ }
973
+ // No interesting data
974
+ return [];
975
+ };
976
+ exports.extract = extract;