@webex/plugin-meetings 3.3.1-next.1 → 3.3.1-next.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/mediaQualityMetrics/config.js +10 -6
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/index.js +9 -5
- package/dist/meeting/index.js.map +1 -1
- package/dist/statsAnalyzer/index.js +74 -26
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +34 -8
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/types/mediaQualityMetrics/config.d.ts +6 -0
- package/dist/types/statsAnalyzer/index.d.ts +14 -6
- package/dist/types/statsAnalyzer/mqaUtil.d.ts +17 -4
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/mediaQualityMetrics/config.ts +9 -3
- package/src/meeting/index.ts +6 -5
- package/src/statsAnalyzer/index.ts +78 -21
- package/src/statsAnalyzer/mqaUtil.ts +53 -5
- package/test/unit/spec/stats-analyzer/index.js +586 -312
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
getAudioReceiverStreamMqa,
|
|
36
36
|
getVideoSenderStreamMqa,
|
|
37
37
|
getVideoReceiverStreamMqa,
|
|
38
|
+
isStreamRequested,
|
|
38
39
|
} from './mqaUtil';
|
|
39
40
|
import {ReceiveSlot} from '../multistream/receiveSlot';
|
|
40
41
|
|
|
@@ -91,22 +92,31 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
91
92
|
successfulCandidatePair: any;
|
|
92
93
|
localIpAddress: string; // Returns the local IP address for diagnostics. this is the local IP of the interface used for the current media connection a host can have many local Ip Addresses
|
|
93
94
|
receiveSlotCallback: ReceiveSlotCallback;
|
|
95
|
+
isMultistream: boolean;
|
|
94
96
|
|
|
95
97
|
/**
|
|
96
98
|
* Creates a new instance of StatsAnalyzer
|
|
97
99
|
* @constructor
|
|
98
100
|
* @public
|
|
99
|
-
* @param {Object} config SDK Configuration Object
|
|
100
|
-
* @param {Function} receiveSlotCallback Callback used to access receive slots.
|
|
101
|
-
* @param {Object} networkQualityMonitor
|
|
102
|
-
* @param {Object} statsResults Default properties for stats
|
|
101
|
+
* @param {Object} config - SDK Configuration Object
|
|
102
|
+
* @param {Function} receiveSlotCallback - Callback used to access receive slots.
|
|
103
|
+
* @param {Object} networkQualityMonitor - Class for assessing network characteristics (jitter, packetLoss, latency)
|
|
104
|
+
* @param {Object} statsResults - Default properties for stats
|
|
105
|
+
* @param {boolean | undefined} isMultistream - Param indicating if the media connection is multistream or not
|
|
103
106
|
*/
|
|
104
|
-
constructor(
|
|
105
|
-
config
|
|
106
|
-
receiveSlotCallback
|
|
107
|
-
networkQualityMonitor
|
|
108
|
-
statsResults
|
|
109
|
-
|
|
107
|
+
constructor({
|
|
108
|
+
config,
|
|
109
|
+
receiveSlotCallback = () => undefined,
|
|
110
|
+
networkQualityMonitor = {},
|
|
111
|
+
statsResults = defaultStats,
|
|
112
|
+
isMultistream = false,
|
|
113
|
+
}: {
|
|
114
|
+
config: any;
|
|
115
|
+
receiveSlotCallback: ReceiveSlotCallback;
|
|
116
|
+
networkQualityMonitor: any;
|
|
117
|
+
statsResults?: any;
|
|
118
|
+
isMultistream?: boolean;
|
|
119
|
+
}) {
|
|
110
120
|
super();
|
|
111
121
|
this.statsStarted = false;
|
|
112
122
|
this.statsResults = statsResults;
|
|
@@ -120,6 +130,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
120
130
|
this.receiveSlotCallback = receiveSlotCallback;
|
|
121
131
|
this.successfulCandidatePair = {};
|
|
122
132
|
this.localIpAddress = '';
|
|
133
|
+
this.isMultistream = isMultistream;
|
|
123
134
|
}
|
|
124
135
|
|
|
125
136
|
/**
|
|
@@ -203,6 +214,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
203
214
|
statsResults: this.statsResults,
|
|
204
215
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
205
216
|
baseMediaType: 'audio-send',
|
|
217
|
+
isMultistream: this.isMultistream,
|
|
206
218
|
});
|
|
207
219
|
newMqa.audioTransmit.push(audioSender);
|
|
208
220
|
|
|
@@ -211,6 +223,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
211
223
|
statsResults: this.statsResults,
|
|
212
224
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
213
225
|
baseMediaType: 'audio-share-send',
|
|
226
|
+
isMultistream: this.isMultistream,
|
|
214
227
|
});
|
|
215
228
|
newMqa.audioTransmit.push(audioShareSender);
|
|
216
229
|
|
|
@@ -219,6 +232,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
219
232
|
statsResults: this.statsResults,
|
|
220
233
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
221
234
|
baseMediaType: 'audio-recv',
|
|
235
|
+
isMultistream: this.isMultistream,
|
|
222
236
|
});
|
|
223
237
|
newMqa.audioReceive.push(audioReceiver);
|
|
224
238
|
|
|
@@ -227,6 +241,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
227
241
|
statsResults: this.statsResults,
|
|
228
242
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
229
243
|
baseMediaType: 'audio-share-recv',
|
|
244
|
+
isMultistream: this.isMultistream,
|
|
230
245
|
});
|
|
231
246
|
newMqa.audioReceive.push(audioShareReceiver);
|
|
232
247
|
|
|
@@ -235,6 +250,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
235
250
|
statsResults: this.statsResults,
|
|
236
251
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
237
252
|
baseMediaType: 'video-send',
|
|
253
|
+
isMultistream: this.isMultistream,
|
|
238
254
|
});
|
|
239
255
|
newMqa.videoTransmit.push(videoSender);
|
|
240
256
|
|
|
@@ -243,6 +259,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
243
259
|
statsResults: this.statsResults,
|
|
244
260
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
245
261
|
baseMediaType: 'video-share-send',
|
|
262
|
+
isMultistream: this.isMultistream,
|
|
246
263
|
});
|
|
247
264
|
newMqa.videoTransmit.push(videoShareSender);
|
|
248
265
|
|
|
@@ -251,6 +268,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
251
268
|
statsResults: this.statsResults,
|
|
252
269
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
253
270
|
baseMediaType: 'video-recv',
|
|
271
|
+
isMultistream: this.isMultistream,
|
|
254
272
|
});
|
|
255
273
|
newMqa.videoReceive.push(videoReceiver);
|
|
256
274
|
|
|
@@ -259,6 +277,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
259
277
|
statsResults: this.statsResults,
|
|
260
278
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
261
279
|
baseMediaType: 'video-share-recv',
|
|
280
|
+
isMultistream: this.isMultistream,
|
|
262
281
|
});
|
|
263
282
|
newMqa.videoReceive.push(videoShareReceiver);
|
|
264
283
|
|
|
@@ -273,7 +292,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
273
292
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
274
293
|
mediaType,
|
|
275
294
|
});
|
|
276
|
-
|
|
295
|
+
if (isStreamRequested(this.statsResults, mediaType, STATS.SEND_DIRECTION)) {
|
|
296
|
+
newMqa.audioTransmit[0].streams.push(audioSenderStream);
|
|
297
|
+
}
|
|
277
298
|
|
|
278
299
|
this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
|
|
279
300
|
} else if (mediaType.startsWith('audio-share-send')) {
|
|
@@ -285,7 +306,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
285
306
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
286
307
|
mediaType,
|
|
287
308
|
});
|
|
288
|
-
|
|
309
|
+
if (isStreamRequested(this.statsResults, mediaType, STATS.SEND_DIRECTION)) {
|
|
310
|
+
newMqa.audioTransmit[1].streams.push(audioSenderStream);
|
|
311
|
+
}
|
|
289
312
|
|
|
290
313
|
this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
|
|
291
314
|
} else if (mediaType.startsWith('audio-recv')) {
|
|
@@ -297,7 +320,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
297
320
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
298
321
|
mediaType,
|
|
299
322
|
});
|
|
300
|
-
|
|
323
|
+
if (isStreamRequested(this.statsResults, mediaType, STATS.RECEIVE_DIRECTION)) {
|
|
324
|
+
newMqa.audioReceive[0].streams.push(audioReceiverStream);
|
|
325
|
+
}
|
|
301
326
|
|
|
302
327
|
this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
|
|
303
328
|
} else if (mediaType.startsWith('audio-share-recv')) {
|
|
@@ -309,8 +334,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
309
334
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
310
335
|
mediaType,
|
|
311
336
|
});
|
|
312
|
-
|
|
313
|
-
|
|
337
|
+
if (isStreamRequested(this.statsResults, mediaType, STATS.RECEIVE_DIRECTION)) {
|
|
338
|
+
newMqa.audioReceive[1].streams.push(audioReceiverStream);
|
|
339
|
+
}
|
|
314
340
|
this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
|
|
315
341
|
} else if (mediaType.startsWith('video-send-layer')) {
|
|
316
342
|
// We only want the stream-specific stats we get with video-send-layer-0, video-send-layer-1, etc.
|
|
@@ -322,8 +348,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
322
348
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
323
349
|
mediaType,
|
|
324
350
|
});
|
|
325
|
-
|
|
326
|
-
|
|
351
|
+
if (isStreamRequested(this.statsResults, mediaType, STATS.SEND_DIRECTION)) {
|
|
352
|
+
newMqa.videoTransmit[0].streams.push(videoSenderStream);
|
|
353
|
+
}
|
|
327
354
|
this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
|
|
328
355
|
} else if (mediaType.startsWith('video-share-send')) {
|
|
329
356
|
const videoSenderStream = cloneDeep(emptyVideoTransmitStream);
|
|
@@ -334,7 +361,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
334
361
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
335
362
|
mediaType,
|
|
336
363
|
});
|
|
337
|
-
|
|
364
|
+
if (isStreamRequested(this.statsResults, mediaType, STATS.SEND_DIRECTION)) {
|
|
365
|
+
newMqa.videoTransmit[1].streams.push(videoSenderStream);
|
|
366
|
+
}
|
|
338
367
|
|
|
339
368
|
this.lastMqaDataSent[mediaType].send = cloneDeep(this.statsResults[mediaType].send);
|
|
340
369
|
} else if (mediaType.startsWith('video-recv')) {
|
|
@@ -346,7 +375,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
346
375
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
347
376
|
mediaType,
|
|
348
377
|
});
|
|
349
|
-
|
|
378
|
+
if (isStreamRequested(this.statsResults, mediaType, STATS.RECEIVE_DIRECTION)) {
|
|
379
|
+
newMqa.videoReceive[0].streams.push(videoReceiverStream);
|
|
380
|
+
}
|
|
350
381
|
|
|
351
382
|
this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
|
|
352
383
|
} else if (mediaType.startsWith('video-share-recv')) {
|
|
@@ -358,8 +389,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
358
389
|
lastMqaDataSent: this.lastMqaDataSent,
|
|
359
390
|
mediaType,
|
|
360
391
|
});
|
|
361
|
-
|
|
362
|
-
|
|
392
|
+
if (isStreamRequested(this.statsResults, mediaType, STATS.RECEIVE_DIRECTION)) {
|
|
393
|
+
newMqa.videoReceive[1].streams.push(videoReceiverStream);
|
|
394
|
+
}
|
|
363
395
|
this.lastMqaDataSent[mediaType].recv = cloneDeep(this.statsResults[mediaType].recv);
|
|
364
396
|
}
|
|
365
397
|
});
|
|
@@ -388,6 +420,17 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
388
420
|
|
|
389
421
|
newMqa.networkType = this.statsResults.connectionType.local.networkType;
|
|
390
422
|
|
|
423
|
+
newMqa.intervalMetadata.screenWidth = window.screen.width;
|
|
424
|
+
newMqa.intervalMetadata.screenHeight = window.screen.height;
|
|
425
|
+
newMqa.intervalMetadata.screenResolution = Math.round(
|
|
426
|
+
(window.screen.width * window.screen.height) / 256
|
|
427
|
+
);
|
|
428
|
+
newMqa.intervalMetadata.appWindowWidth = window.innerWidth;
|
|
429
|
+
newMqa.intervalMetadata.appWindowHeight = window.innerHeight;
|
|
430
|
+
newMqa.intervalMetadata.appWindowSize = Math.round(
|
|
431
|
+
(window.innerWidth * window.innerHeight) / 256
|
|
432
|
+
);
|
|
433
|
+
|
|
391
434
|
this.mqaSentCount += 1;
|
|
392
435
|
|
|
393
436
|
newMqa.intervalNumber = this.mqaSentCount;
|
|
@@ -1003,6 +1046,11 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1003
1046
|
this.statsResults[mediaType][sendrecvType].totalRtxBytesSent = result.retransmittedBytesSent;
|
|
1004
1047
|
this.statsResults[mediaType][sendrecvType].totalBytesSent = result.bytesSent;
|
|
1005
1048
|
this.statsResults[mediaType][sendrecvType].headerBytesSent = result.headerBytesSent;
|
|
1049
|
+
this.statsResults[mediaType][sendrecvType].retransmittedBytesSent =
|
|
1050
|
+
result.retransmittedBytesSent;
|
|
1051
|
+
this.statsResults[mediaType][sendrecvType].isRequested = result.isRequested;
|
|
1052
|
+
this.statsResults[mediaType][sendrecvType].lastRequestedUpdateTimestamp =
|
|
1053
|
+
result.lastRequestedUpdateTimestamp;
|
|
1006
1054
|
this.statsResults[mediaType][sendrecvType].requestedBitrate = result.requestedBitrate;
|
|
1007
1055
|
this.statsResults[mediaType][sendrecvType].requestedFrameSize = result.requestedFrameSize;
|
|
1008
1056
|
}
|
|
@@ -1088,6 +1136,12 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1088
1136
|
}
|
|
1089
1137
|
}
|
|
1090
1138
|
|
|
1139
|
+
if (mediaType.startsWith('video-recv')) {
|
|
1140
|
+
this.statsResults[mediaType][sendrecvType].isActiveSpeaker = result.isActiveSpeaker;
|
|
1141
|
+
this.statsResults[mediaType][sendrecvType].lastActiveSpeakerTimestamp =
|
|
1142
|
+
result.lastActiveSpeakerUpdateTimestamp;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1091
1145
|
// Check the over all packet Lost ratio
|
|
1092
1146
|
this.statsResults[mediaType][sendrecvType].currentPacketLossRatio =
|
|
1093
1147
|
currentPacketsLost > 0
|
|
@@ -1151,6 +1205,9 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
1151
1205
|
this.statsResults[mediaType][sendrecvType].totalSamplesDecoded =
|
|
1152
1206
|
result.totalSamplesDecoded || 0;
|
|
1153
1207
|
this.statsResults[mediaType][sendrecvType].concealedSamples = result.concealedSamples || 0;
|
|
1208
|
+
this.statsResults[mediaType][sendrecvType].isRequested = result.isRequested;
|
|
1209
|
+
this.statsResults[mediaType][sendrecvType].lastRequestedUpdateTimestamp =
|
|
1210
|
+
result.lastRequestedUpdateTimestamp;
|
|
1154
1211
|
}
|
|
1155
1212
|
}
|
|
1156
1213
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {mean, max} from 'lodash';
|
|
4
4
|
|
|
5
|
-
import {STATS} from '../constants';
|
|
5
|
+
import {MQA_INTERVAL, STATS} from '../constants';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Get the totals of a certain value from a certain media type.
|
|
@@ -28,6 +28,7 @@ export const getAudioReceiverMqa = ({
|
|
|
28
28
|
statsResults,
|
|
29
29
|
lastMqaDataSent,
|
|
30
30
|
baseMediaType,
|
|
31
|
+
isMultistream,
|
|
31
32
|
}) => {
|
|
32
33
|
const sendrecvType = STATS.RECEIVE_DIRECTION;
|
|
33
34
|
|
|
@@ -52,6 +53,7 @@ export const getAudioReceiverMqa = ({
|
|
|
52
53
|
statsResults[Object.keys(statsResults).find((mediaType) => mediaType.includes(baseMediaType))]
|
|
53
54
|
?.direction || 'inactive';
|
|
54
55
|
audioReceiver.common.common.isMain = !baseMediaType.includes('-share');
|
|
56
|
+
audioReceiver.common.common.multistreamEnabled = isMultistream;
|
|
55
57
|
audioReceiver.common.transportType = statsResults.connectionType.local.transport;
|
|
56
58
|
|
|
57
59
|
// add rtpPacket info inside common as also for call analyzer
|
|
@@ -67,7 +69,9 @@ export const getAudioReceiverMqa = ({
|
|
|
67
69
|
totalFecPacketsReceived -
|
|
68
70
|
lastFecPacketsReceived -
|
|
69
71
|
(totalFecPacketsDiscarded - lastFecPacketsDiscarded);
|
|
70
|
-
audioReceiver.common.fecPackets =
|
|
72
|
+
audioReceiver.common.fecPackets = totalFecPacketsReceived - lastFecPacketsReceived;
|
|
73
|
+
|
|
74
|
+
audioReceiver.common.rtpRecovered = fecRecovered;
|
|
71
75
|
|
|
72
76
|
audioReceiver.common.rtpBitrate = ((totalBytesReceived - lastBytesReceived) * 8) / 60 || 0;
|
|
73
77
|
};
|
|
@@ -127,7 +131,13 @@ export const getAudioReceiverStreamMqa = ({
|
|
|
127
131
|
((statsResults[mediaType][sendrecvType].totalBytesReceived - lastBytesReceived) * 8) / 60 || 0;
|
|
128
132
|
};
|
|
129
133
|
|
|
130
|
-
export const getAudioSenderMqa = ({
|
|
134
|
+
export const getAudioSenderMqa = ({
|
|
135
|
+
audioSender,
|
|
136
|
+
statsResults,
|
|
137
|
+
lastMqaDataSent,
|
|
138
|
+
baseMediaType,
|
|
139
|
+
isMultistream,
|
|
140
|
+
}) => {
|
|
131
141
|
const sendrecvType = STATS.SEND_DIRECTION;
|
|
132
142
|
|
|
133
143
|
const getLastTotalValue = (value: string) =>
|
|
@@ -152,6 +162,7 @@ export const getAudioSenderMqa = ({audioSender, statsResults, lastMqaDataSent, b
|
|
|
152
162
|
statsResults[Object.keys(statsResults).find((mediaType) => mediaType.includes(baseMediaType))]
|
|
153
163
|
?.direction || 'inactive';
|
|
154
164
|
audioSender.common.common.isMain = !baseMediaType.includes('-share');
|
|
165
|
+
audioSender.common.common.multistreamEnabled = isMultistream;
|
|
155
166
|
audioSender.common.transportType = statsResults.connectionType.local.transport;
|
|
156
167
|
|
|
157
168
|
audioSender.common.maxRemoteJitter = max(meanRemoteJitter) * 1000 || 0;
|
|
@@ -166,8 +177,8 @@ export const getAudioSenderMqa = ({audioSender, statsResults, lastMqaDataSent, b
|
|
|
166
177
|
baseMediaType,
|
|
167
178
|
'availableOutgoingBitrate'
|
|
168
179
|
);
|
|
169
|
-
// Calculate based on how much packets lost of received compated to how to the client sent
|
|
170
180
|
|
|
181
|
+
// Calculate based on how much packets lost of received compated to how to the client sent
|
|
171
182
|
const totalPacketsLostForaMin = totalPacketsLostOnReceiver - lastPacketsLostTotal;
|
|
172
183
|
audioSender.common.remoteLossRate =
|
|
173
184
|
totalPacketsSent - lastPacketsSent > 0
|
|
@@ -225,6 +236,7 @@ export const getVideoReceiverMqa = ({
|
|
|
225
236
|
statsResults,
|
|
226
237
|
lastMqaDataSent,
|
|
227
238
|
baseMediaType,
|
|
239
|
+
isMultistream,
|
|
228
240
|
}) => {
|
|
229
241
|
const sendrecvType = STATS.RECEIVE_DIRECTION;
|
|
230
242
|
|
|
@@ -254,6 +266,7 @@ export const getVideoReceiverMqa = ({
|
|
|
254
266
|
videoReceiver.common.common.direction =
|
|
255
267
|
statsResults[Object.keys(statsResults).find((mediaType) => mediaType.includes(baseMediaType))]
|
|
256
268
|
?.direction || 'inactive';
|
|
269
|
+
videoReceiver.common.common.multistreamEnabled = isMultistream;
|
|
257
270
|
videoReceiver.common.common.isMain = !baseMediaType.includes('-share');
|
|
258
271
|
videoReceiver.common.transportType = statsResults.connectionType.local.transport;
|
|
259
272
|
|
|
@@ -347,9 +360,23 @@ export const getVideoReceiverStreamMqa = ({
|
|
|
347
360
|
statsResults[mediaType][sendrecvType].keyFramesDecoded - lastKeyFramesDecoded || 0;
|
|
348
361
|
videoReceiverStream.requestedKeyFrames =
|
|
349
362
|
statsResults[mediaType][sendrecvType].totalPliCount - lastPliCount || 0;
|
|
363
|
+
|
|
364
|
+
videoReceiverStream.isActiveSpeaker =
|
|
365
|
+
statsResults[mediaType][sendrecvType].isActiveSpeaker ||
|
|
366
|
+
((statsResults[mediaType][sendrecvType].lastActiveSpeakerTimestamp ?? 0) > 0 &&
|
|
367
|
+
performance.now() +
|
|
368
|
+
performance.timeOrigin -
|
|
369
|
+
(statsResults[mediaType][sendrecvType].lastActiveSpeakerTimestamp ?? 0) <
|
|
370
|
+
MQA_INTERVAL);
|
|
350
371
|
};
|
|
351
372
|
|
|
352
|
-
export const getVideoSenderMqa = ({
|
|
373
|
+
export const getVideoSenderMqa = ({
|
|
374
|
+
videoSender,
|
|
375
|
+
statsResults,
|
|
376
|
+
lastMqaDataSent,
|
|
377
|
+
baseMediaType,
|
|
378
|
+
isMultistream,
|
|
379
|
+
}) => {
|
|
353
380
|
const sendrecvType = STATS.SEND_DIRECTION;
|
|
354
381
|
|
|
355
382
|
const getLastTotalValue = (value: string) =>
|
|
@@ -373,6 +400,7 @@ export const getVideoSenderMqa = ({videoSender, statsResults, lastMqaDataSent, b
|
|
|
373
400
|
videoSender.common.common.direction =
|
|
374
401
|
statsResults[Object.keys(statsResults).find((mediaType) => mediaType.includes(baseMediaType))]
|
|
375
402
|
?.direction || 'inactive';
|
|
403
|
+
videoSender.common.common.multistreamEnabled = isMultistream;
|
|
376
404
|
videoSender.common.common.isMain = !baseMediaType.includes('-share');
|
|
377
405
|
videoSender.common.transportType = statsResults.connectionType.local.transport;
|
|
378
406
|
|
|
@@ -461,3 +489,23 @@ export const getVideoSenderStreamMqa = ({
|
|
|
461
489
|
videoSenderStream.requestedFrameSize =
|
|
462
490
|
statsResults[mediaType][sendrecvType].requestedFrameSize || 0;
|
|
463
491
|
};
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Checks if stream stats should be updated based on request status and elapsed time.
|
|
495
|
+
*
|
|
496
|
+
* @param {Object} statsResults - Stats results object.
|
|
497
|
+
* @param {string} mediaType - Media type (e.g., 'audio', 'video').
|
|
498
|
+
* @param {string} direction - Stats direction (e.g., 'send', 'receive').
|
|
499
|
+
* @returns {boolean} Whether stats should be updated.
|
|
500
|
+
*/
|
|
501
|
+
export const isStreamRequested = (
|
|
502
|
+
statsResults: any,
|
|
503
|
+
mediaType: string,
|
|
504
|
+
direction: string
|
|
505
|
+
): boolean => {
|
|
506
|
+
const now = performance.timeOrigin + performance.now();
|
|
507
|
+
const lastUpdateTimestamp = statsResults[mediaType][direction]?.lastRequestedUpdateTimestamp;
|
|
508
|
+
const isRequested = statsResults[mediaType][direction]?.isRequested;
|
|
509
|
+
|
|
510
|
+
return isRequested || (lastUpdateTimestamp && now - lastUpdateTimestamp < MQA_INTERVAL);
|
|
511
|
+
};
|