@webex/plugin-meetings 2.60.1-next.6 → 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 +14 -2
- package/dist/constants.js +18 -6
- 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 +63 -19
- package/dist/meeting/index.js +703 -579
- 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 +15 -2
- package/src/locus-info/index.ts +13 -12
- package/src/meeting/index.ts +256 -130
- 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
|
|
|
@@ -1965,6 +2029,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1965
2029
|
* @memberof Meeting
|
|
1966
2030
|
*/
|
|
1967
2031
|
private setUpVoiceaListeners() {
|
|
2032
|
+
// @ts-ignore
|
|
2033
|
+
this.webex.internal.voicea.listenToEvents();
|
|
2034
|
+
|
|
1968
2035
|
// @ts-ignore
|
|
1969
2036
|
this.webex.internal.voicea.on(
|
|
1970
2037
|
VOICEAEVENTS.VOICEA_ANNOUNCEMENT,
|
|
@@ -1994,6 +2061,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1994
2061
|
VOICEAEVENTS.HIGHLIGHT_CREATED,
|
|
1995
2062
|
this.voiceaListenerCallbacks[VOICEAEVENTS.HIGHLIGHT_CREATED]
|
|
1996
2063
|
);
|
|
2064
|
+
|
|
2065
|
+
this.areVoiceaEventsSetup = true;
|
|
1997
2066
|
}
|
|
1998
2067
|
|
|
1999
2068
|
/**
|
|
@@ -2362,16 +2431,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2362
2431
|
}
|
|
2363
2432
|
);
|
|
2364
2433
|
|
|
2365
|
-
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_JOIN_BREAKOUT_FROM_MAIN, ({mainLocusUrl}) => {
|
|
2366
|
-
this.meetingRequest.getLocusStatusByUrl(mainLocusUrl).catch((error) => {
|
|
2367
|
-
// clear main session cache when attendee join into breakout and forbidden to get locus from main locus url,
|
|
2368
|
-
// which means main session is not active for the attendee
|
|
2369
|
-
if (error?.statusCode === 403) {
|
|
2370
|
-
this.locusInfo.clearMainSessionLocusCache();
|
|
2371
|
-
}
|
|
2372
|
-
});
|
|
2373
|
-
});
|
|
2374
|
-
|
|
2375
2434
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_ENTRY_EXIT_TONE_UPDATED, ({entryExitTone}) => {
|
|
2376
2435
|
Trigger.trigger(
|
|
2377
2436
|
this,
|
|
@@ -2606,6 +2665,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2606
2665
|
switch (newShareStatus) {
|
|
2607
2666
|
case SHARE_STATUS.REMOTE_SHARE_ACTIVE: {
|
|
2608
2667
|
const sendStartedSharingRemote = () => {
|
|
2668
|
+
this.remoteShareInstanceId = contentShare.shareInstanceId;
|
|
2669
|
+
|
|
2609
2670
|
Trigger.trigger(
|
|
2610
2671
|
this,
|
|
2611
2672
|
{
|
|
@@ -2616,7 +2677,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2616
2677
|
{
|
|
2617
2678
|
memberId: contentShare.beneficiaryId,
|
|
2618
2679
|
url: contentShare.url,
|
|
2619
|
-
shareInstanceId:
|
|
2680
|
+
shareInstanceId: this.remoteShareInstanceId,
|
|
2620
2681
|
annotationInfo: contentShare.annotation,
|
|
2621
2682
|
}
|
|
2622
2683
|
);
|
|
@@ -2653,6 +2714,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2653
2714
|
name: 'client.share.floor-granted.local',
|
|
2654
2715
|
payload: {
|
|
2655
2716
|
mediaType: 'share',
|
|
2717
|
+
shareInstanceId: this.localShareInstanceId,
|
|
2656
2718
|
},
|
|
2657
2719
|
options: {meetingId: this.id},
|
|
2658
2720
|
});
|
|
@@ -2695,6 +2757,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2695
2757
|
} else if (newShareStatus === SHARE_STATUS.REMOTE_SHARE_ACTIVE) {
|
|
2696
2758
|
// if we got here, then some remote participant has stolen
|
|
2697
2759
|
// the presentation from another remote participant
|
|
2760
|
+
this.remoteShareInstanceId = contentShare.shareInstanceId;
|
|
2761
|
+
|
|
2698
2762
|
Trigger.trigger(
|
|
2699
2763
|
this,
|
|
2700
2764
|
{
|
|
@@ -2705,7 +2769,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2705
2769
|
{
|
|
2706
2770
|
memberId: contentShare.beneficiaryId,
|
|
2707
2771
|
url: contentShare.url,
|
|
2708
|
-
shareInstanceId:
|
|
2772
|
+
shareInstanceId: this.remoteShareInstanceId,
|
|
2709
2773
|
annotationInfo: contentShare.annotation,
|
|
2710
2774
|
}
|
|
2711
2775
|
);
|
|
@@ -3323,30 +3387,40 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3323
3387
|
/**
|
|
3324
3388
|
* Sets the meeting info on the class instance
|
|
3325
3389
|
* @param {Object} meetingInfo
|
|
3326
|
-
* @param {
|
|
3327
|
-
* @param {String} meetingInfo.
|
|
3328
|
-
* @param {String} meetingInfo.
|
|
3329
|
-
* @param {String} meetingInfo.
|
|
3330
|
-
* @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
|
|
3331
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
|
|
3332
3403
|
* @returns {undefined}
|
|
3333
3404
|
* @private
|
|
3334
3405
|
* @memberof Meeting
|
|
3335
3406
|
*/
|
|
3336
3407
|
parseMeetingInfo(
|
|
3337
|
-
meetingInfo:
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
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
|
|
3348
3423
|
) {
|
|
3349
|
-
const webexMeetingInfo = meetingInfo?.body;
|
|
3350
3424
|
// We try to use as much info from Locus meeting object, stored in destination
|
|
3351
3425
|
|
|
3352
3426
|
let locusMeetingObject;
|
|
@@ -3356,40 +3430,31 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3356
3430
|
}
|
|
3357
3431
|
|
|
3358
3432
|
// MeetingInfo will be undefined for 1:1 calls
|
|
3359
|
-
if (
|
|
3360
|
-
locusMeetingObject ||
|
|
3361
|
-
(webexMeetingInfo && !(meetingInfo?.errors && meetingInfo?.errors.length > 0))
|
|
3362
|
-
) {
|
|
3433
|
+
if (locusMeetingObject || (meetingInfo && !(errors?.length > 0))) {
|
|
3363
3434
|
this.conversationUrl =
|
|
3364
|
-
locusMeetingObject?.conversationUrl ||
|
|
3365
|
-
|
|
3366
|
-
this.conversationUrl;
|
|
3367
|
-
this.locusUrl = locusMeetingObject?.url || webexMeetingInfo?.locusUrl || this.locusUrl;
|
|
3435
|
+
locusMeetingObject?.conversationUrl || meetingInfo?.conversationUrl || this.conversationUrl;
|
|
3436
|
+
this.locusUrl = locusMeetingObject?.url || meetingInfo?.locusUrl || this.locusUrl;
|
|
3368
3437
|
// @ts-ignore - config coming from registerPlugin
|
|
3369
3438
|
this.setSipUri(
|
|
3370
3439
|
// @ts-ignore
|
|
3371
3440
|
this.config.experimental.enableUnifiedMeetings
|
|
3372
|
-
? locusMeetingObject?.info.sipUri ||
|
|
3373
|
-
: locusMeetingObject?.info.sipUri ||
|
|
3441
|
+
? locusMeetingObject?.info.sipUri || meetingInfo?.sipUrl
|
|
3442
|
+
: locusMeetingObject?.info.sipUri || meetingInfo?.sipMeetingUri || this.sipUri
|
|
3374
3443
|
);
|
|
3375
3444
|
// @ts-ignore - config coming from registerPlugin
|
|
3376
3445
|
if (this.config.experimental.enableUnifiedMeetings) {
|
|
3377
|
-
this.meetingNumber =
|
|
3378
|
-
|
|
3379
|
-
this.meetingJoinUrl = webexMeetingInfo?.meetingJoinUrl;
|
|
3446
|
+
this.meetingNumber = locusMeetingObject?.info.webExMeetingId || meetingInfo?.meetingNumber;
|
|
3447
|
+
this.meetingJoinUrl = meetingInfo?.meetingJoinUrl;
|
|
3380
3448
|
}
|
|
3381
3449
|
this.owner =
|
|
3382
|
-
locusMeetingObject?.info.owner ||
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
this.owner;
|
|
3386
|
-
this.permissionToken = webexMeetingInfo?.permissionToken;
|
|
3387
|
-
this.setPermissionTokenPayload(webexMeetingInfo?.permissionToken);
|
|
3450
|
+
locusMeetingObject?.info.owner || meetingInfo?.owner || meetingInfo?.hostId || this.owner;
|
|
3451
|
+
this.permissionToken = meetingInfo?.permissionToken;
|
|
3452
|
+
this.setPermissionTokenPayload(meetingInfo?.permissionToken);
|
|
3388
3453
|
this.setSelfUserPolicies();
|
|
3389
3454
|
// Need to populate environment when sending CA event
|
|
3390
|
-
this.environment = locusMeetingObject?.info.channel ||
|
|
3455
|
+
this.environment = locusMeetingObject?.info.channel || meetingInfo?.channel;
|
|
3391
3456
|
}
|
|
3392
|
-
MeetingUtil.parseInterpretationInfo(this,
|
|
3457
|
+
MeetingUtil.parseInterpretationInfo(this, meetingInfo);
|
|
3393
3458
|
}
|
|
3394
3459
|
|
|
3395
3460
|
/**
|
|
@@ -4587,13 +4652,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4587
4652
|
const {statusCode} = payload;
|
|
4588
4653
|
|
|
4589
4654
|
if (statusCode === 200) {
|
|
4590
|
-
const currentCaptionLanguage =
|
|
4591
|
-
this.transcription.languageOptions.requestedCaptionLanguage ?? LANGUAGE_ENGLISH;
|
|
4592
4655
|
this.transcription.languageOptions = {
|
|
4593
4656
|
...this.transcription.languageOptions,
|
|
4594
|
-
currentCaptionLanguage,
|
|
4657
|
+
currentCaptionLanguage: language,
|
|
4595
4658
|
};
|
|
4596
|
-
resolve(
|
|
4659
|
+
resolve(language);
|
|
4597
4660
|
} else {
|
|
4598
4661
|
reject(payload);
|
|
4599
4662
|
}
|
|
@@ -4677,10 +4740,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4677
4740
|
try {
|
|
4678
4741
|
if (!this.areVoiceaEventsSetup) {
|
|
4679
4742
|
this.setUpVoiceaListeners();
|
|
4680
|
-
this.areVoiceaEventsSetup = true;
|
|
4681
4743
|
}
|
|
4682
|
-
|
|
4683
|
-
|
|
4744
|
+
|
|
4745
|
+
if (this.getCurUserType() === 'host') {
|
|
4746
|
+
// @ts-ignore
|
|
4747
|
+
await this.webex.internal.voicea.toggleTranscribing(true, options?.spokenLanguage);
|
|
4748
|
+
}
|
|
4684
4749
|
} catch (error) {
|
|
4685
4750
|
LoggerProxy.logger.error(`Meeting:index#startTranscription --> ${error}`);
|
|
4686
4751
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_FAILURE, {
|
|
@@ -4769,6 +4834,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4769
4834
|
VOICEAEVENTS.HIGHLIGHT_CREATED,
|
|
4770
4835
|
this.voiceaListenerCallbacks[VOICEAEVENTS.HIGHLIGHT_CREATED]
|
|
4771
4836
|
);
|
|
4837
|
+
|
|
4772
4838
|
this.areVoiceaEventsSetup = false;
|
|
4773
4839
|
this.triggerStopReceivingTranscriptionEvent();
|
|
4774
4840
|
}
|
|
@@ -5014,15 +5080,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5014
5080
|
.then((join) => {
|
|
5015
5081
|
// @ts-ignore - config coming from registerPlugin
|
|
5016
5082
|
if (this.config.enableAutomaticLLM) {
|
|
5017
|
-
this.updateLLMConnection()
|
|
5018
|
-
|
|
5083
|
+
this.updateLLMConnection()
|
|
5084
|
+
.catch((error) => {
|
|
5085
|
+
LoggerProxy.logger.error(
|
|
5086
|
+
'Meeting:index#join --> Transcription Socket Connection Failed',
|
|
5087
|
+
error
|
|
5088
|
+
);
|
|
5019
5089
|
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5090
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.LLM_CONNECTION_AFTER_JOIN_FAILURE, {
|
|
5091
|
+
correlation_id: this.correlationId,
|
|
5092
|
+
reason: error?.message,
|
|
5093
|
+
stack: error.stack,
|
|
5094
|
+
});
|
|
5095
|
+
})
|
|
5096
|
+
.then(() => {
|
|
5097
|
+
LoggerProxy.logger.info(
|
|
5098
|
+
'Meeting:index#join --> Transcription Socket Connection Success'
|
|
5099
|
+
);
|
|
5100
|
+
Trigger.trigger(
|
|
5101
|
+
this,
|
|
5102
|
+
{
|
|
5103
|
+
file: 'meeting/index',
|
|
5104
|
+
function: 'join',
|
|
5105
|
+
},
|
|
5106
|
+
EVENT_TRIGGERS.MEETING_TRANSCRIPTION_CONNECTED,
|
|
5107
|
+
undefined
|
|
5108
|
+
);
|
|
5024
5109
|
});
|
|
5025
|
-
});
|
|
5026
5110
|
}
|
|
5027
5111
|
|
|
5028
5112
|
return join;
|
|
@@ -5510,7 +5594,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5510
5594
|
seq: event.roapMessage.seq,
|
|
5511
5595
|
tieBreaker: event.roapMessage.tieBreaker,
|
|
5512
5596
|
meeting: this, // or can pass meeting ID
|
|
5513
|
-
reconnect: this.reconnectionManager.isReconnectInProgress(),
|
|
5514
5597
|
})
|
|
5515
5598
|
.then(({roapAnswer}) => {
|
|
5516
5599
|
if (roapAnswer) {
|
|
@@ -5827,7 +5910,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5827
5910
|
// @ts-ignore
|
|
5828
5911
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
5829
5912
|
name: 'client.media.tx.start',
|
|
5830
|
-
payload: {
|
|
5913
|
+
payload: {
|
|
5914
|
+
mediaType: data.type,
|
|
5915
|
+
shareInstanceId: data.type === 'share' ? this.localShareInstanceId : undefined,
|
|
5916
|
+
},
|
|
5831
5917
|
options: {
|
|
5832
5918
|
meetingId: this.id,
|
|
5833
5919
|
},
|
|
@@ -5837,7 +5923,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5837
5923
|
// @ts-ignore
|
|
5838
5924
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
5839
5925
|
name: 'client.media.tx.stop',
|
|
5840
|
-
payload: {
|
|
5926
|
+
payload: {
|
|
5927
|
+
mediaType: data.type,
|
|
5928
|
+
shareInstanceId: data.type === 'share' ? this.localShareInstanceId : undefined,
|
|
5929
|
+
},
|
|
5841
5930
|
options: {
|
|
5842
5931
|
meetingId: this.id,
|
|
5843
5932
|
},
|
|
@@ -5856,7 +5945,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5856
5945
|
// @ts-ignore
|
|
5857
5946
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
5858
5947
|
name: 'client.media.rx.start',
|
|
5859
|
-
payload: {
|
|
5948
|
+
payload: {
|
|
5949
|
+
mediaType: data.type,
|
|
5950
|
+
shareInstanceId: data.type === 'share' ? this.remoteShareInstanceId : undefined,
|
|
5951
|
+
},
|
|
5860
5952
|
options: {
|
|
5861
5953
|
meetingId: this.id,
|
|
5862
5954
|
},
|
|
@@ -5866,7 +5958,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5866
5958
|
// @ts-ignore
|
|
5867
5959
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
5868
5960
|
name: 'client.media.rx.stop',
|
|
5869
|
-
payload: {
|
|
5961
|
+
payload: {
|
|
5962
|
+
mediaType: data.type,
|
|
5963
|
+
shareInstanceId: data.type === 'share' ? this.remoteShareInstanceId : undefined,
|
|
5964
|
+
},
|
|
5870
5965
|
options: {
|
|
5871
5966
|
meetingId: this.id,
|
|
5872
5967
|
},
|
|
@@ -7112,11 +7207,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7112
7207
|
if (content && this.shareStatus !== SHARE_STATUS.LOCAL_SHARE_ACTIVE) {
|
|
7113
7208
|
// @ts-ignore
|
|
7114
7209
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
7115
|
-
name: 'client.share.
|
|
7210
|
+
name: 'client.share.floor-grant.request',
|
|
7116
7211
|
payload: {
|
|
7117
7212
|
mediaType: 'share',
|
|
7213
|
+
shareInstanceId: this.localShareInstanceId,
|
|
7214
|
+
},
|
|
7215
|
+
options: {
|
|
7216
|
+
meetingId: this.id,
|
|
7118
7217
|
},
|
|
7119
|
-
options: {meetingId: this.id},
|
|
7120
7218
|
});
|
|
7121
7219
|
|
|
7122
7220
|
return this.meetingRequest
|
|
@@ -7147,6 +7245,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7147
7245
|
stack: error.stack,
|
|
7148
7246
|
});
|
|
7149
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
|
+
|
|
7150
7261
|
this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
|
|
7151
7262
|
|
|
7152
7263
|
return Promise.reject(error);
|
|
@@ -7198,6 +7309,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7198
7309
|
name: 'client.share.stopped',
|
|
7199
7310
|
payload: {
|
|
7200
7311
|
mediaType: 'share',
|
|
7312
|
+
shareInstanceId: this.localShareInstanceId,
|
|
7201
7313
|
},
|
|
7202
7314
|
options: {meetingId: this.id},
|
|
7203
7315
|
});
|
|
@@ -7673,6 +7785,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7673
7785
|
if (roles.includes(SELF_ROLES.COHOST)) {
|
|
7674
7786
|
return 'cohost';
|
|
7675
7787
|
}
|
|
7788
|
+
if (roles.includes(SELF_ROLES.PRESENTER)) {
|
|
7789
|
+
return 'presenter';
|
|
7790
|
+
}
|
|
7676
7791
|
if (roles.includes(SELF_ROLES.ATTENDEE)) {
|
|
7677
7792
|
return 'attendee';
|
|
7678
7793
|
}
|
|
@@ -8077,6 +8192,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8077
8192
|
}
|
|
8078
8193
|
|
|
8079
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
|
+
});
|
|
8080
8206
|
// we're sending the http request to Locus to request the screen share floor
|
|
8081
8207
|
// only after the SDP update, because that's how it's always been done for transcoded meetings
|
|
8082
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
|
}
|