@voicenter-team/opensips-js 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
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;