@webex/plugin-meetings 1.149.1 → 1.151.0
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/constants.js +14 -4
- package/dist/constants.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js +88 -11
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/meeting/index.js +368 -42
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +17 -41
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting-info/index.js +1 -1
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/util.js +14 -0
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meetings/index.js +1 -1
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/util.js +0 -16
- package/dist/meetings/util.js.map +1 -1
- package/dist/members/index.js +72 -11
- package/dist/members/index.js.map +1 -1
- package/dist/metrics/config.js +6 -0
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/index.js +26 -1
- package/dist/metrics/index.js.map +1 -1
- package/dist/peer-connection-manager/index.js +1 -1
- package/dist/peer-connection-manager/index.js.map +1 -1
- package/package.json +5 -5
- package/src/constants.js +11 -2
- package/src/locus-info/mediaSharesUtils.js +84 -12
- package/src/meeting/index.js +350 -29
- package/src/meeting/request.js +50 -29
- package/src/meeting-info/index.js +4 -1
- package/src/meeting-info/util.js +13 -0
- package/src/meetings/index.js +1 -1
- package/src/meetings/util.js +0 -14
- package/src/members/index.js +80 -11
- package/src/metrics/config.js +6 -0
- package/src/metrics/index.js +23 -2
- package/src/peer-connection-manager/index.js +7 -2
- package/test/integration/spec/journey.js +177 -3
- package/test/integration/spec/space-meeting.js +33 -5
- package/test/unit/spec/meeting/index.js +547 -2
- package/test/utils/testUtils.js +18 -1
- package/test/utils/webex-test-users.js +2 -0
package/src/meeting/index.js
CHANGED
|
@@ -51,6 +51,7 @@ import {
|
|
|
51
51
|
MEETING_STATE_MACHINE,
|
|
52
52
|
MEETING_STATE,
|
|
53
53
|
MEETINGS,
|
|
54
|
+
METRICS_JOIN_TIMES_MAX_DURATION,
|
|
54
55
|
METRICS_OPERATIONAL_MEASURES,
|
|
55
56
|
MQA_STATS,
|
|
56
57
|
NETWORK_STATUS,
|
|
@@ -1065,10 +1066,45 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1065
1066
|
};
|
|
1066
1067
|
}
|
|
1067
1068
|
|
|
1069
|
+
const localSDPGenRemoteSDPRecv = this.getLocalSDPGenRemoteSDPRecvDelay();
|
|
1070
|
+
|
|
1071
|
+
if (localSDPGenRemoteSDPRecv) {
|
|
1072
|
+
options.joinTimes = {
|
|
1073
|
+
...options.joinTimes,
|
|
1074
|
+
localSDPGenRemoteSDPRecv
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
const callInitiateJoinReq = this.getCallInitiateJoinReq();
|
|
1079
|
+
|
|
1080
|
+
if (callInitiateJoinReq) {
|
|
1081
|
+
options.joinTimes = {
|
|
1082
|
+
...options.joinTimes,
|
|
1083
|
+
callInitiateJoinReq
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
const joinReqResp = this.getJoinReqResp();
|
|
1088
|
+
|
|
1089
|
+
if (joinReqResp) {
|
|
1090
|
+
options.joinTimes = {
|
|
1091
|
+
...options.joinTimes,
|
|
1092
|
+
joinReqResp
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
const getTotalJmt = this.getTotalJmt();
|
|
1097
|
+
|
|
1098
|
+
if (getTotalJmt) {
|
|
1099
|
+
options.joinTimes = {
|
|
1100
|
+
...options.joinTimes,
|
|
1101
|
+
getTotalJmt
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1068
1105
|
if (options.type === MQA_STATS.CA_TYPE) {
|
|
1069
1106
|
payload = Metrics.initMediaPayload(options.event, identifiers, options);
|
|
1070
1107
|
}
|
|
1071
|
-
|
|
1072
1108
|
else {
|
|
1073
1109
|
payload = Metrics.initPayload(options.event, identifiers, options);
|
|
1074
1110
|
}
|
|
@@ -1310,7 +1346,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1310
1346
|
|
|
1311
1347
|
/**
|
|
1312
1348
|
* Set up the locus info media shares listener
|
|
1313
|
-
* update content sharing id value for members, and updates the member
|
|
1349
|
+
* update content and whiteboard sharing id value for members, and updates the member
|
|
1314
1350
|
* notifies consumer with members:content:update {activeContentSharingId, endedContentSharingId}
|
|
1315
1351
|
* @returns {undefined}
|
|
1316
1352
|
* @private
|
|
@@ -1319,11 +1355,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1319
1355
|
setUpLocusMediaSharesListener() {
|
|
1320
1356
|
// Will get triggered on local and remote share
|
|
1321
1357
|
this.locusInfo.on(EVENTS.LOCUS_INFO_UPDATE_MEDIA_SHARES, (payload) => {
|
|
1322
|
-
const {
|
|
1358
|
+
const {content: contentShare, whiteboard: whiteboardShare} = payload.current;
|
|
1359
|
+
const previousContentShare = payload.previous?.content;
|
|
1360
|
+
const previousWhiteboardShare = payload.previous?.whiteboard;
|
|
1323
1361
|
|
|
1324
1362
|
if (
|
|
1325
|
-
|
|
1326
|
-
|
|
1363
|
+
(contentShare.beneficiaryId === previousContentShare?.beneficiaryId &&
|
|
1364
|
+
contentShare.disposition === previousContentShare?.disposition) &&
|
|
1365
|
+
(whiteboardShare.beneficiaryId === previousWhiteboardShare?.beneficiaryId &&
|
|
1366
|
+
whiteboardShare.disposition === previousWhiteboardShare?.disposition &&
|
|
1367
|
+
whiteboardShare.resourceUrl === previousWhiteboardShare?.resourceUrl)
|
|
1327
1368
|
) {
|
|
1328
1369
|
// nothing changed, so ignore
|
|
1329
1370
|
// (this happens when we steal presentation from remote)
|
|
@@ -1334,15 +1375,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1334
1375
|
|
|
1335
1376
|
// REMOTE - check if remote started sharing
|
|
1336
1377
|
if (
|
|
1337
|
-
this.selfId !==
|
|
1338
|
-
disposition === FLOOR_ACTION.GRANTED
|
|
1378
|
+
this.selfId !== contentShare.beneficiaryId &&
|
|
1379
|
+
contentShare.disposition === FLOOR_ACTION.GRANTED
|
|
1339
1380
|
) {
|
|
1381
|
+
// CONTENT - sharing content remote
|
|
1340
1382
|
newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
|
|
1341
1383
|
}
|
|
1342
|
-
// LOCAL - check if we started sharing
|
|
1384
|
+
// LOCAL - check if we started sharing content
|
|
1343
1385
|
else if (
|
|
1344
|
-
this.selfId ===
|
|
1345
|
-
disposition === FLOOR_ACTION.GRANTED
|
|
1386
|
+
this.selfId === contentShare.beneficiaryId &&
|
|
1387
|
+
contentShare.disposition === FLOOR_ACTION.GRANTED
|
|
1346
1388
|
) {
|
|
1347
1389
|
if (this.mediaProperties.shareTrack?.readyState === 'ended') {
|
|
1348
1390
|
this.stopShare({
|
|
@@ -1353,13 +1395,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1353
1395
|
});
|
|
1354
1396
|
}
|
|
1355
1397
|
else {
|
|
1398
|
+
// CONTENT - sharing content local
|
|
1356
1399
|
newShareStatus = SHARE_STATUS.LOCAL_SHARE_ACTIVE;
|
|
1357
1400
|
}
|
|
1358
1401
|
}
|
|
1359
|
-
//
|
|
1402
|
+
// If we did not hit the cases above, no one is sharng content, so we check if we are sharing whiteboard
|
|
1403
|
+
// There is no concept of local/remote share for whiteboard
|
|
1404
|
+
// It does not matter who requested to share the whiteboard, everyone gets the same view
|
|
1405
|
+
else if (whiteboardShare.disposition === FLOOR_ACTION.GRANTED) {
|
|
1406
|
+
// WHITEBOARD - sharing whiteboard
|
|
1407
|
+
newShareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
|
1408
|
+
}
|
|
1409
|
+
// or if content share is either released or null and whiteboard share is either released or null, no one is sharing
|
|
1360
1410
|
else if (
|
|
1361
|
-
|
|
1362
|
-
|
|
1411
|
+
(previousContentShare &&
|
|
1412
|
+
(contentShare.disposition === FLOOR_ACTION.RELEASED) || (contentShare.disposition === null)) &&
|
|
1413
|
+
(previousWhiteboardShare &&
|
|
1414
|
+
(whiteboardShare.disposition === FLOOR_ACTION.RELEASED) || (whiteboardShare.disposition === null))
|
|
1363
1415
|
) {
|
|
1364
1416
|
newShareStatus = SHARE_STATUS.NO_SHARE;
|
|
1365
1417
|
}
|
|
@@ -1397,6 +1449,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1397
1449
|
);
|
|
1398
1450
|
break;
|
|
1399
1451
|
|
|
1452
|
+
case SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE:
|
|
1453
|
+
Trigger.trigger(
|
|
1454
|
+
this,
|
|
1455
|
+
{
|
|
1456
|
+
file: 'meeting/index',
|
|
1457
|
+
function: 'stopWhiteboardShare'
|
|
1458
|
+
},
|
|
1459
|
+
EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD
|
|
1460
|
+
);
|
|
1461
|
+
break;
|
|
1462
|
+
|
|
1400
1463
|
case SHARE_STATUS.NO_SHARE:
|
|
1401
1464
|
// nothing to do
|
|
1402
1465
|
break;
|
|
@@ -1417,13 +1480,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1417
1480
|
},
|
|
1418
1481
|
EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
|
1419
1482
|
{
|
|
1420
|
-
memberId:
|
|
1483
|
+
memberId: contentShare.beneficiaryId
|
|
1421
1484
|
}
|
|
1422
1485
|
);
|
|
1423
1486
|
};
|
|
1424
1487
|
|
|
1425
1488
|
// if a remote participant is stealing the presentation from us
|
|
1426
|
-
if (this.mediaProperties.mediaDirection?.sendShare) {
|
|
1489
|
+
if (!this.mediaProperties.mediaDirection?.sendShare || oldShareStatus === SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE) {
|
|
1490
|
+
sendStartedSharingRemote();
|
|
1491
|
+
}
|
|
1492
|
+
else {
|
|
1427
1493
|
this.updateShare({
|
|
1428
1494
|
sendShare: false,
|
|
1429
1495
|
receiveShare: this.mediaProperties.mediaDirection.receiveShare
|
|
@@ -1432,9 +1498,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1432
1498
|
sendStartedSharingRemote();
|
|
1433
1499
|
});
|
|
1434
1500
|
}
|
|
1435
|
-
else {
|
|
1436
|
-
sendStartedSharingRemote();
|
|
1437
|
-
}
|
|
1438
1501
|
break;
|
|
1439
1502
|
}
|
|
1440
1503
|
|
|
@@ -1450,6 +1513,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1450
1513
|
Metrics.postEvent({event: eventType.LOCAL_SHARE_FLOOR_GRANTED, meeting: this});
|
|
1451
1514
|
break;
|
|
1452
1515
|
|
|
1516
|
+
case SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE:
|
|
1517
|
+
Trigger.trigger(
|
|
1518
|
+
this,
|
|
1519
|
+
{
|
|
1520
|
+
file: 'meeting/index',
|
|
1521
|
+
function: 'startWhiteboardShare'
|
|
1522
|
+
},
|
|
1523
|
+
EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
|
1524
|
+
{
|
|
1525
|
+
resourceUrl: whiteboardShare.resourceUrl,
|
|
1526
|
+
memberId: whiteboardShare.beneficiaryId
|
|
1527
|
+
}
|
|
1528
|
+
);
|
|
1529
|
+
Metrics.postEvent({event: eventType.WHITEBOARD_SHARE_FLOOR_GRANTED, meeting: this});
|
|
1530
|
+
break;
|
|
1531
|
+
|
|
1453
1532
|
case SHARE_STATUS.NO_SHARE:
|
|
1454
1533
|
// nothing to do
|
|
1455
1534
|
break;
|
|
@@ -1471,9 +1550,27 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1471
1550
|
},
|
|
1472
1551
|
EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
|
1473
1552
|
{
|
|
1474
|
-
memberId:
|
|
1553
|
+
memberId: contentShare.beneficiaryId
|
|
1554
|
+
}
|
|
1555
|
+
);
|
|
1556
|
+
this.members.locusMediaSharesUpdate(payload);
|
|
1557
|
+
}
|
|
1558
|
+
else if (newShareStatus === SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE) {
|
|
1559
|
+
// if we got here, then some remote participant has stolen
|
|
1560
|
+
// the presentation from another remote participant
|
|
1561
|
+
Trigger.trigger(
|
|
1562
|
+
this,
|
|
1563
|
+
{
|
|
1564
|
+
file: 'meeting/index',
|
|
1565
|
+
function: 'startWhiteboardShare'
|
|
1566
|
+
},
|
|
1567
|
+
EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
|
1568
|
+
{
|
|
1569
|
+
resourceUrl: whiteboardShare.resourceUrl,
|
|
1570
|
+
memberId: whiteboardShare.beneficiaryId
|
|
1475
1571
|
}
|
|
1476
1572
|
);
|
|
1573
|
+
Metrics.postEvent({event: eventType.WHITEBOARD_SHARE_FLOOR_GRANTED, meeting: this});
|
|
1477
1574
|
this.members.locusMediaSharesUpdate(payload);
|
|
1478
1575
|
}
|
|
1479
1576
|
});
|
|
@@ -3311,12 +3408,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3311
3408
|
}
|
|
3312
3409
|
}
|
|
3313
3410
|
|
|
3314
|
-
return MeetingUtil.joinMeetingOptions(this, options)
|
|
3315
|
-
|
|
3316
|
-
|
|
3411
|
+
return MeetingUtil.joinMeetingOptions(this, options)
|
|
3412
|
+
.then((join) => {
|
|
3413
|
+
this.meetingFiniteStateMachine.join();
|
|
3414
|
+
LoggerProxy.logger.log('Meeting:index#join --> Success');
|
|
3317
3415
|
|
|
3318
|
-
|
|
3319
|
-
|
|
3416
|
+
return join;
|
|
3417
|
+
})
|
|
3320
3418
|
.then((join) => {
|
|
3321
3419
|
joinSuccess(join);
|
|
3322
3420
|
this.deferJoin = undefined;
|
|
@@ -3790,7 +3888,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3790
3888
|
meetingId: this.id,
|
|
3791
3889
|
remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
|
|
3792
3890
|
enableRtx: this.config.enableRtx,
|
|
3793
|
-
enableExtmap: this.config.enableExtmap
|
|
3891
|
+
enableExtmap: this.config.enableExtmap,
|
|
3892
|
+
setStartLocalSDPGenRemoteSDPRecvDelay: this.setStartLocalSDPGenRemoteSDPRecvDelay.bind(this)
|
|
3794
3893
|
})
|
|
3795
3894
|
.then((peerConnection) => this.getDevices().then((devices) => {
|
|
3796
3895
|
MeetingUtil.handleDeviceLogging(devices);
|
|
@@ -4491,6 +4590,105 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4491
4590
|
});
|
|
4492
4591
|
}
|
|
4493
4592
|
|
|
4593
|
+
/**
|
|
4594
|
+
* Start sharing whiteboard given channelUrl
|
|
4595
|
+
* @param {string} channelUrl whiteboard url
|
|
4596
|
+
* @param {String} resourceToken token created by authorize media injector
|
|
4597
|
+
* @returns {Promise}
|
|
4598
|
+
* @public
|
|
4599
|
+
* @memberof Meeting
|
|
4600
|
+
*/
|
|
4601
|
+
startWhiteboardShare(channelUrl, resourceToken) {
|
|
4602
|
+
const whiteboard = this.locusInfo.mediaShares.find((element) => element.name === 'whiteboard');
|
|
4603
|
+
|
|
4604
|
+
if (!channelUrl) {
|
|
4605
|
+
return Promise.reject(new ParameterError('Cannot share without channelUrl.'));
|
|
4606
|
+
}
|
|
4607
|
+
|
|
4608
|
+
if (whiteboard) {
|
|
4609
|
+
Metrics.postEvent({event: eventType.WHITEBOARD_SHARE_INITIATED, meeting: this});
|
|
4610
|
+
|
|
4611
|
+
const body = {
|
|
4612
|
+
disposition: FLOOR_ACTION.GRANTED,
|
|
4613
|
+
personUrl: this.locusInfo.self.url,
|
|
4614
|
+
deviceUrl: this.deviceUrl,
|
|
4615
|
+
uri: whiteboard.url,
|
|
4616
|
+
resourceUrl: channelUrl
|
|
4617
|
+
};
|
|
4618
|
+
|
|
4619
|
+
if (resourceToken) {
|
|
4620
|
+
body.resourceToken = resourceToken;
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
return this.meetingRequest.changeMeetingFloor(body)
|
|
4624
|
+
.then(() => {
|
|
4625
|
+
this.isSharing = false;
|
|
4626
|
+
|
|
4627
|
+
return Promise.resolve();
|
|
4628
|
+
})
|
|
4629
|
+
.catch((error) => {
|
|
4630
|
+
LoggerProxy.logger.error('Meeting:index#startWhiteboardShare --> Error ', error);
|
|
4631
|
+
|
|
4632
|
+
Metrics.sendOperationalMetric(
|
|
4633
|
+
METRICS_OPERATIONAL_MEASURES.MEETING_START_WHITEBOARD_SHARE_FAILURE,
|
|
4634
|
+
{
|
|
4635
|
+
correlation_id: this.correlationId,
|
|
4636
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4637
|
+
reason: error.message,
|
|
4638
|
+
stack: error.stack,
|
|
4639
|
+
board: {channelUrl}
|
|
4640
|
+
}
|
|
4641
|
+
);
|
|
4642
|
+
|
|
4643
|
+
return Promise.reject(error);
|
|
4644
|
+
});
|
|
4645
|
+
}
|
|
4646
|
+
|
|
4647
|
+
return Promise.reject(new ParameterError('Cannot share without whiteboard.'));
|
|
4648
|
+
}
|
|
4649
|
+
|
|
4650
|
+
/**
|
|
4651
|
+
* Stop sharing whiteboard given channelUrl
|
|
4652
|
+
* @param {string} channelUrl whiteboard url
|
|
4653
|
+
* @returns {Promise}
|
|
4654
|
+
* @public
|
|
4655
|
+
* @memberof Meeting
|
|
4656
|
+
*/
|
|
4657
|
+
stopWhiteboardShare(channelUrl) {
|
|
4658
|
+
const whiteboard = this.locusInfo.mediaShares.find((element) => element.name === 'whiteboard');
|
|
4659
|
+
|
|
4660
|
+
if (whiteboard) {
|
|
4661
|
+
Metrics.postEvent({event: eventType.WHITEBOARD_SHARE_STOPPED, meeting: this});
|
|
4662
|
+
|
|
4663
|
+
return this.meetingRequest.changeMeetingFloor({
|
|
4664
|
+
disposition: FLOOR_ACTION.RELEASED,
|
|
4665
|
+
personUrl: this.locusInfo.self.url,
|
|
4666
|
+
deviceUrl: this.deviceUrl,
|
|
4667
|
+
uri: whiteboard.url
|
|
4668
|
+
})
|
|
4669
|
+
.catch((error) => {
|
|
4670
|
+
LoggerProxy.logger.error('Meeting:index#stopWhiteboardShare --> Error ', error);
|
|
4671
|
+
|
|
4672
|
+
Metrics.sendOperationalMetric(
|
|
4673
|
+
METRICS_OPERATIONAL_MEASURES.STOP_WHITEBOARD_SHARE_FAILURE,
|
|
4674
|
+
{
|
|
4675
|
+
correlation_id: this.correlationId,
|
|
4676
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4677
|
+
reason: error.message,
|
|
4678
|
+
stack: error.stack,
|
|
4679
|
+
board: {channelUrl}
|
|
4680
|
+
}
|
|
4681
|
+
);
|
|
4682
|
+
|
|
4683
|
+
return Promise.reject(error);
|
|
4684
|
+
})
|
|
4685
|
+
.finally(() => {
|
|
4686
|
+
});
|
|
4687
|
+
}
|
|
4688
|
+
|
|
4689
|
+
return Promise.reject(new ParameterError('Cannot stop share without whiteboard.'));
|
|
4690
|
+
}
|
|
4691
|
+
|
|
4494
4692
|
/**
|
|
4495
4693
|
* Start sharing content with server
|
|
4496
4694
|
* @returns {Promise} see #meetingRequest.changeMeetingFloor
|
|
@@ -4564,7 +4762,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4564
4762
|
Metrics.postEvent({event: eventType.SHARE_STOPPED, meeting: this});
|
|
4565
4763
|
Media.stopTracks(this.mediaProperties.shareTrack);
|
|
4566
4764
|
|
|
4567
|
-
if (
|
|
4765
|
+
if (content.floor.beneficiary.id !== this.selfId) {
|
|
4568
4766
|
// remote participant started sharing and caused our sharing to stop, we don't want to send any floor action request in that case
|
|
4569
4767
|
this.isSharing = false;
|
|
4570
4768
|
|
|
@@ -5078,9 +5276,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5078
5276
|
}
|
|
5079
5277
|
|
|
5080
5278
|
/**
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5279
|
+
* @param {string} typeMedia 'audio' or 'video'
|
|
5280
|
+
* @returns {undefined}
|
|
5281
|
+
*/
|
|
5084
5282
|
setEndSendingMediaDelay(typeMedia) {
|
|
5085
5283
|
this[`endSendingMediaDelay${typeMedia}`] = performance.now();
|
|
5086
5284
|
}
|
|
@@ -5095,4 +5293,127 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5095
5293
|
|
|
5096
5294
|
return (start && end) ? end - start : undefined;
|
|
5097
5295
|
}
|
|
5296
|
+
|
|
5297
|
+
/**
|
|
5298
|
+
*
|
|
5299
|
+
* @returns {undefined}
|
|
5300
|
+
*/
|
|
5301
|
+
setStartLocalSDPGenRemoteSDPRecvDelay() {
|
|
5302
|
+
if (!this.startLocalSDPGenRemoteSDPRecvDelay) {
|
|
5303
|
+
this.startLocalSDPGenRemoteSDPRecvDelay = performance.now();
|
|
5304
|
+
this.endLocalSDPGenRemoteSDPRecvDelay = undefined;
|
|
5305
|
+
}
|
|
5306
|
+
}
|
|
5307
|
+
|
|
5308
|
+
/**
|
|
5309
|
+
*
|
|
5310
|
+
* @returns {undefined}
|
|
5311
|
+
*/
|
|
5312
|
+
setEndLocalSDPGenRemoteSDPRecvDelay() {
|
|
5313
|
+
if (!this.endLocalSDPGenRemoteSDPRecvDelay) {
|
|
5314
|
+
this.endLocalSDPGenRemoteSDPRecvDelay = performance.now();
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
|
|
5318
|
+
/**
|
|
5319
|
+
*
|
|
5320
|
+
* @returns {string} duration between local SDP generation and remote SDP reception
|
|
5321
|
+
*/
|
|
5322
|
+
getLocalSDPGenRemoteSDPRecvDelay() {
|
|
5323
|
+
const start = this.startLocalSDPGenRemoteSDPRecvDelay;
|
|
5324
|
+
const end = this.endLocalSDPGenRemoteSDPRecvDelay;
|
|
5325
|
+
|
|
5326
|
+
if (start && end) {
|
|
5327
|
+
const calculatedDelay = end - start;
|
|
5328
|
+
|
|
5329
|
+
return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ?
|
|
5330
|
+
undefined :
|
|
5331
|
+
calculatedDelay;
|
|
5332
|
+
}
|
|
5333
|
+
|
|
5334
|
+
return undefined;
|
|
5335
|
+
}
|
|
5336
|
+
|
|
5337
|
+
/**
|
|
5338
|
+
*
|
|
5339
|
+
* @returns {undefined}
|
|
5340
|
+
*/
|
|
5341
|
+
setStartCallInitiateJoinReq() {
|
|
5342
|
+
this.startCallInitiateJoinReq = performance.now();
|
|
5343
|
+
this.endCallInitiateJoinReq = undefined;
|
|
5344
|
+
}
|
|
5345
|
+
|
|
5346
|
+
/**
|
|
5347
|
+
*
|
|
5348
|
+
* @returns {undefined}
|
|
5349
|
+
*/
|
|
5350
|
+
setEndCallInitiateJoinReq() {
|
|
5351
|
+
this.endCallInitiateJoinReq = performance.now();
|
|
5352
|
+
}
|
|
5353
|
+
|
|
5354
|
+
/**
|
|
5355
|
+
*
|
|
5356
|
+
* @returns {string} duration between call initiate and sending join request to locus
|
|
5357
|
+
*/
|
|
5358
|
+
getCallInitiateJoinReq() {
|
|
5359
|
+
const start = this.startCallInitiateJoinReq;
|
|
5360
|
+
const end = this.endCallInitiateJoinReq;
|
|
5361
|
+
|
|
5362
|
+
if (start && end) {
|
|
5363
|
+
const calculatedDelay = end - start;
|
|
5364
|
+
|
|
5365
|
+
return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ?
|
|
5366
|
+
undefined :
|
|
5367
|
+
calculatedDelay;
|
|
5368
|
+
}
|
|
5369
|
+
|
|
5370
|
+
return undefined;
|
|
5371
|
+
}
|
|
5372
|
+
|
|
5373
|
+
/**
|
|
5374
|
+
*
|
|
5375
|
+
* @returns {undefined}
|
|
5376
|
+
*/
|
|
5377
|
+
setStartJoinReqResp() {
|
|
5378
|
+
this.startJoinReqResp = performance.now();
|
|
5379
|
+
this.endJoinReqResp = undefined;
|
|
5380
|
+
}
|
|
5381
|
+
|
|
5382
|
+
/**
|
|
5383
|
+
*
|
|
5384
|
+
* @returns {undefined}
|
|
5385
|
+
*/
|
|
5386
|
+
setEndJoinReqResp() {
|
|
5387
|
+
this.endJoinReqResp = performance.now();
|
|
5388
|
+
}
|
|
5389
|
+
|
|
5390
|
+
/**
|
|
5391
|
+
*
|
|
5392
|
+
* @returns {string} duration between sending locus join request and receiving join response
|
|
5393
|
+
*/
|
|
5394
|
+
getJoinReqResp() {
|
|
5395
|
+
const start = this.startJoinReqResp;
|
|
5396
|
+
const end = this.endJoinReqResp;
|
|
5397
|
+
|
|
5398
|
+
if (start && end) {
|
|
5399
|
+
const calculatedDelay = end - start;
|
|
5400
|
+
|
|
5401
|
+
return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ?
|
|
5402
|
+
undefined :
|
|
5403
|
+
calculatedDelay;
|
|
5404
|
+
}
|
|
5405
|
+
|
|
5406
|
+
return undefined;
|
|
5407
|
+
}
|
|
5408
|
+
|
|
5409
|
+
/**
|
|
5410
|
+
*
|
|
5411
|
+
* @returns {string} duration between call initiate and successful locus join (even if it is in lobby)
|
|
5412
|
+
*/
|
|
5413
|
+
getTotalJmt() {
|
|
5414
|
+
const start = this.startCallInitiateJoinReq;
|
|
5415
|
+
const end = this.endJoinReqResp;
|
|
5416
|
+
|
|
5417
|
+
return (start && end) ? end - start : undefined;
|
|
5418
|
+
}
|
|
5098
5419
|
}
|
package/src/meeting/request.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import uuid from 'uuid';
|
|
2
2
|
import {debounce} from 'lodash';
|
|
3
3
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
4
|
-
import {
|
|
5
|
-
deviceType
|
|
6
|
-
} from '@webex/common';
|
|
4
|
+
import {deviceType} from '@webex/common';
|
|
7
5
|
|
|
8
6
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
9
7
|
import {
|
|
@@ -51,7 +49,19 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
51
49
|
*/
|
|
52
50
|
async joinMeeting(options) {
|
|
53
51
|
const {
|
|
54
|
-
asResourceOccupant,
|
|
52
|
+
asResourceOccupant,
|
|
53
|
+
sipUri,
|
|
54
|
+
meetingNumber,
|
|
55
|
+
deviceUrl,
|
|
56
|
+
locusUrl,
|
|
57
|
+
resourceId,
|
|
58
|
+
correlationId,
|
|
59
|
+
ensureConversation,
|
|
60
|
+
moderator,
|
|
61
|
+
pin,
|
|
62
|
+
moveToResource,
|
|
63
|
+
roapMessage,
|
|
64
|
+
preferTranscoding
|
|
55
65
|
} = options;
|
|
56
66
|
|
|
57
67
|
LoggerProxy.logger.info(
|
|
@@ -95,29 +105,16 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
95
105
|
if (locusUrl) {
|
|
96
106
|
url = `${locusUrl}/${PARTICIPANT}`;
|
|
97
107
|
}
|
|
98
|
-
else if (meetingNumber) {
|
|
108
|
+
else if (sipUri || meetingNumber) {
|
|
99
109
|
try {
|
|
100
110
|
await this.webex.internal.services.waitForCatalog('postauth');
|
|
101
111
|
url = `${this.webex.internal.services.get('locus')}/${LOCI}/${CALL}`;
|
|
102
112
|
body.invitee = {
|
|
103
|
-
address: `wbxmn:${meetingNumber}`
|
|
113
|
+
address: sipUri || `wbxmn:${meetingNumber}`
|
|
104
114
|
};
|
|
105
115
|
}
|
|
106
116
|
catch (e) {
|
|
107
|
-
LoggerProxy.logger.error(`Meeting:request#joinMeeting
|
|
108
|
-
throw (e);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
else if (sipUri) {
|
|
112
|
-
try {
|
|
113
|
-
await this.webex.internal.services.waitForCatalog('postauth');
|
|
114
|
-
url = `${this.webex.internal.services.get('locus')}/${LOCI}/${CALL}`;
|
|
115
|
-
body.invitee = {
|
|
116
|
-
address: sipUri
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
catch (e) {
|
|
120
|
-
LoggerProxy.logger.error(`Meeting:request#joinMeeting sipUrl --> ${e}`);
|
|
117
|
+
LoggerProxy.logger.error(`Meeting:request#joinMeeting ${sipUri ? 'sipUri' : 'meetingNumber'} --> ${e}`);
|
|
121
118
|
throw (e);
|
|
122
119
|
}
|
|
123
120
|
}
|
|
@@ -154,7 +151,10 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
154
151
|
* @private
|
|
155
152
|
*/
|
|
156
153
|
dialIn({
|
|
157
|
-
locusUrl,
|
|
154
|
+
locusUrl,
|
|
155
|
+
dialInUrl,
|
|
156
|
+
clientUrl,
|
|
157
|
+
correlationId
|
|
158
158
|
}) {
|
|
159
159
|
LoggerProxy.logger.info(
|
|
160
160
|
'Meeting:request#dialIn --> Provisioning a dial in device',
|
|
@@ -195,7 +195,11 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
195
195
|
* @private
|
|
196
196
|
*/
|
|
197
197
|
dialOut({
|
|
198
|
-
locusUrl,
|
|
198
|
+
locusUrl,
|
|
199
|
+
dialOutUrl,
|
|
200
|
+
phoneNumber,
|
|
201
|
+
clientUrl,
|
|
202
|
+
correlationId
|
|
199
203
|
}) {
|
|
200
204
|
LoggerProxy.logger.info(
|
|
201
205
|
'Meeting:request#dialOut --> Provisioning a dial out device',
|
|
@@ -294,7 +298,10 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
294
298
|
* @private
|
|
295
299
|
*/
|
|
296
300
|
disconnectPhoneAudio({
|
|
297
|
-
locusUrl,
|
|
301
|
+
locusUrl,
|
|
302
|
+
phoneUrl,
|
|
303
|
+
correlationId,
|
|
304
|
+
selfId
|
|
298
305
|
}) {
|
|
299
306
|
LoggerProxy.logger.info(
|
|
300
307
|
`Meeting:request#disconnectPhoneAudio --> request phone ${phoneUrl} to leave`,
|
|
@@ -334,7 +341,11 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
334
341
|
* @returns {Promise}
|
|
335
342
|
*/
|
|
336
343
|
leaveMeeting({
|
|
337
|
-
locusUrl,
|
|
344
|
+
locusUrl,
|
|
345
|
+
selfId,
|
|
346
|
+
deviceUrl: url,
|
|
347
|
+
resourceId,
|
|
348
|
+
correlationId
|
|
338
349
|
}) {
|
|
339
350
|
LoggerProxy.logger.info(
|
|
340
351
|
'Meeting:request#leaveMeeting --> Leaving a meeting',
|
|
@@ -512,13 +523,19 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
512
523
|
};
|
|
513
524
|
}
|
|
514
525
|
|
|
526
|
+
const body = {
|
|
527
|
+
floor: floorReq,
|
|
528
|
+
resourceUrl: options.resourceUrl
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
if (options?.resourceToken) {
|
|
532
|
+
body.resourceToken = options?.resourceToken;
|
|
533
|
+
}
|
|
534
|
+
|
|
515
535
|
return this.request({
|
|
516
536
|
uri: options.uri,
|
|
517
537
|
method: HTTP_VERBS.PUT,
|
|
518
|
-
body
|
|
519
|
-
floor: floorReq,
|
|
520
|
-
resourceUrl: options.resourceUrl
|
|
521
|
-
}
|
|
538
|
+
body
|
|
522
539
|
});
|
|
523
540
|
}
|
|
524
541
|
|
|
@@ -559,7 +576,11 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
559
576
|
* @returns {Promise}
|
|
560
577
|
*/
|
|
561
578
|
changeVideoLayout({
|
|
562
|
-
locusUrl,
|
|
579
|
+
locusUrl,
|
|
580
|
+
deviceUrl,
|
|
581
|
+
layoutType,
|
|
582
|
+
main,
|
|
583
|
+
content
|
|
563
584
|
}) {
|
|
564
585
|
// send main/content renderInfo only if both width and height are specified
|
|
565
586
|
if (main && (!main.width || !main.height)) {
|
|
@@ -108,7 +108,10 @@ export default class MeetingInfo {
|
|
|
108
108
|
* @memberof MeetingInfo
|
|
109
109
|
*/
|
|
110
110
|
fetchMeetingInfo(destination, type = null) {
|
|
111
|
-
return this.fetchInfoOptions(
|
|
111
|
+
return this.fetchInfoOptions(
|
|
112
|
+
MeetingInfoUtil.extractDestination(destination, type),
|
|
113
|
+
type
|
|
114
|
+
).then((options) =>
|
|
112
115
|
// fetch meeting info
|
|
113
116
|
this.requestFetchInfo(options).catch((error) => {
|
|
114
117
|
// if it failed the first time as meeting link
|
package/src/meeting-info/util.js
CHANGED
|
@@ -35,6 +35,19 @@ import {
|
|
|
35
35
|
|
|
36
36
|
const MeetingInfoUtil = {};
|
|
37
37
|
|
|
38
|
+
MeetingInfoUtil.extractDestination = (destination, type) => {
|
|
39
|
+
let dest = destination;
|
|
40
|
+
|
|
41
|
+
if (type === _LOCUS_ID_) {
|
|
42
|
+
if (!(destination && destination.url)) {
|
|
43
|
+
throw new ParameterError('You cannot create a meeting by locus without a locus.url defined');
|
|
44
|
+
}
|
|
45
|
+
dest = destination.url;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return dest;
|
|
49
|
+
};
|
|
50
|
+
|
|
38
51
|
MeetingInfoUtil.getParsedUrl = (link) => {
|
|
39
52
|
try {
|
|
40
53
|
let parsedUrl = url.parse(link);
|
package/src/meetings/index.js
CHANGED
|
@@ -724,7 +724,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
724
724
|
this.meetingCollection.set(meeting);
|
|
725
725
|
|
|
726
726
|
try {
|
|
727
|
-
const info = await this.meetingInfo.fetchMeetingInfo(
|
|
727
|
+
const info = await this.meetingInfo.fetchMeetingInfo(destination, type);
|
|
728
728
|
|
|
729
729
|
meeting.parseMeetingInfo(info);
|
|
730
730
|
meeting.meetingInfo = info ? info.body : null;
|