@webex/plugin-meetings 2.60.1-next.7 → 2.60.1-next.9
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/meeting/index.ts
CHANGED
|
@@ -233,6 +233,13 @@ export enum ScreenShareFloorStatus {
|
|
|
233
233
|
RELEASED = 'floor_released',
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
type FetchMeetingInfoParams = {
|
|
237
|
+
password?: string;
|
|
238
|
+
captchaCode?: string;
|
|
239
|
+
extraParams?: Record<string, any>;
|
|
240
|
+
sendCAevents?: boolean;
|
|
241
|
+
};
|
|
242
|
+
|
|
236
243
|
/**
|
|
237
244
|
* MediaDirection
|
|
238
245
|
* @typedef {Object} MediaDirection
|
|
@@ -615,6 +622,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
615
622
|
environment: string;
|
|
616
623
|
namespace = MEETINGS;
|
|
617
624
|
allowMediaInLobby: boolean;
|
|
625
|
+
localShareInstanceId: string;
|
|
626
|
+
remoteShareInstanceId: string;
|
|
618
627
|
turnDiscoverySkippedReason: string;
|
|
619
628
|
turnServerUsed: boolean;
|
|
620
629
|
areVoiceaEventsSetup = false;
|
|
@@ -1323,6 +1332,24 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1323
1332
|
*/
|
|
1324
1333
|
this.keepAliveTimerId = null;
|
|
1325
1334
|
|
|
1335
|
+
/**
|
|
1336
|
+
* id for tracking Local Share instances in Call Analyzer
|
|
1337
|
+
* @instance
|
|
1338
|
+
* @type {String}
|
|
1339
|
+
* @private
|
|
1340
|
+
* @memberof Meeting
|
|
1341
|
+
*/
|
|
1342
|
+
this.localShareInstanceId = null;
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* id for tracking Remote Share instances in Call Analyzer
|
|
1346
|
+
* @instance
|
|
1347
|
+
* @type {String}
|
|
1348
|
+
* @private
|
|
1349
|
+
* @memberof Meeting
|
|
1350
|
+
*/
|
|
1351
|
+
this.remoteShareInstanceId = null;
|
|
1352
|
+
|
|
1326
1353
|
/**
|
|
1327
1354
|
* The class that helps to control recording functions: start, stop, pause, resume, etc
|
|
1328
1355
|
* @instance
|
|
@@ -1477,6 +1504,97 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1477
1504
|
this.callStateForMetrics.correlationId = correlationId;
|
|
1478
1505
|
}
|
|
1479
1506
|
|
|
1507
|
+
/**
|
|
1508
|
+
* Set meeting info and trigger `MEETING_INFO_AVAILABLE` event
|
|
1509
|
+
* @param {any} info
|
|
1510
|
+
* @param {string} [meetingLookupUrl] Lookup url, defined when the meeting info fetched
|
|
1511
|
+
* @returns {void}
|
|
1512
|
+
*/
|
|
1513
|
+
private setMeetingInfo(info, meetingLookupUrl) {
|
|
1514
|
+
this.meetingInfo = info ? {...info, meetingLookupUrl} : null;
|
|
1515
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NONE;
|
|
1516
|
+
|
|
1517
|
+
this.requiredCaptcha = null;
|
|
1518
|
+
if (
|
|
1519
|
+
this.passwordStatus === PASSWORD_STATUS.REQUIRED ||
|
|
1520
|
+
this.passwordStatus === PASSWORD_STATUS.VERIFIED
|
|
1521
|
+
) {
|
|
1522
|
+
this.passwordStatus = PASSWORD_STATUS.VERIFIED;
|
|
1523
|
+
} else {
|
|
1524
|
+
this.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
Trigger.trigger(
|
|
1528
|
+
this,
|
|
1529
|
+
{
|
|
1530
|
+
file: 'meetings',
|
|
1531
|
+
function: 'fetchMeetingInfo',
|
|
1532
|
+
},
|
|
1533
|
+
EVENT_TRIGGERS.MEETING_INFO_AVAILABLE
|
|
1534
|
+
);
|
|
1535
|
+
|
|
1536
|
+
this.updateMeetingActions();
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
/**
|
|
1540
|
+
* Add pre-fetched meeting info
|
|
1541
|
+
*
|
|
1542
|
+
* The passed meeting info should be be complete, e.g.: fetched after password or captcha provided
|
|
1543
|
+
*
|
|
1544
|
+
* @param {Object} meetingInfo - Complete meeting info
|
|
1545
|
+
* @param {FetchMeetingInfoParams} fetchParams - Fetch parameters for validation
|
|
1546
|
+
* @param {String|undefined} meetingLookupUrl - Lookup url, defined when the meeting info fetched
|
|
1547
|
+
* @returns {Promise<void>}
|
|
1548
|
+
*/
|
|
1549
|
+
public async injectMeetingInfo(
|
|
1550
|
+
meetingInfo: any,
|
|
1551
|
+
fetchParams: FetchMeetingInfoParams,
|
|
1552
|
+
meetingLookupUrl: string | undefined
|
|
1553
|
+
): Promise<void> {
|
|
1554
|
+
await this.prepForFetchMeetingInfo(fetchParams, 'injectMeetingInfo');
|
|
1555
|
+
|
|
1556
|
+
this.parseMeetingInfo(meetingInfo, this.destination);
|
|
1557
|
+
this.setMeetingInfo(meetingInfo, meetingLookupUrl);
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
/**
|
|
1561
|
+
* Validate fetch parameters and clear the fetchMeetingInfoTimeout timeout
|
|
1562
|
+
*
|
|
1563
|
+
* @param {FetchMeetingInfoParams} fetchParams - fetch parameters for validation
|
|
1564
|
+
* @param {String} caller - Name of the caller for logging
|
|
1565
|
+
*
|
|
1566
|
+
* @returns {Promise<void>}
|
|
1567
|
+
* @private
|
|
1568
|
+
*/
|
|
1569
|
+
private prepForFetchMeetingInfo(
|
|
1570
|
+
{password = null, captchaCode = null, extraParams = {}}: FetchMeetingInfoParams,
|
|
1571
|
+
caller: string
|
|
1572
|
+
): Promise<void> {
|
|
1573
|
+
// when fetch meeting info is called directly by the client, we want to clear out the random timer for sdk to do it
|
|
1574
|
+
if (this.fetchMeetingInfoTimeoutId) {
|
|
1575
|
+
clearTimeout(this.fetchMeetingInfoTimeoutId);
|
|
1576
|
+
this.fetchMeetingInfoTimeoutId = undefined;
|
|
1577
|
+
}
|
|
1578
|
+
if (captchaCode && !this.requiredCaptcha) {
|
|
1579
|
+
return Promise.reject(
|
|
1580
|
+
new Error(`${caller}() called with captchaCode when captcha was not required`)
|
|
1581
|
+
);
|
|
1582
|
+
}
|
|
1583
|
+
if (
|
|
1584
|
+
password &&
|
|
1585
|
+
this.passwordStatus !== PASSWORD_STATUS.REQUIRED &&
|
|
1586
|
+
this.passwordStatus !== PASSWORD_STATUS.UNKNOWN
|
|
1587
|
+
) {
|
|
1588
|
+
return Promise.reject(
|
|
1589
|
+
new Error(`${caller}() called with password when password was not required`)
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
this.meetingInfoExtraParams = cloneDeep(extraParams);
|
|
1594
|
+
|
|
1595
|
+
return Promise.resolve();
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1480
1598
|
/**
|
|
1481
1599
|
* Internal method for fetching meeting info
|
|
1482
1600
|
*
|
|
@@ -1507,29 +1625,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1507
1625
|
{meetingId: this.id, sendCAevents}
|
|
1508
1626
|
);
|
|
1509
1627
|
|
|
1510
|
-
this.parseMeetingInfo(info, this.destination);
|
|
1511
|
-
this.
|
|
1512
|
-
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NONE;
|
|
1513
|
-
this.requiredCaptcha = null;
|
|
1514
|
-
if (
|
|
1515
|
-
this.passwordStatus === PASSWORD_STATUS.REQUIRED ||
|
|
1516
|
-
this.passwordStatus === PASSWORD_STATUS.VERIFIED
|
|
1517
|
-
) {
|
|
1518
|
-
this.passwordStatus = PASSWORD_STATUS.VERIFIED;
|
|
1519
|
-
} else {
|
|
1520
|
-
this.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
Trigger.trigger(
|
|
1524
|
-
this,
|
|
1525
|
-
{
|
|
1526
|
-
file: 'meetings',
|
|
1527
|
-
function: 'fetchMeetingInfo',
|
|
1528
|
-
},
|
|
1529
|
-
EVENT_TRIGGERS.MEETING_INFO_AVAILABLE
|
|
1530
|
-
);
|
|
1531
|
-
|
|
1532
|
-
this.updateMeetingActions();
|
|
1628
|
+
this.parseMeetingInfo(info?.body, this.destination, info?.errors);
|
|
1629
|
+
this.setMeetingInfo(info?.body, info?.url);
|
|
1533
1630
|
|
|
1534
1631
|
return Promise.resolve();
|
|
1535
1632
|
} catch (err) {
|
|
@@ -1673,46 +1770,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1673
1770
|
* @memberof Meeting
|
|
1674
1771
|
* @returns {Promise}
|
|
1675
1772
|
*/
|
|
1676
|
-
public async fetchMeetingInfo({
|
|
1677
|
-
|
|
1678
|
-
captchaCode = null,
|
|
1679
|
-
extraParams = {},
|
|
1680
|
-
sendCAevents = false,
|
|
1681
|
-
}: {
|
|
1682
|
-
password?: string;
|
|
1683
|
-
captchaCode?: string;
|
|
1684
|
-
extraParams?: Record<string, any>;
|
|
1685
|
-
sendCAevents?: boolean;
|
|
1686
|
-
}) {
|
|
1687
|
-
// when fetch meeting info is called directly by the client, we want to clear out the random timer for sdk to do it
|
|
1688
|
-
if (this.fetchMeetingInfoTimeoutId) {
|
|
1689
|
-
clearTimeout(this.fetchMeetingInfoTimeoutId);
|
|
1690
|
-
this.fetchMeetingInfoTimeoutId = undefined;
|
|
1691
|
-
}
|
|
1692
|
-
if (captchaCode && !this.requiredCaptcha) {
|
|
1693
|
-
return Promise.reject(
|
|
1694
|
-
new Error('fetchMeetingInfo() called with captchaCode when captcha was not required')
|
|
1695
|
-
);
|
|
1696
|
-
}
|
|
1697
|
-
if (
|
|
1698
|
-
password &&
|
|
1699
|
-
this.passwordStatus !== PASSWORD_STATUS.REQUIRED &&
|
|
1700
|
-
this.passwordStatus !== PASSWORD_STATUS.UNKNOWN
|
|
1701
|
-
) {
|
|
1702
|
-
return Promise.reject(
|
|
1703
|
-
new Error('fetchMeetingInfo() called with password when password was not required')
|
|
1704
|
-
);
|
|
1705
|
-
}
|
|
1706
|
-
|
|
1707
|
-
this.meetingInfoExtraParams = cloneDeep(extraParams);
|
|
1773
|
+
public async fetchMeetingInfo(options: FetchMeetingInfoParams) {
|
|
1774
|
+
await this.prepForFetchMeetingInfo(options, 'fetchMeetingInfo');
|
|
1708
1775
|
|
|
1709
1776
|
return this.fetchMeetingInfoInternal({
|
|
1710
1777
|
destination: this.destination,
|
|
1711
1778
|
destinationType: this.destinationType,
|
|
1712
|
-
|
|
1713
|
-
captchaCode,
|
|
1714
|
-
extraParams,
|
|
1715
|
-
sendCAevents,
|
|
1779
|
+
...options,
|
|
1716
1780
|
});
|
|
1717
1781
|
}
|
|
1718
1782
|
|
|
@@ -2367,16 +2431,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2367
2431
|
}
|
|
2368
2432
|
);
|
|
2369
2433
|
|
|
2370
|
-
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_JOIN_BREAKOUT_FROM_MAIN, ({mainLocusUrl}) => {
|
|
2371
|
-
this.meetingRequest.getLocusStatusByUrl(mainLocusUrl).catch((error) => {
|
|
2372
|
-
// clear main session cache when attendee join into breakout and forbidden to get locus from main locus url,
|
|
2373
|
-
// which means main session is not active for the attendee
|
|
2374
|
-
if (error?.statusCode === 403) {
|
|
2375
|
-
this.locusInfo.clearMainSessionLocusCache();
|
|
2376
|
-
}
|
|
2377
|
-
});
|
|
2378
|
-
});
|
|
2379
|
-
|
|
2380
2434
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_ENTRY_EXIT_TONE_UPDATED, ({entryExitTone}) => {
|
|
2381
2435
|
Trigger.trigger(
|
|
2382
2436
|
this,
|
|
@@ -2611,6 +2665,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2611
2665
|
switch (newShareStatus) {
|
|
2612
2666
|
case SHARE_STATUS.REMOTE_SHARE_ACTIVE: {
|
|
2613
2667
|
const sendStartedSharingRemote = () => {
|
|
2668
|
+
this.remoteShareInstanceId = contentShare.shareInstanceId;
|
|
2669
|
+
|
|
2614
2670
|
Trigger.trigger(
|
|
2615
2671
|
this,
|
|
2616
2672
|
{
|
|
@@ -2621,7 +2677,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2621
2677
|
{
|
|
2622
2678
|
memberId: contentShare.beneficiaryId,
|
|
2623
2679
|
url: contentShare.url,
|
|
2624
|
-
shareInstanceId:
|
|
2680
|
+
shareInstanceId: this.remoteShareInstanceId,
|
|
2625
2681
|
annotationInfo: contentShare.annotation,
|
|
2626
2682
|
}
|
|
2627
2683
|
);
|
|
@@ -2658,6 +2714,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2658
2714
|
name: 'client.share.floor-granted.local',
|
|
2659
2715
|
payload: {
|
|
2660
2716
|
mediaType: 'share',
|
|
2717
|
+
shareInstanceId: this.localShareInstanceId,
|
|
2661
2718
|
},
|
|
2662
2719
|
options: {meetingId: this.id},
|
|
2663
2720
|
});
|
|
@@ -2700,6 +2757,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2700
2757
|
} else if (newShareStatus === SHARE_STATUS.REMOTE_SHARE_ACTIVE) {
|
|
2701
2758
|
// if we got here, then some remote participant has stolen
|
|
2702
2759
|
// the presentation from another remote participant
|
|
2760
|
+
this.remoteShareInstanceId = contentShare.shareInstanceId;
|
|
2761
|
+
|
|
2703
2762
|
Trigger.trigger(
|
|
2704
2763
|
this,
|
|
2705
2764
|
{
|
|
@@ -2710,7 +2769,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2710
2769
|
{
|
|
2711
2770
|
memberId: contentShare.beneficiaryId,
|
|
2712
2771
|
url: contentShare.url,
|
|
2713
|
-
shareInstanceId:
|
|
2772
|
+
shareInstanceId: this.remoteShareInstanceId,
|
|
2714
2773
|
annotationInfo: contentShare.annotation,
|
|
2715
2774
|
}
|
|
2716
2775
|
);
|
|
@@ -3328,30 +3387,40 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3328
3387
|
/**
|
|
3329
3388
|
* Sets the meeting info on the class instance
|
|
3330
3389
|
* @param {Object} meetingInfo
|
|
3331
|
-
* @param {
|
|
3332
|
-
* @param {String} meetingInfo.
|
|
3333
|
-
* @param {String} meetingInfo.
|
|
3334
|
-
* @param {String} meetingInfo.
|
|
3335
|
-
* @param {
|
|
3390
|
+
* @param {String} meetingInfo.conversationUrl
|
|
3391
|
+
* @param {String} meetingInfo.locusUrl
|
|
3392
|
+
* @param {String} meetingInfo.sipUri
|
|
3393
|
+
* @param {String} [meetingInfo.sipUrl]
|
|
3394
|
+
* @param {String} [meetingInfo.sipMeetingUri]
|
|
3395
|
+
* @param {String} [meetingInfo.meetingNumber]
|
|
3396
|
+
* @param {String} [meetingInfo.meetingJoinUrl]
|
|
3397
|
+
* @param {String} [meetingInfo.hostId]
|
|
3398
|
+
* @param {String} [meetingInfo.permissionToken]
|
|
3399
|
+
* @param {String} [meetingInfo.channel]
|
|
3400
|
+
* @param {Object} meetingInfo.owner
|
|
3336
3401
|
* @param {Object | String} destination locus object with meeting data or destination string (sip url, meeting link, etc)
|
|
3402
|
+
* @param {Object | String} errors Meeting info request error
|
|
3337
3403
|
* @returns {undefined}
|
|
3338
3404
|
* @private
|
|
3339
3405
|
* @memberof Meeting
|
|
3340
3406
|
*/
|
|
3341
3407
|
parseMeetingInfo(
|
|
3342
|
-
meetingInfo:
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3408
|
+
meetingInfo: {
|
|
3409
|
+
conversationUrl: string;
|
|
3410
|
+
locusUrl: string;
|
|
3411
|
+
sipUri: string;
|
|
3412
|
+
owner: object;
|
|
3413
|
+
sipUrl?: string;
|
|
3414
|
+
sipMeetingUri?: string;
|
|
3415
|
+
meetingNumber?: string;
|
|
3416
|
+
meetingJoinUrl?: string;
|
|
3417
|
+
hostId?: string;
|
|
3418
|
+
permissionToken?: string;
|
|
3419
|
+
channel?: string;
|
|
3420
|
+
},
|
|
3421
|
+
destination: object | string | null = null,
|
|
3422
|
+
errors: any = undefined
|
|
3353
3423
|
) {
|
|
3354
|
-
const webexMeetingInfo = meetingInfo?.body;
|
|
3355
3424
|
// We try to use as much info from Locus meeting object, stored in destination
|
|
3356
3425
|
|
|
3357
3426
|
let locusMeetingObject;
|
|
@@ -3361,40 +3430,31 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3361
3430
|
}
|
|
3362
3431
|
|
|
3363
3432
|
// MeetingInfo will be undefined for 1:1 calls
|
|
3364
|
-
if (
|
|
3365
|
-
locusMeetingObject ||
|
|
3366
|
-
(webexMeetingInfo && !(meetingInfo?.errors && meetingInfo?.errors.length > 0))
|
|
3367
|
-
) {
|
|
3433
|
+
if (locusMeetingObject || (meetingInfo && !(errors?.length > 0))) {
|
|
3368
3434
|
this.conversationUrl =
|
|
3369
|
-
locusMeetingObject?.conversationUrl ||
|
|
3370
|
-
|
|
3371
|
-
this.conversationUrl;
|
|
3372
|
-
this.locusUrl = locusMeetingObject?.url || webexMeetingInfo?.locusUrl || this.locusUrl;
|
|
3435
|
+
locusMeetingObject?.conversationUrl || meetingInfo?.conversationUrl || this.conversationUrl;
|
|
3436
|
+
this.locusUrl = locusMeetingObject?.url || meetingInfo?.locusUrl || this.locusUrl;
|
|
3373
3437
|
// @ts-ignore - config coming from registerPlugin
|
|
3374
3438
|
this.setSipUri(
|
|
3375
3439
|
// @ts-ignore
|
|
3376
3440
|
this.config.experimental.enableUnifiedMeetings
|
|
3377
|
-
? locusMeetingObject?.info.sipUri ||
|
|
3378
|
-
: locusMeetingObject?.info.sipUri ||
|
|
3441
|
+
? locusMeetingObject?.info.sipUri || meetingInfo?.sipUrl
|
|
3442
|
+
: locusMeetingObject?.info.sipUri || meetingInfo?.sipMeetingUri || this.sipUri
|
|
3379
3443
|
);
|
|
3380
3444
|
// @ts-ignore - config coming from registerPlugin
|
|
3381
3445
|
if (this.config.experimental.enableUnifiedMeetings) {
|
|
3382
|
-
this.meetingNumber =
|
|
3383
|
-
|
|
3384
|
-
this.meetingJoinUrl = webexMeetingInfo?.meetingJoinUrl;
|
|
3446
|
+
this.meetingNumber = locusMeetingObject?.info.webExMeetingId || meetingInfo?.meetingNumber;
|
|
3447
|
+
this.meetingJoinUrl = meetingInfo?.meetingJoinUrl;
|
|
3385
3448
|
}
|
|
3386
3449
|
this.owner =
|
|
3387
|
-
locusMeetingObject?.info.owner ||
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
this.owner;
|
|
3391
|
-
this.permissionToken = webexMeetingInfo?.permissionToken;
|
|
3392
|
-
this.setPermissionTokenPayload(webexMeetingInfo?.permissionToken);
|
|
3450
|
+
locusMeetingObject?.info.owner || meetingInfo?.owner || meetingInfo?.hostId || this.owner;
|
|
3451
|
+
this.permissionToken = meetingInfo?.permissionToken;
|
|
3452
|
+
this.setPermissionTokenPayload(meetingInfo?.permissionToken);
|
|
3393
3453
|
this.setSelfUserPolicies();
|
|
3394
3454
|
// Need to populate environment when sending CA event
|
|
3395
|
-
this.environment = locusMeetingObject?.info.channel ||
|
|
3455
|
+
this.environment = locusMeetingObject?.info.channel || meetingInfo?.channel;
|
|
3396
3456
|
}
|
|
3397
|
-
MeetingUtil.parseInterpretationInfo(this,
|
|
3457
|
+
MeetingUtil.parseInterpretationInfo(this, meetingInfo);
|
|
3398
3458
|
}
|
|
3399
3459
|
|
|
3400
3460
|
/**
|
|
@@ -5534,7 +5594,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5534
5594
|
seq: event.roapMessage.seq,
|
|
5535
5595
|
tieBreaker: event.roapMessage.tieBreaker,
|
|
5536
5596
|
meeting: this, // or can pass meeting ID
|
|
5537
|
-
reconnect: this.reconnectionManager.isReconnectInProgress(),
|
|
5538
5597
|
})
|
|
5539
5598
|
.then(({roapAnswer}) => {
|
|
5540
5599
|
if (roapAnswer) {
|
|
@@ -5851,7 +5910,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5851
5910
|
// @ts-ignore
|
|
5852
5911
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
5853
5912
|
name: 'client.media.tx.start',
|
|
5854
|
-
payload: {
|
|
5913
|
+
payload: {
|
|
5914
|
+
mediaType: data.type,
|
|
5915
|
+
shareInstanceId: data.type === 'share' ? this.localShareInstanceId : undefined,
|
|
5916
|
+
},
|
|
5855
5917
|
options: {
|
|
5856
5918
|
meetingId: this.id,
|
|
5857
5919
|
},
|
|
@@ -5861,7 +5923,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5861
5923
|
// @ts-ignore
|
|
5862
5924
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
5863
5925
|
name: 'client.media.tx.stop',
|
|
5864
|
-
payload: {
|
|
5926
|
+
payload: {
|
|
5927
|
+
mediaType: data.type,
|
|
5928
|
+
shareInstanceId: data.type === 'share' ? this.localShareInstanceId : undefined,
|
|
5929
|
+
},
|
|
5865
5930
|
options: {
|
|
5866
5931
|
meetingId: this.id,
|
|
5867
5932
|
},
|
|
@@ -5880,7 +5945,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5880
5945
|
// @ts-ignore
|
|
5881
5946
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
5882
5947
|
name: 'client.media.rx.start',
|
|
5883
|
-
payload: {
|
|
5948
|
+
payload: {
|
|
5949
|
+
mediaType: data.type,
|
|
5950
|
+
shareInstanceId: data.type === 'share' ? this.remoteShareInstanceId : undefined,
|
|
5951
|
+
},
|
|
5884
5952
|
options: {
|
|
5885
5953
|
meetingId: this.id,
|
|
5886
5954
|
},
|
|
@@ -5890,7 +5958,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5890
5958
|
// @ts-ignore
|
|
5891
5959
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
5892
5960
|
name: 'client.media.rx.stop',
|
|
5893
|
-
payload: {
|
|
5961
|
+
payload: {
|
|
5962
|
+
mediaType: data.type,
|
|
5963
|
+
shareInstanceId: data.type === 'share' ? this.remoteShareInstanceId : undefined,
|
|
5964
|
+
},
|
|
5894
5965
|
options: {
|
|
5895
5966
|
meetingId: this.id,
|
|
5896
5967
|
},
|
|
@@ -7136,11 +7207,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7136
7207
|
if (content && this.shareStatus !== SHARE_STATUS.LOCAL_SHARE_ACTIVE) {
|
|
7137
7208
|
// @ts-ignore
|
|
7138
7209
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
7139
|
-
name: 'client.share.
|
|
7210
|
+
name: 'client.share.floor-grant.request',
|
|
7140
7211
|
payload: {
|
|
7141
7212
|
mediaType: 'share',
|
|
7213
|
+
shareInstanceId: this.localShareInstanceId,
|
|
7214
|
+
},
|
|
7215
|
+
options: {
|
|
7216
|
+
meetingId: this.id,
|
|
7142
7217
|
},
|
|
7143
|
-
options: {meetingId: this.id},
|
|
7144
7218
|
});
|
|
7145
7219
|
|
|
7146
7220
|
return this.meetingRequest
|
|
@@ -7171,6 +7245,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7171
7245
|
stack: error.stack,
|
|
7172
7246
|
});
|
|
7173
7247
|
|
|
7248
|
+
// @ts-ignore
|
|
7249
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
7250
|
+
name: 'client.share.floor-granted.local',
|
|
7251
|
+
payload: {
|
|
7252
|
+
mediaType: 'share',
|
|
7253
|
+
errors: MeetingUtil.getChangeMeetingFloorErrorPayload(error.message),
|
|
7254
|
+
shareInstanceId: this.localShareInstanceId,
|
|
7255
|
+
},
|
|
7256
|
+
options: {
|
|
7257
|
+
meetingId: this.id,
|
|
7258
|
+
},
|
|
7259
|
+
});
|
|
7260
|
+
|
|
7174
7261
|
this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
|
|
7175
7262
|
|
|
7176
7263
|
return Promise.reject(error);
|
|
@@ -7222,6 +7309,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7222
7309
|
name: 'client.share.stopped',
|
|
7223
7310
|
payload: {
|
|
7224
7311
|
mediaType: 'share',
|
|
7312
|
+
shareInstanceId: this.localShareInstanceId,
|
|
7225
7313
|
},
|
|
7226
7314
|
options: {meetingId: this.id},
|
|
7227
7315
|
});
|
|
@@ -8104,6 +8192,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8104
8192
|
}
|
|
8105
8193
|
|
|
8106
8194
|
if (floorRequestNeeded) {
|
|
8195
|
+
this.localShareInstanceId = uuid.v4();
|
|
8196
|
+
|
|
8197
|
+
// @ts-ignore
|
|
8198
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
8199
|
+
name: 'client.share.initiated',
|
|
8200
|
+
payload: {
|
|
8201
|
+
mediaType: 'share',
|
|
8202
|
+
shareInstanceId: this.localShareInstanceId,
|
|
8203
|
+
},
|
|
8204
|
+
options: {meetingId: this.id},
|
|
8205
|
+
});
|
|
8107
8206
|
// we're sending the http request to Locus to request the screen share floor
|
|
8108
8207
|
// only after the SDP update, because that's how it's always been done for transcoded meetings
|
|
8109
8208
|
// and also if sharing from the start, we need confluence to have been created
|
package/src/meeting/request.ts
CHANGED
|
@@ -185,6 +185,13 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
185
185
|
deviceCapabilities.push(ANNOTATION.ANNOTATION_ON_SHARE_SUPPORTED);
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// append installationId to device config if it exists
|
|
189
|
+
// @ts-ignore
|
|
190
|
+
if (this.webex.internal.device.config.installationId) {
|
|
191
|
+
// @ts-ignore
|
|
192
|
+
body.device.installationId = this.webex.internal.device.config.installationId;
|
|
193
|
+
}
|
|
194
|
+
|
|
188
195
|
if (locale) {
|
|
189
196
|
body.locale = locale;
|
|
190
197
|
}
|
package/src/meeting/util.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
FULL_STATE,
|
|
14
14
|
SELF_POLICY,
|
|
15
15
|
EVENT_TRIGGERS,
|
|
16
|
+
LOCAL_SHARE_ERRORS,
|
|
16
17
|
IP_VERSION,
|
|
17
18
|
} from '../constants';
|
|
18
19
|
import BrowserDetection from '../common/browser-detection';
|
|
@@ -692,6 +693,102 @@ const MeetingUtil = {
|
|
|
692
693
|
EVENT_TRIGGERS.MEETING_INTERPRETATION_UPDATE
|
|
693
694
|
);
|
|
694
695
|
},
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Returns a CA-recognized error payload for the specified raw error message/reason.
|
|
699
|
+
*
|
|
700
|
+
* New errors can be added to this function for handling in the future
|
|
701
|
+
*
|
|
702
|
+
* @param {String} reason the raw error message
|
|
703
|
+
* @returns {Array<object>} an array of payload objects
|
|
704
|
+
*/
|
|
705
|
+
getChangeMeetingFloorErrorPayload: (reason: string) => {
|
|
706
|
+
const errorPayload = {
|
|
707
|
+
errorDescription: reason,
|
|
708
|
+
name: 'locus.response',
|
|
709
|
+
shownToUser: false,
|
|
710
|
+
};
|
|
711
|
+
if (reason.includes(LOCAL_SHARE_ERRORS.UNDEFINED)) {
|
|
712
|
+
return [
|
|
713
|
+
{
|
|
714
|
+
...errorPayload,
|
|
715
|
+
fatal: true,
|
|
716
|
+
category: 'signaling',
|
|
717
|
+
errorCode: 1100,
|
|
718
|
+
},
|
|
719
|
+
];
|
|
720
|
+
}
|
|
721
|
+
if (reason.includes(LOCAL_SHARE_ERRORS.DEVICE_NOT_JOINED)) {
|
|
722
|
+
return [
|
|
723
|
+
{
|
|
724
|
+
...errorPayload,
|
|
725
|
+
fatal: true,
|
|
726
|
+
category: 'signaling',
|
|
727
|
+
errorCode: 4050,
|
|
728
|
+
},
|
|
729
|
+
];
|
|
730
|
+
}
|
|
731
|
+
if (reason.includes(LOCAL_SHARE_ERRORS.NO_MEDIA_FOR_DEVICE)) {
|
|
732
|
+
return [
|
|
733
|
+
{
|
|
734
|
+
...errorPayload,
|
|
735
|
+
fatal: true,
|
|
736
|
+
category: 'media',
|
|
737
|
+
errorCode: 2048,
|
|
738
|
+
},
|
|
739
|
+
];
|
|
740
|
+
}
|
|
741
|
+
if (reason.includes(LOCAL_SHARE_ERRORS.NO_CONFLUENCE_ID)) {
|
|
742
|
+
return [
|
|
743
|
+
{
|
|
744
|
+
...errorPayload,
|
|
745
|
+
fatal: true,
|
|
746
|
+
category: 'signaling',
|
|
747
|
+
errorCode: 4064,
|
|
748
|
+
},
|
|
749
|
+
];
|
|
750
|
+
}
|
|
751
|
+
if (reason.includes(LOCAL_SHARE_ERRORS.CONTENT_SHARING_DISABLED)) {
|
|
752
|
+
return [
|
|
753
|
+
{
|
|
754
|
+
...errorPayload,
|
|
755
|
+
fatal: true,
|
|
756
|
+
category: 'expected',
|
|
757
|
+
errorCode: 4065,
|
|
758
|
+
},
|
|
759
|
+
];
|
|
760
|
+
}
|
|
761
|
+
if (reason.includes(LOCAL_SHARE_ERRORS.LOCUS_PARTICIPANT_DNE)) {
|
|
762
|
+
return [
|
|
763
|
+
{
|
|
764
|
+
...errorPayload,
|
|
765
|
+
fatal: true,
|
|
766
|
+
category: 'signaling',
|
|
767
|
+
errorCode: 4066,
|
|
768
|
+
},
|
|
769
|
+
];
|
|
770
|
+
}
|
|
771
|
+
if (reason.includes(LOCAL_SHARE_ERRORS.CONTENT_REQUEST_WHILE_PENDING_WHITEBOARD)) {
|
|
772
|
+
return [
|
|
773
|
+
{
|
|
774
|
+
...errorPayload,
|
|
775
|
+
fatal: true,
|
|
776
|
+
category: 'expected',
|
|
777
|
+
errorCode: 4067,
|
|
778
|
+
},
|
|
779
|
+
];
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// return unknown error
|
|
783
|
+
return [
|
|
784
|
+
{
|
|
785
|
+
...errorPayload,
|
|
786
|
+
fatal: true,
|
|
787
|
+
category: 'signaling',
|
|
788
|
+
errorCode: 1100,
|
|
789
|
+
},
|
|
790
|
+
];
|
|
791
|
+
},
|
|
695
792
|
};
|
|
696
793
|
|
|
697
794
|
export default MeetingUtil;
|