@webex/plugin-meetings 2.60.1-next.7 → 2.60.1-next.8
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/README.md +12 -0
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.d.ts +12 -2
- package/dist/constants.js +15 -5
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.d.ts +1 -1
- package/dist/locus-info/index.js +8 -8
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/index.d.ts +62 -18
- package/dist/meeting/index.js +679 -568
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +25 -18
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.d.ts +16 -0
- package/dist/meeting/util.js +71 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.d.ts +25 -3
- package/dist/meetings/index.js +83 -32
- package/dist/meetings/index.js.map +1 -1
- package/dist/reachability/index.js +11 -6
- package/dist/reachability/index.js.map +1 -1
- package/dist/reconnection-manager/index.js +3 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.js +50 -54
- package/dist/roap/index.js.map +1 -1
- package/dist/statsAnalyzer/index.js +1 -1
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +13 -10
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/constants.ts +13 -2
- package/src/locus-info/index.ts +13 -12
- package/src/meeting/index.ts +215 -116
- package/src/meeting/request.ts +7 -0
- package/src/meeting/util.ts +97 -0
- package/src/meetings/index.ts +59 -18
- package/src/reachability/index.ts +7 -4
- package/src/reconnection-manager/index.ts +1 -1
- package/src/roap/index.ts +49 -51
- package/src/statsAnalyzer/index.ts +2 -2
- package/src/statsAnalyzer/mqaUtil.ts +15 -14
- package/test/unit/spec/locus-info/index.js +53 -5
- package/test/unit/spec/meeting/index.js +1792 -1139
- package/test/unit/spec/meeting/request.js +22 -12
- package/test/unit/spec/meeting/utils.js +93 -0
- package/test/unit/spec/meetings/index.js +180 -21
- package/test/unit/spec/reachability/index.ts +2 -1
- package/test/unit/spec/reconnection-manager/index.js +1 -0
- package/test/unit/spec/roap/index.ts +28 -42
- package/test/unit/spec/stats-analyzer/index.js +415 -30
package/src/meetings/index.ts
CHANGED
|
@@ -584,7 +584,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
584
584
|
|
|
585
585
|
// @ts-ignore
|
|
586
586
|
this.webex.internal.mercury.on(ONLINE, () => {
|
|
587
|
-
this.syncMeetings();
|
|
587
|
+
this.syncMeetings({keepOnlyLocusMeetings: false});
|
|
588
588
|
});
|
|
589
589
|
|
|
590
590
|
// @ts-ignore
|
|
@@ -699,6 +699,24 @@ export default class Meetings extends WebexPlugin {
|
|
|
699
699
|
}
|
|
700
700
|
}
|
|
701
701
|
|
|
702
|
+
/**
|
|
703
|
+
* API to toggle TCP reachability, needs to be called before webex.meetings.register()
|
|
704
|
+
* @param {Boolean} newValue
|
|
705
|
+
* @private
|
|
706
|
+
* @memberof Meetings
|
|
707
|
+
* @returns {undefined}
|
|
708
|
+
*/
|
|
709
|
+
private _toggleTcpReachability(newValue: boolean) {
|
|
710
|
+
if (typeof newValue !== 'boolean') {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
// @ts-ignore
|
|
714
|
+
if (this.config.experimental.enableTcpReachability !== newValue) {
|
|
715
|
+
// @ts-ignore
|
|
716
|
+
this.config.experimental.enableTcpReachability = newValue;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
702
720
|
/**
|
|
703
721
|
* Explicitly sets up the meetings plugin by registering
|
|
704
722
|
* the device, connecting to mercury, and listening for locus events.
|
|
@@ -1026,6 +1044,9 @@ export default class Meetings extends WebexPlugin {
|
|
|
1026
1044
|
|
|
1027
1045
|
/**
|
|
1028
1046
|
* Create a meeting or return an existing meeting.
|
|
1047
|
+
*
|
|
1048
|
+
* When meeting info passed it should be complete, e.g.: fetched after password or captcha provided
|
|
1049
|
+
*
|
|
1029
1050
|
* @param {string} destination - sipURL, phonenumber, or locus object}
|
|
1030
1051
|
* @param {string} [type] - the optional specified type, such as locusId
|
|
1031
1052
|
* @param {Boolean} useRandomDelayForInfo - whether a random delay should be added to fetching meeting info
|
|
@@ -1033,6 +1054,8 @@ export default class Meetings extends WebexPlugin {
|
|
|
1033
1054
|
* @param {string} correlationId - the optional specified correlationId (callStateForMetrics.correlationId can be provided instead)
|
|
1034
1055
|
* @param {Boolean} failOnMissingMeetingInfo - whether to throw an error if meeting info fails to fetch (for calls that are not 1:1 or content share)
|
|
1035
1056
|
* @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
|
|
1057
|
+
* @param {Object} [meetingInfo] - Pre-fetched complete meeting info
|
|
1058
|
+
* @param {String} [meetingLookupUrl] - meeting info prefetch url
|
|
1036
1059
|
* @returns {Promise<Meeting>} A new Meeting.
|
|
1037
1060
|
* @public
|
|
1038
1061
|
* @memberof Meetings
|
|
@@ -1044,7 +1067,9 @@ export default class Meetings extends WebexPlugin {
|
|
|
1044
1067
|
infoExtraParams = {},
|
|
1045
1068
|
correlationId: string = undefined,
|
|
1046
1069
|
failOnMissingMeetingInfo = false,
|
|
1047
|
-
callStateForMetrics: CallStateForMetrics = undefined
|
|
1070
|
+
callStateForMetrics: CallStateForMetrics = undefined,
|
|
1071
|
+
meetingInfo = undefined,
|
|
1072
|
+
meetingLookupUrl = undefined
|
|
1048
1073
|
) {
|
|
1049
1074
|
// TODO: type should be from a dictionary
|
|
1050
1075
|
|
|
@@ -1103,7 +1128,9 @@ export default class Meetings extends WebexPlugin {
|
|
|
1103
1128
|
useRandomDelayForInfo,
|
|
1104
1129
|
infoExtraParams,
|
|
1105
1130
|
callStateForMetrics,
|
|
1106
|
-
failOnMissingMeetingInfo
|
|
1131
|
+
failOnMissingMeetingInfo,
|
|
1132
|
+
meetingInfo,
|
|
1133
|
+
meetingLookupUrl
|
|
1107
1134
|
).then((createdMeeting: any) => {
|
|
1108
1135
|
// If the meeting was successfully created.
|
|
1109
1136
|
if (createdMeeting && createdMeeting.on) {
|
|
@@ -1158,12 +1185,18 @@ export default class Meetings extends WebexPlugin {
|
|
|
1158
1185
|
}
|
|
1159
1186
|
|
|
1160
1187
|
/**
|
|
1188
|
+
* Create meeting
|
|
1189
|
+
*
|
|
1190
|
+
* When meeting info passed it should be complete, e.g.: fetched after password or captcha provided
|
|
1191
|
+
*
|
|
1161
1192
|
* @param {String} destination see create()
|
|
1162
1193
|
* @param {String} type see create()
|
|
1163
1194
|
* @param {Boolean} useRandomDelayForInfo whether a random delay should be added to fetching meeting info
|
|
1164
1195
|
* @param {Object} infoExtraParams extra parameters to be provided when fetching meeting info
|
|
1165
1196
|
* @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
|
|
1166
1197
|
* @param {Boolean} failOnMissingMeetingInfo - whether to throw an error if meeting info fails to fetch (for calls that are not 1:1 or content share)
|
|
1198
|
+
* @param {Object} [meetingInfo] - Pre-fetched complete meeting info
|
|
1199
|
+
* @param {String} [meetingLookupUrl] - meeting info prefetch url
|
|
1167
1200
|
* @returns {Promise} a new meeting instance complete with meeting info and destination
|
|
1168
1201
|
* @private
|
|
1169
1202
|
* @memberof Meetings
|
|
@@ -1174,7 +1207,9 @@ export default class Meetings extends WebexPlugin {
|
|
|
1174
1207
|
useRandomDelayForInfo = false,
|
|
1175
1208
|
infoExtraParams = {},
|
|
1176
1209
|
callStateForMetrics: CallStateForMetrics = undefined,
|
|
1177
|
-
failOnMissingMeetingInfo = false
|
|
1210
|
+
failOnMissingMeetingInfo = false,
|
|
1211
|
+
meetingInfo = undefined,
|
|
1212
|
+
meetingLookupUrl = undefined
|
|
1178
1213
|
) {
|
|
1179
1214
|
const meeting = new Meeting(
|
|
1180
1215
|
{
|
|
@@ -1220,22 +1255,26 @@ export default class Meetings extends WebexPlugin {
|
|
|
1220
1255
|
const isMeetingActive = !!destination.fullState?.active;
|
|
1221
1256
|
// @ts-ignore
|
|
1222
1257
|
const {enableUnifiedMeetings} = this.config.experimental;
|
|
1223
|
-
|
|
1224
|
-
|
|
1258
|
+
const meetingInfoOptions = {
|
|
1259
|
+
extraParams: infoExtraParams,
|
|
1260
|
+
sendCAevents: !!callStateForMetrics?.correlationId, // if client sends correlation id as argument of public create(), then it means that this meeting creation is part of a pre-join intent from user
|
|
1261
|
+
};
|
|
1262
|
+
|
|
1263
|
+
if (meetingInfo) {
|
|
1264
|
+
meeting.injectMeetingInfo(meetingInfo, meetingInfoOptions, meetingLookupUrl);
|
|
1265
|
+
} else if (
|
|
1266
|
+
enableUnifiedMeetings &&
|
|
1267
|
+
!isMeetingActive &&
|
|
1268
|
+
useRandomDelayForInfo &&
|
|
1269
|
+
waitingTime > 0
|
|
1270
|
+
) {
|
|
1225
1271
|
meeting.fetchMeetingInfoTimeoutId = setTimeout(
|
|
1226
|
-
() =>
|
|
1227
|
-
meeting.fetchMeetingInfo({
|
|
1228
|
-
extraParams: infoExtraParams,
|
|
1229
|
-
sendCAevents: !!callStateForMetrics?.correlationId, // if client sends correlation id as argument of public create(), then it means that this meeting creation is part of a pre-join intent from user
|
|
1230
|
-
}),
|
|
1272
|
+
() => meeting.fetchMeetingInfo(meetingInfoOptions),
|
|
1231
1273
|
waitingTime
|
|
1232
1274
|
);
|
|
1233
1275
|
meeting.parseMeetingInfo(undefined, destination);
|
|
1234
1276
|
} else {
|
|
1235
|
-
await meeting.fetchMeetingInfo(
|
|
1236
|
-
extraParams: infoExtraParams,
|
|
1237
|
-
sendCAevents: !!callStateForMetrics?.correlationId, // if client sends correlation id as argument of public create(), then it means that this meeting creation is part of a pre-join intent from user
|
|
1238
|
-
});
|
|
1277
|
+
await meeting.fetchMeetingInfo(meetingInfoOptions);
|
|
1239
1278
|
}
|
|
1240
1279
|
} catch (err) {
|
|
1241
1280
|
if (
|
|
@@ -1346,11 +1385,12 @@ export default class Meetings extends WebexPlugin {
|
|
|
1346
1385
|
|
|
1347
1386
|
/**
|
|
1348
1387
|
* syncs all the meeting from server
|
|
1349
|
-
* @
|
|
1388
|
+
* @param {boolean} keepOnlyLocusMeetings - whether the sync should keep only locus meetings or any other meeting in meetingCollection
|
|
1389
|
+
* @returns {Promise<void>}
|
|
1350
1390
|
* @public
|
|
1351
1391
|
* @memberof Meetings
|
|
1352
1392
|
*/
|
|
1353
|
-
public syncMeetings() {
|
|
1393
|
+
public syncMeetings({keepOnlyLocusMeetings = true} = {}): Promise<void> {
|
|
1354
1394
|
return this.request
|
|
1355
1395
|
.getActiveMeetings()
|
|
1356
1396
|
.then((locusArray) => {
|
|
@@ -1374,7 +1414,8 @@ export default class Meetings extends WebexPlugin {
|
|
|
1374
1414
|
// (they had a locusUrl previously but are no longer active) in the sync
|
|
1375
1415
|
for (const meeting of Object.values(meetingsCollection)) {
|
|
1376
1416
|
// @ts-ignore
|
|
1377
|
-
|
|
1417
|
+
const {locusUrl} = meeting;
|
|
1418
|
+
if ((keepOnlyLocusMeetings || locusUrl) && !activeLocusUrl.includes(locusUrl)) {
|
|
1378
1419
|
// destroy function also uploads logs
|
|
1379
1420
|
// @ts-ignore
|
|
1380
1421
|
this.destroy(meeting, MEETING_REMOVED_REASON.NO_MEETINGS_TO_SYNC);
|
|
@@ -341,18 +341,21 @@ export default class Reachability {
|
|
|
341
341
|
return Promise.resolve(results);
|
|
342
342
|
}
|
|
343
343
|
|
|
344
|
-
// @ts-ignore
|
|
345
|
-
const includeTcpReachability = this.webex.config.meetings.experimental.enableTcpReachability;
|
|
346
|
-
|
|
347
344
|
LoggerProxy.logger.log(
|
|
348
345
|
`Reachability:index#performReachabilityChecks --> doing UDP${
|
|
349
|
-
|
|
346
|
+
// @ts-ignore
|
|
347
|
+
this.webex.config.meetings.experimental.enableTcpReachability ? ' and TCP' : ''
|
|
350
348
|
} reachability checks`
|
|
351
349
|
);
|
|
352
350
|
|
|
353
351
|
const clusterReachabilityChecks = Object.keys(clusterList).map((key) => {
|
|
354
352
|
const cluster = clusterList[key];
|
|
355
353
|
|
|
354
|
+
// Linus doesn't support TCP reachability checks on video mesh nodes
|
|
355
|
+
const includeTcpReachability =
|
|
356
|
+
// @ts-ignore
|
|
357
|
+
this.webex.config.meetings.experimental.enableTcpReachability && !cluster.isVideoMesh;
|
|
358
|
+
|
|
356
359
|
if (!includeTcpReachability) {
|
|
357
360
|
cluster.tcp = [];
|
|
358
361
|
}
|
|
@@ -442,7 +442,7 @@ export default class ReconnectionManager {
|
|
|
442
442
|
LoggerProxy.logger.info(
|
|
443
443
|
'ReconnectionManager:index#executeReconnection --> Updating meeting data from server.'
|
|
444
444
|
);
|
|
445
|
-
await this.webex.meetings.syncMeetings();
|
|
445
|
+
await this.webex.meetings.syncMeetings({keepOnlyLocusMeetings: false});
|
|
446
446
|
} catch (syncError) {
|
|
447
447
|
LoggerProxy.logger.info(
|
|
448
448
|
'ReconnectionManager:index#executeReconnection --> Unable to sync meetings, reconnecting.',
|
package/src/roap/index.ts
CHANGED
|
@@ -187,7 +187,7 @@ export default class Roap extends StatelessWebexPlugin {
|
|
|
187
187
|
* @memberof Roap
|
|
188
188
|
*/
|
|
189
189
|
sendRoapMediaRequest(options: any) {
|
|
190
|
-
const {meeting, seq, sdp,
|
|
190
|
+
const {meeting, seq, sdp, tieBreaker} = options;
|
|
191
191
|
const roapMessage = {
|
|
192
192
|
messageType: ROAP.ROAP_TYPES.OFFER,
|
|
193
193
|
sdps: [sdp],
|
|
@@ -197,64 +197,62 @@ export default class Roap extends StatelessWebexPlugin {
|
|
|
197
197
|
headers: ['includeAnswerInHttpResponse', 'noOkInTransaction'],
|
|
198
198
|
};
|
|
199
199
|
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
const sendEmptyMediaId = reconnect && isTurnDiscoverySkipped;
|
|
200
|
+
// The only time we want to send an empty media id is when we are reconnecting, because this way we tell Locus
|
|
201
|
+
// that it needs to create a new confluence, but when reconnecting we always send TURN_DISCOVERY_REQUEST first,
|
|
202
|
+
// so we don't need to ever send an empty media id here
|
|
203
|
+
const sendEmptyMediaId = false;
|
|
205
204
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
205
|
+
return this.roapRequest
|
|
206
|
+
.sendRoap({
|
|
207
|
+
roapMessage,
|
|
208
|
+
locusSelfUrl: meeting.selfUrl,
|
|
209
|
+
mediaId: sendEmptyMediaId ? '' : meeting.mediaId,
|
|
210
|
+
meetingId: meeting.id,
|
|
211
|
+
preferTranscoding: !meeting.isMultistream,
|
|
212
|
+
locusMediaRequest: meeting.locusMediaRequest,
|
|
213
|
+
ipVersion: MeetingUtil.getIpVersion(meeting.webex),
|
|
214
|
+
})
|
|
215
|
+
.then(({locus, mediaConnections}) => {
|
|
216
|
+
if (mediaConnections) {
|
|
217
|
+
meeting.updateMediaConnections(mediaConnections);
|
|
218
|
+
}
|
|
220
219
|
|
|
221
|
-
|
|
220
|
+
let roapAnswer;
|
|
222
221
|
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
if (mediaConnections?.[0]?.remoteSdp) {
|
|
223
|
+
const remoteSdp = JSON.parse(mediaConnections[0].remoteSdp);
|
|
225
224
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
225
|
+
if (remoteSdp.roapMessage) {
|
|
226
|
+
const {
|
|
227
|
+
seq: answerSeq,
|
|
228
|
+
messageType,
|
|
229
|
+
sdps,
|
|
230
|
+
errorType,
|
|
231
|
+
errorCause,
|
|
232
|
+
headers,
|
|
233
|
+
} = remoteSdp.roapMessage;
|
|
235
234
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
235
|
+
roapAnswer = {
|
|
236
|
+
seq: answerSeq,
|
|
237
|
+
messageType,
|
|
238
|
+
sdp: sdps[0],
|
|
239
|
+
errorType,
|
|
240
|
+
errorCause,
|
|
241
|
+
headers,
|
|
242
|
+
};
|
|
245
243
|
}
|
|
244
|
+
}
|
|
246
245
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
246
|
+
if (!roapAnswer) {
|
|
247
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_HTTP_RESPONSE_MISSING, {
|
|
248
|
+
correlationId: meeting.correlationId,
|
|
249
|
+
messageType: 'ANSWER',
|
|
250
|
+
isMultistream: meeting.isMultistream,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
254
253
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
});
|
|
254
|
+
return {locus, roapAnswer};
|
|
255
|
+
});
|
|
258
256
|
}
|
|
259
257
|
|
|
260
258
|
/**
|
|
@@ -7,7 +7,7 @@ import EventsScope from '../common/events/events-scope';
|
|
|
7
7
|
import {
|
|
8
8
|
DEFAULT_GET_STATS_FILTER,
|
|
9
9
|
STATS,
|
|
10
|
-
|
|
10
|
+
MQA_INTERVAL,
|
|
11
11
|
NETWORK_TYPE,
|
|
12
12
|
MEDIA_DEVICES,
|
|
13
13
|
_UNKNOWN_,
|
|
@@ -299,7 +299,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
299
299
|
this.sendMqaData();
|
|
300
300
|
this.mqaInterval = setInterval(() => {
|
|
301
301
|
this.sendMqaData();
|
|
302
|
-
},
|
|
302
|
+
}, MQA_INTERVAL);
|
|
303
303
|
});
|
|
304
304
|
}
|
|
305
305
|
|
|
@@ -29,13 +29,14 @@ export const getAudioReceiverMqa = ({audioReceiver, statsResults, lastMqaDataSen
|
|
|
29
29
|
// add rtpPacket info inside common as also for call analyzer
|
|
30
30
|
audioReceiver.common.rtpPackets =
|
|
31
31
|
statsResults[mediaType][sendrecvType].totalPacketsReceived - lastPacketsReceived || 0;
|
|
32
|
+
audioReceiver.streams[0].common.rtpPackets = audioReceiver.common.rtpPackets;
|
|
33
|
+
|
|
32
34
|
// Hop by hop are numbers and not percentage so we compare on what we sent the last min
|
|
33
35
|
// collect the packets received for the last min
|
|
34
|
-
|
|
35
|
-
audioReceiver.common.mediaHopByHopLost =
|
|
36
|
-
statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost || 0;
|
|
37
|
-
audioReceiver.common.rtpHopByHopLost =
|
|
36
|
+
const totalPacketsLost =
|
|
38
37
|
statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost || 0;
|
|
38
|
+
audioReceiver.common.mediaHopByHopLost = totalPacketsLost;
|
|
39
|
+
audioReceiver.common.rtpHopByHopLost = totalPacketsLost;
|
|
39
40
|
|
|
40
41
|
audioReceiver.streams[0].common.maxRtpJitter =
|
|
41
42
|
// @ts-ignore
|
|
@@ -49,6 +50,7 @@ export const getAudioReceiverMqa = ({audioReceiver, statsResults, lastMqaDataSen
|
|
|
49
50
|
statsResults[mediaType][sendrecvType].fecPacketsReceived -
|
|
50
51
|
lastFecPacketsReceived -
|
|
51
52
|
(statsResults[mediaType][sendrecvType].fecPacketsDiscarded - lastFecPacketsDiscarded);
|
|
53
|
+
audioReceiver.common.fecPackets = fecRecovered || 0;
|
|
52
54
|
|
|
53
55
|
audioReceiver.streams[0].common.rtpEndToEndLost =
|
|
54
56
|
statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost - fecRecovered || 0;
|
|
@@ -105,7 +107,7 @@ export const getAudioSenderMqa = ({audioSender, statsResults, lastMqaDataSent, m
|
|
|
105
107
|
statsResults[mediaType][sendrecvType].totalPacketsLostOnReceiver - lastPacketsLost;
|
|
106
108
|
|
|
107
109
|
audioSender.common.remoteLossRate =
|
|
108
|
-
|
|
110
|
+
audioSender.common.rtpPackets > 0
|
|
109
111
|
? (totalpacketsLostForaMin * 100) / audioSender.common.rtpPackets
|
|
110
112
|
: 0; // This is the packets sent with in last min || 0;
|
|
111
113
|
|
|
@@ -156,16 +158,15 @@ export const getVideoReceiverMqa = ({videoReceiver, statsResults, lastMqaDataSen
|
|
|
156
158
|
statsResults[mediaType][sendrecvType].totalPacketsReceived - lastPacketsReceived || 0;
|
|
157
159
|
videoReceiver.streams[0].common.rtpPackets = videoReceiver.common.rtpPackets;
|
|
158
160
|
|
|
159
|
-
|
|
160
|
-
statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost || 0;
|
|
161
|
-
|
|
162
|
-
// Hope by hop are numbers and not percentage so we compare on what we sent the last min
|
|
161
|
+
// Hop by hop are numbers and not percentage so we compare on what we sent the last min
|
|
163
162
|
// this is including packet lost
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
const totalPacketsLost =
|
|
164
|
+
statsResults[mediaType][sendrecvType].totalPacketsLost - lastPacketsLost || 0;
|
|
165
|
+
videoReceiver.common.mediaHopByHopLost = totalPacketsLost;
|
|
166
|
+
videoReceiver.common.rtpHopByHopLost = totalPacketsLost;
|
|
166
167
|
|
|
167
168
|
// End to end packetloss is after recovery
|
|
168
|
-
videoReceiver.streams[0].common.rtpEndToEndLost =
|
|
169
|
+
videoReceiver.streams[0].common.rtpEndToEndLost = totalPacketsLost;
|
|
169
170
|
|
|
170
171
|
// calculate this values
|
|
171
172
|
|
|
@@ -249,8 +250,8 @@ export const getVideoSenderMqa = ({videoSender, statsResults, lastMqaDataSent, m
|
|
|
249
250
|
statsResults[mediaType][sendrecvType].totalPacketsLostOnReceiver - lastPacketsLost;
|
|
250
251
|
|
|
251
252
|
videoSender.common.remoteLossRate =
|
|
252
|
-
|
|
253
|
-
? (totalpacketsLostForaMin * 100) /
|
|
253
|
+
videoSender.common.rtpPackets > 0
|
|
254
|
+
? (totalpacketsLostForaMin * 100) / videoSender.common.rtpPackets
|
|
254
255
|
: 0; // This is the packets sent with in last min || 0;
|
|
255
256
|
|
|
256
257
|
videoSender.common.maxRoundTripTime =
|
|
@@ -2058,7 +2058,7 @@ describe('plugin-meetings', () => {
|
|
|
2058
2058
|
});
|
|
2059
2059
|
|
|
2060
2060
|
describe('#getTheLocusToUpdate', () => {
|
|
2061
|
-
it('return the cache locus if return to main session', () => {
|
|
2061
|
+
it('return the cache locus if return to main session and do not clear main session cache', () => {
|
|
2062
2062
|
locusInfo.mainSessionLocusCache = {url: 'url'};
|
|
2063
2063
|
locusInfo.controls = {
|
|
2064
2064
|
breakout: {
|
|
@@ -2074,9 +2074,13 @@ describe('plugin-meetings', () => {
|
|
|
2074
2074
|
};
|
|
2075
2075
|
|
|
2076
2076
|
assert.deepEqual(locusInfo.getTheLocusToUpdate(newLocus), {url: 'url'});
|
|
2077
|
+
|
|
2078
|
+
locusInfo.clearMainSessionLocusCache = sinon.stub();
|
|
2079
|
+
locusInfo.getTheLocusToUpdate(newLocus);
|
|
2080
|
+
assert.notCalled(locusInfo.clearMainSessionLocusCache)
|
|
2077
2081
|
});
|
|
2078
2082
|
|
|
2079
|
-
it('return the new locus if return to main session but no cache', () => {
|
|
2083
|
+
it('return the new locus if return to main session but no cache and do not clear main session cache', () => {
|
|
2080
2084
|
locusInfo.mainSessionLocusCache = null;
|
|
2081
2085
|
locusInfo.controls = {
|
|
2082
2086
|
breakout: {
|
|
@@ -2092,10 +2096,22 @@ describe('plugin-meetings', () => {
|
|
|
2092
2096
|
};
|
|
2093
2097
|
|
|
2094
2098
|
assert.deepEqual(locusInfo.getTheLocusToUpdate(newLocus), newLocus);
|
|
2099
|
+
|
|
2100
|
+
locusInfo.clearMainSessionLocusCache = sinon.stub();
|
|
2101
|
+
locusInfo.getTheLocusToUpdate(newLocus);
|
|
2102
|
+
assert.notCalled(locusInfo.clearMainSessionLocusCache)
|
|
2095
2103
|
});
|
|
2096
2104
|
|
|
2097
|
-
it('return the new locus if not return to main session', () => {
|
|
2098
|
-
locusInfo.mainSessionLocusCache = {
|
|
2105
|
+
it('return the new locus if not return to main session and clear main session cache', () => {
|
|
2106
|
+
locusInfo.mainSessionLocusCache = {
|
|
2107
|
+
controls: {
|
|
2108
|
+
breakout: {
|
|
2109
|
+
sessionType: 'MAIN',
|
|
2110
|
+
},
|
|
2111
|
+
},
|
|
2112
|
+
self: {removed: true}
|
|
2113
|
+
};
|
|
2114
|
+
locusInfo.fullState = {state: 'ACTIVE'}
|
|
2099
2115
|
locusInfo.controls = {
|
|
2100
2116
|
breakout: {
|
|
2101
2117
|
sessionType: 'MAIN',
|
|
@@ -2109,7 +2125,39 @@ describe('plugin-meetings', () => {
|
|
|
2109
2125
|
},
|
|
2110
2126
|
};
|
|
2111
2127
|
|
|
2112
|
-
|
|
2128
|
+
locusInfo.clearMainSessionLocusCache = sinon.stub();
|
|
2129
|
+
const result = locusInfo.getTheLocusToUpdate(newLocus);
|
|
2130
|
+
assert.calledOnce(locusInfo.clearMainSessionLocusCache)
|
|
2131
|
+
|
|
2132
|
+
assert.deepEqual(result, newLocus);
|
|
2133
|
+
});
|
|
2134
|
+
|
|
2135
|
+
it('do not clear main session cache when "mainSessionLocusCache?.self?.removed" is not true', () => {
|
|
2136
|
+
locusInfo.mainSessionLocusCache = {
|
|
2137
|
+
controls: {
|
|
2138
|
+
breakout: {
|
|
2139
|
+
sessionType: 'MAIN',
|
|
2140
|
+
},
|
|
2141
|
+
},
|
|
2142
|
+
self: {removed: undefined}
|
|
2143
|
+
};
|
|
2144
|
+
locusInfo.fullState = {state: 'ACTIVE'}
|
|
2145
|
+
locusInfo.controls = {
|
|
2146
|
+
breakout: {
|
|
2147
|
+
sessionType: 'MAIN',
|
|
2148
|
+
},
|
|
2149
|
+
};
|
|
2150
|
+
const newLocus = {
|
|
2151
|
+
controls: {
|
|
2152
|
+
breakout: {
|
|
2153
|
+
sessionType: 'BREAKOUT',
|
|
2154
|
+
},
|
|
2155
|
+
},
|
|
2156
|
+
};
|
|
2157
|
+
|
|
2158
|
+
locusInfo.clearMainSessionLocusCache = sinon.stub();
|
|
2159
|
+
locusInfo.getTheLocusToUpdate(newLocus);
|
|
2160
|
+
assert.notCalled(locusInfo.clearMainSessionLocusCache)
|
|
2113
2161
|
});
|
|
2114
2162
|
});
|
|
2115
2163
|
|