@webex/plugin-meetings 2.60.0-next.2 → 2.60.0-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/parser.js +5 -5
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/media/index.js +6 -5
- package/dist/media/index.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +2 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +121 -47
- package/dist/meeting/index.js.map +1 -1
- package/dist/meetings/index.js +17 -9
- package/dist/meetings/index.js.map +1 -1
- package/dist/metrics/constants.js +2 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/reconnection-manager/index.js +1 -2
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +21 -21
- package/src/locus-info/parser.ts +6 -6
- package/src/media/index.ts +5 -5
- package/src/meeting/in-meeting-actions.ts +4 -0
- package/src/meeting/index.ts +111 -30
- package/src/meetings/index.ts +17 -10
- package/src/metrics/constants.ts +2 -0
- package/src/reconnection-manager/index.ts +1 -2
- package/test/unit/spec/media/index.ts +20 -4
- package/test/unit/spec/meeting/in-meeting-actions.ts +2 -0
- package/test/unit/spec/meeting/index.js +243 -47
- package/test/unit/spec/meetings/index.js +84 -8
- package/test/unit/spec/reconnection-manager/index.js +33 -18
package/src/meeting/index.ts
CHANGED
|
@@ -178,6 +178,12 @@ export type AddMediaOptions = {
|
|
|
178
178
|
allowMediaInLobby?: boolean; // allows adding media when in the lobby
|
|
179
179
|
};
|
|
180
180
|
|
|
181
|
+
export type CallStateForMetrics = {
|
|
182
|
+
correlationId?: string;
|
|
183
|
+
joinTrigger?: string;
|
|
184
|
+
loginType?: string;
|
|
185
|
+
};
|
|
186
|
+
|
|
181
187
|
export const MEDIA_UPDATE_TYPE = {
|
|
182
188
|
TRANSCODED_MEDIA_CONNECTION: 'TRANSCODED_MEDIA_CONNECTION',
|
|
183
189
|
SHARE_FLOOR_REQUEST: 'SHARE_FLOOR_REQUEST',
|
|
@@ -470,7 +476,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
470
476
|
annotation: any;
|
|
471
477
|
webinar: any;
|
|
472
478
|
conversationUrl: string;
|
|
473
|
-
|
|
479
|
+
callStateForMetrics: CallStateForMetrics;
|
|
474
480
|
destination: string;
|
|
475
481
|
destinationType: string;
|
|
476
482
|
deviceUrl: string;
|
|
@@ -538,6 +544,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
538
544
|
requiredCaptcha: any;
|
|
539
545
|
receiveSlotManager: ReceiveSlotManager;
|
|
540
546
|
selfUserPolicies: any;
|
|
547
|
+
enforceVBGImagesURL: string;
|
|
541
548
|
shareStatus: string;
|
|
542
549
|
screenShareFloorState: ScreenShareFloorStatus;
|
|
543
550
|
statsAnalyzer: StatsAnalyzer;
|
|
@@ -612,20 +619,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
612
619
|
*/
|
|
613
620
|
this.id = uuid.v4();
|
|
614
621
|
/**
|
|
615
|
-
*
|
|
622
|
+
* Call state used for metrics
|
|
616
623
|
* @instance
|
|
617
|
-
* @type {
|
|
624
|
+
* @type {CallStateForMetrics}
|
|
618
625
|
* @readonly
|
|
619
626
|
* @public
|
|
620
627
|
* @memberof Meeting
|
|
621
628
|
*/
|
|
622
|
-
|
|
629
|
+
this.callStateForMetrics = attrs.callStateForMetrics || {};
|
|
630
|
+
const correlationId = attrs.correlationId || attrs.callStateForMetrics?.correlationId;
|
|
631
|
+
if (correlationId) {
|
|
623
632
|
LoggerProxy.logger.log(
|
|
624
|
-
`Meetings:index#constructor --> Initializing the meeting object with correlation id from app ${
|
|
633
|
+
`Meetings:index#constructor --> Initializing the meeting object with correlation id from app ${correlationId}`
|
|
625
634
|
);
|
|
626
|
-
this.correlationId =
|
|
635
|
+
this.callStateForMetrics.correlationId = correlationId;
|
|
627
636
|
} else {
|
|
628
|
-
this.correlationId = this.id;
|
|
637
|
+
this.callStateForMetrics.correlationId = this.id;
|
|
629
638
|
}
|
|
630
639
|
/**
|
|
631
640
|
* @instance
|
|
@@ -1361,6 +1370,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1361
1370
|
return this.type === 'CALL';
|
|
1362
1371
|
}
|
|
1363
1372
|
|
|
1373
|
+
/**
|
|
1374
|
+
* Getter - Returns callStateForMetrics.correlationId
|
|
1375
|
+
* @returns {string}
|
|
1376
|
+
*/
|
|
1377
|
+
get correlationId() {
|
|
1378
|
+
return this.callStateForMetrics.correlationId;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
/**
|
|
1382
|
+
* Setter - sets callStateForMetrics.correlationId
|
|
1383
|
+
* @param {string} correlationId
|
|
1384
|
+
*/
|
|
1385
|
+
set correlationId(correlationId: string) {
|
|
1386
|
+
this.callStateForMetrics.correlationId = correlationId;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1364
1389
|
/**
|
|
1365
1390
|
* Internal method for fetching meeting info
|
|
1366
1391
|
*
|
|
@@ -1502,15 +1527,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1502
1527
|
: this.destination;
|
|
1503
1528
|
const destinationType = isStartingSpaceInstantV2Meeting ? _MEETING_LINK_ : this.destinationType;
|
|
1504
1529
|
|
|
1505
|
-
const
|
|
1530
|
+
const permissionTokenExpiryInfo = this.getPermissionTokenExpiryInfo();
|
|
1531
|
+
|
|
1532
|
+
const timeLeft = permissionTokenExpiryInfo?.timeLeft;
|
|
1533
|
+
const expiryTime = permissionTokenExpiryInfo?.expiryTime;
|
|
1534
|
+
const currentTime = permissionTokenExpiryInfo?.currentTime;
|
|
1506
1535
|
|
|
1507
1536
|
LoggerProxy.logger.info(
|
|
1508
|
-
`Meeting:index#refreshPermissionToken --> refreshing permission token, destinationType=${destinationType}, timeLeft=${timeLeft}, reason=${reason}`
|
|
1537
|
+
`Meeting:index#refreshPermissionToken --> refreshing permission token, destinationType=${destinationType}, timeLeft=${timeLeft}, permissionTokenExpiry=${expiryTime}, currentTimestamp=${currentTime},reason=${reason}`
|
|
1509
1538
|
);
|
|
1510
1539
|
|
|
1511
1540
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH, {
|
|
1512
1541
|
correlationId: this.correlationId,
|
|
1513
1542
|
timeLeft,
|
|
1543
|
+
expiryTime,
|
|
1544
|
+
currentTime,
|
|
1514
1545
|
reason,
|
|
1515
1546
|
destinationType,
|
|
1516
1547
|
});
|
|
@@ -3286,6 +3317,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3286
3317
|
}) &&
|
|
3287
3318
|
this.meetingInfo?.video?.supportHDV) ||
|
|
3288
3319
|
!this.arePolicyRestrictionsSupported(),
|
|
3320
|
+
enforceVirtualBackground:
|
|
3321
|
+
ControlsOptionsUtil.hasPolicies({
|
|
3322
|
+
requiredPolicies: [SELF_POLICY.ENFORCE_VIRTUAL_BACKGROUND],
|
|
3323
|
+
policies: this.selfUserPolicies,
|
|
3324
|
+
}) && this.arePolicyRestrictionsSupported(),
|
|
3289
3325
|
supportHQV:
|
|
3290
3326
|
(ControlsOptionsUtil.hasPolicies({
|
|
3291
3327
|
requiredPolicies: [SELF_POLICY.SUPPORT_HQV],
|
|
@@ -3502,6 +3538,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3502
3538
|
*/
|
|
3503
3539
|
setSelfUserPolicies() {
|
|
3504
3540
|
this.selfUserPolicies = this.permissionTokenPayload?.permission?.userPolicies;
|
|
3541
|
+
this.enforceVBGImagesURL = this.permissionTokenPayload?.permission?.enforceVBGImagesURL;
|
|
3505
3542
|
}
|
|
3506
3543
|
|
|
3507
3544
|
/**
|
|
@@ -3605,8 +3642,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3605
3642
|
* @memberof Meeting
|
|
3606
3643
|
*/
|
|
3607
3644
|
closeRemoteStreams() {
|
|
3608
|
-
const {remoteAudioStream, remoteVideoStream, remoteShareStream
|
|
3609
|
-
this.mediaProperties;
|
|
3645
|
+
const {remoteAudioStream, remoteVideoStream, remoteShareStream} = this.mediaProperties;
|
|
3610
3646
|
|
|
3611
3647
|
/**
|
|
3612
3648
|
* Triggers an event to the developer
|
|
@@ -3647,7 +3683,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3647
3683
|
stopStream(remoteAudioStream, EVENT_TYPES.REMOTE_AUDIO),
|
|
3648
3684
|
stopStream(remoteVideoStream, EVENT_TYPES.REMOTE_VIDEO),
|
|
3649
3685
|
stopStream(remoteShareStream, EVENT_TYPES.REMOTE_SHARE),
|
|
3650
|
-
stopStream(shareAudioStream, EVENT_TYPES.REMOTE_SHARE_AUDIO),
|
|
3651
3686
|
]);
|
|
3652
3687
|
}
|
|
3653
3688
|
|
|
@@ -3718,11 +3753,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3718
3753
|
private async setLocalShareVideoStream(localDisplayStream?: LocalDisplayStream) {
|
|
3719
3754
|
const oldStream = this.mediaProperties.shareVideoStream;
|
|
3720
3755
|
|
|
3756
|
+
oldStream?.off(StreamEventNames.MuteStateChange, this.handleShareVideoStreamMuteStateChange);
|
|
3721
3757
|
oldStream?.off(StreamEventNames.Ended, this.handleShareVideoStreamEnded);
|
|
3722
3758
|
oldStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3723
3759
|
|
|
3724
3760
|
this.mediaProperties.setLocalShareVideoStream(localDisplayStream);
|
|
3725
3761
|
|
|
3762
|
+
localDisplayStream?.on(
|
|
3763
|
+
StreamEventNames.MuteStateChange,
|
|
3764
|
+
this.handleShareVideoStreamMuteStateChange
|
|
3765
|
+
);
|
|
3726
3766
|
localDisplayStream?.on(StreamEventNames.Ended, this.handleShareVideoStreamEnded);
|
|
3727
3767
|
localDisplayStream?.on(
|
|
3728
3768
|
LocalStreamEventNames.OutputTrackChange,
|
|
@@ -3778,7 +3818,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3778
3818
|
functionName: string;
|
|
3779
3819
|
isPublished: boolean;
|
|
3780
3820
|
mediaType: MediaType;
|
|
3781
|
-
stream:
|
|
3821
|
+
stream: LocalStream;
|
|
3782
3822
|
}) {
|
|
3783
3823
|
const {functionName, isPublished, mediaType, stream} = options;
|
|
3784
3824
|
Trigger.trigger(
|
|
@@ -3812,12 +3852,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3812
3852
|
videoStream?.off(StreamEventNames.MuteStateChange, this.localVideoStreamMuteStateHandler);
|
|
3813
3853
|
videoStream?.off(LocalStreamEventNames.OutputTrackChange, this.localOutputTrackChangeHandler);
|
|
3814
3854
|
|
|
3815
|
-
shareAudioStream?.off(StreamEventNames.
|
|
3855
|
+
shareAudioStream?.off(StreamEventNames.Ended, this.handleShareAudioStreamEnded);
|
|
3816
3856
|
shareAudioStream?.off(
|
|
3817
3857
|
LocalStreamEventNames.OutputTrackChange,
|
|
3818
3858
|
this.localOutputTrackChangeHandler
|
|
3819
3859
|
);
|
|
3820
|
-
shareVideoStream?.off(
|
|
3860
|
+
shareVideoStream?.off(
|
|
3861
|
+
StreamEventNames.MuteStateChange,
|
|
3862
|
+
this.handleShareVideoStreamMuteStateChange
|
|
3863
|
+
);
|
|
3864
|
+
shareVideoStream?.off(StreamEventNames.Ended, this.handleShareVideoStreamEnded);
|
|
3821
3865
|
shareVideoStream?.off(
|
|
3822
3866
|
LocalStreamEventNames.OutputTrackChange,
|
|
3823
3867
|
this.localOutputTrackChangeHandler
|
|
@@ -3959,14 +4003,25 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3959
4003
|
}
|
|
3960
4004
|
|
|
3961
4005
|
/**
|
|
3962
|
-
* Convenience method to set the correlation id for the
|
|
3963
|
-
* @param {String} id correlation id to set on the
|
|
4006
|
+
* Convenience method to set the correlation id for the callStateForMetrics
|
|
4007
|
+
* @param {String} id correlation id to set on the callStateForMetrics
|
|
3964
4008
|
* @returns {undefined}
|
|
3965
4009
|
* @public
|
|
3966
4010
|
* @memberof Meeting
|
|
3967
4011
|
*/
|
|
3968
4012
|
public setCorrelationId(id: string) {
|
|
3969
|
-
this.correlationId = id;
|
|
4013
|
+
this.callStateForMetrics.correlationId = id;
|
|
4014
|
+
}
|
|
4015
|
+
|
|
4016
|
+
/**
|
|
4017
|
+
* Update the callStateForMetrics
|
|
4018
|
+
* @param {CallStateForMetrics} callStateForMetrics updated values for callStateForMetrics
|
|
4019
|
+
* @returns {undefined}
|
|
4020
|
+
* @public
|
|
4021
|
+
* @memberof Meeting
|
|
4022
|
+
*/
|
|
4023
|
+
public updateCallStateForMetrics(callStateForMetrics: CallStateForMetrics) {
|
|
4024
|
+
this.callStateForMetrics = {...this.callStateForMetrics, ...callStateForMetrics};
|
|
3970
4025
|
}
|
|
3971
4026
|
|
|
3972
4027
|
/**
|
|
@@ -4618,7 +4673,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4618
4673
|
this.webex.internal.newMetrics.submitClientEvent({
|
|
4619
4674
|
name: 'client.call.initiated',
|
|
4620
4675
|
payload: {
|
|
4621
|
-
trigger: 'user-interaction',
|
|
4676
|
+
trigger: this.callStateForMetrics.joinTrigger || 'user-interaction',
|
|
4622
4677
|
isRoapCallEnabled: true,
|
|
4623
4678
|
pstnAudioType: options?.pstnAudioType,
|
|
4624
4679
|
},
|
|
@@ -6185,7 +6240,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6185
6240
|
const LOG_HEADER = 'Meeting:index#addMedia -->';
|
|
6186
6241
|
LoggerProxy.logger.info(`${LOG_HEADER} called with: ${JSON.stringify(options)}`);
|
|
6187
6242
|
|
|
6188
|
-
if (this.meetingState !== FULL_STATE.ACTIVE) {
|
|
6243
|
+
if (options.allowMediaInLobby !== true && this.meetingState !== FULL_STATE.ACTIVE) {
|
|
6189
6244
|
throw new MeetingNotActiveError();
|
|
6190
6245
|
}
|
|
6191
6246
|
|
|
@@ -6920,6 +6975,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6920
6975
|
.then(() => {
|
|
6921
6976
|
this.screenShareFloorState = ScreenShareFloorStatus.GRANTED;
|
|
6922
6977
|
|
|
6978
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_SHARE_SUCCESS, {
|
|
6979
|
+
correlation_id: this.correlationId,
|
|
6980
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
6981
|
+
});
|
|
6982
|
+
|
|
6923
6983
|
return Promise.resolve();
|
|
6924
6984
|
})
|
|
6925
6985
|
.catch((error) => {
|
|
@@ -7341,6 +7401,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7341
7401
|
}
|
|
7342
7402
|
};
|
|
7343
7403
|
|
|
7404
|
+
/**
|
|
7405
|
+
* Functionality for when a share video is muted or unmuted.
|
|
7406
|
+
* @private
|
|
7407
|
+
* @memberof Meeting
|
|
7408
|
+
* @param {boolean} muted
|
|
7409
|
+
* @returns {undefined}
|
|
7410
|
+
*/
|
|
7411
|
+
private handleShareVideoStreamMuteStateChange = (muted: boolean) => {
|
|
7412
|
+
LoggerProxy.logger.log(
|
|
7413
|
+
`Meeting:index#handleShareVideoStreamMuteStateChange --> Share video stream mute state changed to muted ${muted}`
|
|
7414
|
+
);
|
|
7415
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE, {
|
|
7416
|
+
correlationId: this.correlationId,
|
|
7417
|
+
muted,
|
|
7418
|
+
});
|
|
7419
|
+
};
|
|
7420
|
+
|
|
7344
7421
|
/**
|
|
7345
7422
|
* Functionality for when a share video is ended.
|
|
7346
7423
|
* @private
|
|
@@ -7707,10 +7784,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7707
7784
|
.update({
|
|
7708
7785
|
// TODO: RoapMediaConnection is not ready to use stream classes yet, so we pass the raw MediaStreamTrack for now
|
|
7709
7786
|
localTracks: {
|
|
7710
|
-
audio: this.mediaProperties.audioStream?.
|
|
7711
|
-
video: this.mediaProperties.videoStream?.
|
|
7712
|
-
screenShareVideo:
|
|
7713
|
-
|
|
7787
|
+
audio: this.mediaProperties.audioStream?.outputStream?.getTracks()[0] || null,
|
|
7788
|
+
video: this.mediaProperties.videoStream?.outputStream?.getTracks()[0] || null,
|
|
7789
|
+
screenShareVideo:
|
|
7790
|
+
this.mediaProperties.shareVideoStream?.outputStream?.getTracks()[0] || null,
|
|
7791
|
+
screenShareAudio:
|
|
7792
|
+
this.mediaProperties.shareAudioStream?.outputStream?.getTracks()[0] || null,
|
|
7714
7793
|
},
|
|
7715
7794
|
direction: {
|
|
7716
7795
|
audio: Media.getDirection(
|
|
@@ -7899,12 +7978,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7899
7978
|
}
|
|
7900
7979
|
|
|
7901
7980
|
/**
|
|
7902
|
-
* Gets
|
|
7981
|
+
* Gets permission token expiry information including timeLeft, expiryTime, currentTime
|
|
7903
7982
|
* (from the time the function has been fired)
|
|
7904
7983
|
*
|
|
7905
|
-
* @returns {
|
|
7984
|
+
* @returns {object} containing timeLeft, expiryTime, currentTime
|
|
7906
7985
|
*/
|
|
7907
|
-
public
|
|
7986
|
+
public getPermissionTokenExpiryInfo() {
|
|
7908
7987
|
if (!this.permissionTokenPayload) {
|
|
7909
7988
|
return undefined;
|
|
7910
7989
|
}
|
|
@@ -7917,7 +7996,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7917
7996
|
|
|
7918
7997
|
// substract current time from the permissionTokenExp
|
|
7919
7998
|
// (permissionTokenExp is a epoch timestamp, not a time to live duration)
|
|
7920
|
-
|
|
7999
|
+
const timeLeft = (permissionTokenExpValue - now) / 1000;
|
|
8000
|
+
|
|
8001
|
+
return {timeLeft, expiryTime: permissionTokenExpValue, currentTime: now};
|
|
7921
8002
|
}
|
|
7922
8003
|
|
|
7923
8004
|
/**
|
|
@@ -7929,9 +8010,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7929
8010
|
* @returns {Promise<void>}
|
|
7930
8011
|
*/
|
|
7931
8012
|
public checkAndRefreshPermissionToken(threshold: number, reason: string): Promise<void> {
|
|
7932
|
-
const
|
|
8013
|
+
const timeLeft = this.getPermissionTokenExpiryInfo()?.timeLeft;
|
|
7933
8014
|
|
|
7934
|
-
if (
|
|
8015
|
+
if (timeLeft !== undefined && timeLeft <= threshold) {
|
|
7935
8016
|
return this.refreshPermissionToken(reason);
|
|
7936
8017
|
}
|
|
7937
8018
|
|
package/src/meetings/index.ts
CHANGED
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
50
50
|
import MeetingInfo from '../meeting-info';
|
|
51
51
|
import MeetingInfoV2 from '../meeting-info/meeting-info-v2';
|
|
52
|
-
import Meeting from '../meeting';
|
|
52
|
+
import Meeting, {CallStateForMetrics} from '../meeting';
|
|
53
53
|
import PersonalMeetingRoom from '../personal-meeting-room';
|
|
54
54
|
import Reachability from '../reachability';
|
|
55
55
|
import Request from './request';
|
|
@@ -1025,13 +1025,14 @@ export default class Meetings extends WebexPlugin {
|
|
|
1025
1025
|
}
|
|
1026
1026
|
|
|
1027
1027
|
/**
|
|
1028
|
-
* Create a meeting.
|
|
1028
|
+
* Create a meeting or return an existing meeting.
|
|
1029
1029
|
* @param {string} destination - sipURL, phonenumber, or locus object}
|
|
1030
1030
|
* @param {string} [type] - the optional specified type, such as locusId
|
|
1031
1031
|
* @param {Boolean} useRandomDelayForInfo - whether a random delay should be added to fetching meeting info
|
|
1032
1032
|
* @param {Object} infoExtraParams extra parameters to be provided when fetching meeting info
|
|
1033
|
-
* @param {string} correlationId - the optional specified correlationId
|
|
1033
|
+
* @param {string} correlationId - the optional specified correlationId (callStateForMetrics.correlationId can be provided instead)
|
|
1034
1034
|
* @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
|
+
* @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
|
|
1035
1036
|
* @returns {Promise<Meeting>} A new Meeting.
|
|
1036
1037
|
* @public
|
|
1037
1038
|
* @memberof Meetings
|
|
@@ -1042,7 +1043,8 @@ export default class Meetings extends WebexPlugin {
|
|
|
1042
1043
|
useRandomDelayForInfo = false,
|
|
1043
1044
|
infoExtraParams = {},
|
|
1044
1045
|
correlationId: string = undefined,
|
|
1045
|
-
failOnMissingMeetingInfo = false
|
|
1046
|
+
failOnMissingMeetingInfo = false,
|
|
1047
|
+
callStateForMetrics: CallStateForMetrics = undefined
|
|
1046
1048
|
) {
|
|
1047
1049
|
// TODO: type should be from a dictionary
|
|
1048
1050
|
|
|
@@ -1050,6 +1052,10 @@ export default class Meetings extends WebexPlugin {
|
|
|
1050
1052
|
// type. This must be performed prior to determining if the meeting is
|
|
1051
1053
|
// found in the collection, as we mutate the destination for hydra person
|
|
1052
1054
|
// id values.
|
|
1055
|
+
if (correlationId) {
|
|
1056
|
+
callStateForMetrics = {...(callStateForMetrics || {}), correlationId};
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1053
1059
|
return (
|
|
1054
1060
|
this.meetingInfo
|
|
1055
1061
|
.fetchInfoOptions(destination, type)
|
|
@@ -1096,7 +1102,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
1096
1102
|
type,
|
|
1097
1103
|
useRandomDelayForInfo,
|
|
1098
1104
|
infoExtraParams,
|
|
1099
|
-
|
|
1105
|
+
callStateForMetrics,
|
|
1100
1106
|
failOnMissingMeetingInfo
|
|
1101
1107
|
).then((createdMeeting: any) => {
|
|
1102
1108
|
// If the meeting was successfully created.
|
|
@@ -1143,6 +1149,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
1143
1149
|
return Promise.resolve(createdMeeting);
|
|
1144
1150
|
});
|
|
1145
1151
|
}
|
|
1152
|
+
meeting.setCallStateForMetrics(callStateForMetrics);
|
|
1146
1153
|
|
|
1147
1154
|
// Return the existing meeting.
|
|
1148
1155
|
return Promise.resolve(meeting);
|
|
@@ -1155,7 +1162,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
1155
1162
|
* @param {String} type see create()
|
|
1156
1163
|
* @param {Boolean} useRandomDelayForInfo whether a random delay should be added to fetching meeting info
|
|
1157
1164
|
* @param {Object} infoExtraParams extra parameters to be provided when fetching meeting info
|
|
1158
|
-
* @param {
|
|
1165
|
+
* @param {CallStateForMetrics} callStateForMetrics - information about call state for metrics
|
|
1159
1166
|
* @param {Boolean} failOnMissingMeetingInfo - whether to throw an error if meeting info fails to fetch (for calls that are not 1:1 or content share)
|
|
1160
1167
|
* @returns {Promise} a new meeting instance complete with meeting info and destination
|
|
1161
1168
|
* @private
|
|
@@ -1166,7 +1173,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
1166
1173
|
type: string = null,
|
|
1167
1174
|
useRandomDelayForInfo = false,
|
|
1168
1175
|
infoExtraParams = {},
|
|
1169
|
-
|
|
1176
|
+
callStateForMetrics: CallStateForMetrics = undefined,
|
|
1170
1177
|
failOnMissingMeetingInfo = false
|
|
1171
1178
|
) {
|
|
1172
1179
|
const meeting = new Meeting(
|
|
@@ -1181,7 +1188,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
1181
1188
|
meetingInfoProvider: this.meetingInfo,
|
|
1182
1189
|
destination,
|
|
1183
1190
|
destinationType: type,
|
|
1184
|
-
|
|
1191
|
+
callStateForMetrics,
|
|
1185
1192
|
},
|
|
1186
1193
|
{
|
|
1187
1194
|
// @ts-ignore
|
|
@@ -1219,7 +1226,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
1219
1226
|
() =>
|
|
1220
1227
|
meeting.fetchMeetingInfo({
|
|
1221
1228
|
extraParams: infoExtraParams,
|
|
1222
|
-
sendCAevents: !!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
|
|
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
|
|
1223
1230
|
}),
|
|
1224
1231
|
waitingTime
|
|
1225
1232
|
);
|
|
@@ -1227,7 +1234,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
1227
1234
|
} else {
|
|
1228
1235
|
await meeting.fetchMeetingInfo({
|
|
1229
1236
|
extraParams: infoExtraParams,
|
|
1230
|
-
sendCAevents: !!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
|
|
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
|
|
1231
1238
|
});
|
|
1232
1239
|
}
|
|
1233
1240
|
} catch (err) {
|
package/src/metrics/constants.ts
CHANGED
|
@@ -26,9 +26,11 @@ const BEHAVIORAL_METRICS = {
|
|
|
26
26
|
MEETING_MEDIA_INACTIVE: 'js_sdk_meeting_media_inactive',
|
|
27
27
|
MEETING_RECONNECT_FAILURE: 'js_sdk_meeting_reconnect_failures',
|
|
28
28
|
MEETING_MAX_REJOIN_FAILURE: 'js_sdk_meeting_max_rejoin_failure',
|
|
29
|
+
MEETING_SHARE_SUCCESS: 'js_sdk_meeting_share_success',
|
|
29
30
|
MEETING_SHARE_FAILURE: 'js_sdk_meeting_share_failures',
|
|
30
31
|
MEETING_START_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_start_whiteboard_share_failures',
|
|
31
32
|
MEETING_STOP_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_stop_whiteboard_share_failures',
|
|
33
|
+
MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE: 'js_sdk_meeting_share_video_mute_state_change',
|
|
32
34
|
MUTE_AUDIO_FAILURE: 'js_sdk_mute_audio_failures',
|
|
33
35
|
MUTE_VIDEO_FAILURE: 'js_sdk_mute_video_failures',
|
|
34
36
|
SET_MEETING_QUALITY_FAILURE: 'js_sdk_set_meeting_quality_failures',
|
|
@@ -17,11 +17,11 @@ import {
|
|
|
17
17
|
RECONNECTION_STATE,
|
|
18
18
|
} from '../constants';
|
|
19
19
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
20
|
-
import ReconnectionError from '../common/errors/reconnection';
|
|
21
20
|
import ReconnectInProgress from '../common/errors/reconnection-in-progress';
|
|
22
21
|
import Metrics from '../metrics';
|
|
23
22
|
import Meeting from '../meeting';
|
|
24
23
|
import {MediaRequestManager} from '../multistream/mediaRequestManager';
|
|
24
|
+
import ReconnectionError from '../common/errors/reconnection';
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Used to indicate that the reconnect logic needs to be retried.
|
|
@@ -228,7 +228,6 @@ export default class ReconnectionManager {
|
|
|
228
228
|
*/
|
|
229
229
|
public cleanUp() {
|
|
230
230
|
this.reset();
|
|
231
|
-
this.meeting = null;
|
|
232
231
|
}
|
|
233
232
|
|
|
234
233
|
/**
|
|
@@ -16,16 +16,32 @@ describe('createMediaConnection', () => {
|
|
|
16
16
|
id: 'any fake track'
|
|
17
17
|
}
|
|
18
18
|
const fakeAudioStream = {
|
|
19
|
-
|
|
19
|
+
outputStream: {
|
|
20
|
+
getTracks: () => {
|
|
21
|
+
return [fakeTrack];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
20
24
|
};
|
|
21
25
|
const fakeVideoStream = {
|
|
22
|
-
|
|
26
|
+
outputStream: {
|
|
27
|
+
getTracks: () => {
|
|
28
|
+
return [fakeTrack];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
23
31
|
};
|
|
24
32
|
const fakeShareVideoStream = {
|
|
25
|
-
|
|
33
|
+
outputStream: {
|
|
34
|
+
getTracks: () => {
|
|
35
|
+
return [fakeTrack];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
26
38
|
};
|
|
27
39
|
const fakeShareAudioStream = {
|
|
28
|
-
|
|
40
|
+
outputStream: {
|
|
41
|
+
getTracks: () => {
|
|
42
|
+
return [fakeTrack];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
29
45
|
};
|
|
30
46
|
afterEach(() => {
|
|
31
47
|
sinon.restore();
|
|
@@ -74,6 +74,7 @@ describe('plugin-meetings', () => {
|
|
|
74
74
|
supportHQV: null,
|
|
75
75
|
supportHDV: null,
|
|
76
76
|
canShareWhiteBoard: null,
|
|
77
|
+
enforceVirtualBackground: null,
|
|
77
78
|
...expected,
|
|
78
79
|
};
|
|
79
80
|
|
|
@@ -153,6 +154,7 @@ describe('plugin-meetings', () => {
|
|
|
153
154
|
'supportHQV',
|
|
154
155
|
'supportHDV',
|
|
155
156
|
'canShareWhiteBoard',
|
|
157
|
+
'enforceVirtualBackground',
|
|
156
158
|
].forEach((key) => {
|
|
157
159
|
it(`get and set for ${key} work as expected`, () => {
|
|
158
160
|
const inMeetingActions = new InMeetingActions();
|