@webex/plugin-meetings 3.8.1-web-workers-keepalive.1 → 3.9.0-next.1
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/constants.js +24 -2
- 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.js +39 -85
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/brbState.js +14 -12
- package/dist/meeting/brbState.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +6 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +274 -140
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +19 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/type.js +7 -0
- package/dist/meeting/type.js.map +1 -0
- package/dist/meeting/util.js +68 -2
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +35 -33
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js.map +1 -1
- package/dist/members/index.js +11 -9
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +3 -3
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js +18 -6
- package/dist/members/util.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +1 -1
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js +34 -5
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +42 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +32 -2
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/types/constants.d.ts +22 -0
- package/dist/types/locus-info/index.d.ts +0 -9
- package/dist/types/meeting/brbState.d.ts +0 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +6 -0
- package/dist/types/meeting/index.d.ts +40 -19
- package/dist/types/meeting/request.d.ts +9 -1
- package/dist/types/meeting/request.type.d.ts +74 -0
- package/dist/types/meeting/type.d.ts +9 -0
- package/dist/types/meeting/util.d.ts +3 -0
- package/dist/types/members/index.d.ts +10 -7
- package/dist/types/members/request.d.ts +1 -1
- package/dist/types/members/util.d.ts +7 -3
- package/dist/types/multistream/remoteMedia.d.ts +20 -1
- package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
- package/dist/types/multistream/sendSlotManager.d.ts +16 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -23
- package/src/constants.ts +23 -2
- package/src/locus-info/index.ts +48 -86
- package/src/meeting/brbState.ts +9 -7
- package/src/meeting/in-meeting-actions.ts +13 -0
- package/src/meeting/index.ts +165 -38
- package/src/meeting/request.ts +16 -0
- package/src/meeting/request.type.ts +64 -0
- package/src/meeting/type.ts +9 -0
- package/src/meeting/util.ts +73 -2
- package/src/meetings/index.ts +3 -2
- package/src/member/index.ts +1 -0
- package/src/members/index.ts +13 -10
- package/src/members/request.ts +2 -2
- package/src/members/util.ts +16 -4
- package/src/multistream/mediaRequestManager.ts +7 -7
- package/src/multistream/remoteMedia.ts +34 -4
- package/src/multistream/remoteMediaGroup.ts +37 -2
- package/src/multistream/sendSlotManager.ts +34 -2
- package/test/unit/spec/locus-info/index.js +199 -83
- package/test/unit/spec/meeting/brbState.ts +9 -9
- package/test/unit/spec/meeting/in-meeting-actions.ts +6 -0
- package/test/unit/spec/meeting/index.js +729 -80
- package/test/unit/spec/meeting/request.js +71 -0
- package/test/unit/spec/meeting/utils.js +122 -1
- package/test/unit/spec/meetings/index.js +2 -0
- package/test/unit/spec/members/index.js +68 -9
- package/test/unit/spec/members/request.js +2 -2
- package/test/unit/spec/members/utils.js +27 -7
- package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
- package/test/unit/spec/multistream/remoteMedia.ts +66 -2
- package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
- package/test/unit/spec/reachability/index.ts +3 -1
package/src/meeting/index.ts
CHANGED
@@ -121,6 +121,7 @@ import {
|
|
121
121
|
WEBINAR_ERROR_REGISTRATION_ID,
|
122
122
|
JOIN_BEFORE_HOST,
|
123
123
|
REGISTRATION_ID_STATUS,
|
124
|
+
STAGE_MANAGER_TYPE,
|
124
125
|
} from '../constants';
|
125
126
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
126
127
|
import ParameterError from '../common/errors/parameter';
|
@@ -164,6 +165,8 @@ import {BrbState, createBrbState} from './brbState';
|
|
164
165
|
import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error';
|
165
166
|
import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
166
167
|
import {ReachabilityMetrics} from '../reachability/reachability.types';
|
168
|
+
import {SetStageOptions, SetStageVideoLayout, UnsetStageVideoLayout} from './request.type';
|
169
|
+
import {Invitee} from './type';
|
167
170
|
|
168
171
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
169
172
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
@@ -248,6 +251,7 @@ export type CallStateForMetrics = {
|
|
248
251
|
loginType?: string;
|
249
252
|
userNameInput?: string;
|
250
253
|
emailInput?: string;
|
254
|
+
pstnCorrelationId?: string;
|
251
255
|
};
|
252
256
|
|
253
257
|
export const MEDIA_UPDATE_TYPE = {
|
@@ -741,10 +745,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
741
745
|
/**
|
742
746
|
* @param {Object} attrs
|
743
747
|
* @param {Object} options
|
748
|
+
* @param {Function} callback - if provided, it will be called with the newly created meeting object as soon as the meeting.id is set
|
744
749
|
* @constructor
|
745
750
|
* @memberof Meeting
|
746
751
|
*/
|
747
|
-
constructor(attrs: any, options: object) {
|
752
|
+
constructor(attrs: any, options: object, callback: (meeting: Meeting) => void) {
|
748
753
|
super({}, options);
|
749
754
|
/**
|
750
755
|
* @instance
|
@@ -770,6 +775,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
770
775
|
* @memberof Meeting
|
771
776
|
*/
|
772
777
|
this.id = uuid.v4();
|
778
|
+
|
779
|
+
if (callback) {
|
780
|
+
callback(this);
|
781
|
+
}
|
782
|
+
|
773
783
|
/**
|
774
784
|
* Call state used for metrics
|
775
785
|
* @instance
|
@@ -1674,6 +1684,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1674
1684
|
this.callStateForMetrics.correlationId = correlationId;
|
1675
1685
|
}
|
1676
1686
|
|
1687
|
+
/**
|
1688
|
+
* Getter - Returns callStateForMetrics.pstnCorrelationId
|
1689
|
+
* @returns {string | undefined}
|
1690
|
+
*/
|
1691
|
+
get pstnCorrelationId(): string | undefined {
|
1692
|
+
return this.callStateForMetrics.pstnCorrelationId;
|
1693
|
+
}
|
1694
|
+
|
1695
|
+
/**
|
1696
|
+
* Setter - sets callStateForMetrics.pstnCorrelationId
|
1697
|
+
* @param {string | undefined} correlationId
|
1698
|
+
*/
|
1699
|
+
set pstnCorrelationId(correlationId: string | undefined) {
|
1700
|
+
this.callStateForMetrics.pstnCorrelationId = correlationId;
|
1701
|
+
}
|
1702
|
+
|
1677
1703
|
/**
|
1678
1704
|
* Getter - Returns callStateForMetrics.userNameInput
|
1679
1705
|
* @returns {string}
|
@@ -3056,12 +3082,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3056
3082
|
// There is no concept of local/remote share for whiteboard
|
3057
3083
|
// It does not matter who requested to share the whiteboard, everyone gets the same view
|
3058
3084
|
else if (whiteboardShare.disposition === FLOOR_ACTION.GRANTED) {
|
3059
|
-
|
3060
|
-
|
3061
|
-
|
3062
|
-
|
3063
|
-
|
3064
|
-
|
3085
|
+
if (this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee) {
|
3086
|
+
// WHITEBOARD - sharing whiteboard
|
3087
|
+
// Webinar attendee should receive whiteboard as remote share
|
3088
|
+
newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
|
3089
|
+
} else if (this.guest) {
|
3090
|
+
// If user is a guest to a meeting, they should receive whiteboard as remote share
|
3091
|
+
newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
|
3092
|
+
} else {
|
3093
|
+
newShareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
3094
|
+
}
|
3065
3095
|
}
|
3066
3096
|
// or if content share is either released or null and whiteboard share is either released or null, no one is sharing
|
3067
3097
|
else if (
|
@@ -3827,49 +3857,44 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3827
3857
|
|
3828
3858
|
/**
|
3829
3859
|
* Invite a guest to the call that isn't normally part of this call
|
3830
|
-
* @param {
|
3860
|
+
* @param {Invitee} invitee
|
3831
3861
|
* @param {String} invitee.emailAddress
|
3832
3862
|
* @param {String} invitee.email
|
3833
3863
|
* @param {String} invitee.phoneNumber
|
3834
3864
|
* @param {Boolean} [alertIfActive]
|
3865
|
+
* @param {Boolean} [invitee.skipEmailValidation]
|
3866
|
+
* @param {Boolean} [invitee.isInternalNumber]
|
3835
3867
|
* @returns {Promise} see #members.addMember
|
3836
3868
|
* @public
|
3837
3869
|
* @memberof Meeting
|
3838
3870
|
*/
|
3839
|
-
public invite(
|
3840
|
-
invitee: {
|
3841
|
-
emailAddress: string;
|
3842
|
-
email: string;
|
3843
|
-
phoneNumber: string;
|
3844
|
-
roles: Array<string>;
|
3845
|
-
},
|
3846
|
-
alertIfActive = true
|
3847
|
-
) {
|
3871
|
+
public invite(invitee: Invitee, alertIfActive = true) {
|
3848
3872
|
return this.members.addMember(invitee, alertIfActive);
|
3849
3873
|
}
|
3850
3874
|
|
3851
3875
|
/**
|
3852
3876
|
* Cancel an outgoing phone call invitation made during a meeting
|
3853
|
-
* @param {
|
3877
|
+
* @param {Invitee} invitee
|
3854
3878
|
* @param {String} invitee.phoneNumber
|
3855
3879
|
* @returns {Promise} see #members.cancelPhoneInvite
|
3856
3880
|
* @public
|
3857
3881
|
* @memberof Meeting
|
3858
3882
|
*/
|
3859
|
-
public cancelPhoneInvite(invitee:
|
3883
|
+
public cancelPhoneInvite(invitee: Invitee) {
|
3860
3884
|
return this.members.cancelPhoneInvite(invitee);
|
3861
3885
|
}
|
3862
3886
|
|
3863
3887
|
/**
|
3864
|
-
* Cancel an SIP call invitation made during a meeting
|
3865
|
-
* @param {
|
3888
|
+
* Cancel an SIP/phone call invitation made during a meeting
|
3889
|
+
* @param {Invitee} invitee
|
3866
3890
|
* @param {String} invitee.memberId
|
3867
|
-
* @
|
3891
|
+
* @param {Boolean} [invitee.isInternalNumber] - When cancel phone invitation, if the number is internal
|
3892
|
+
* @returns {Promise} see #members.cancelInviteByMemberId
|
3868
3893
|
* @public
|
3869
3894
|
* @memberof Meeting
|
3870
3895
|
*/
|
3871
|
-
public
|
3872
|
-
return this.members.
|
3896
|
+
public cancelInviteByMemberId(invitee: Invitee) {
|
3897
|
+
return this.members.cancelInviteByMemberId(invitee);
|
3873
3898
|
}
|
3874
3899
|
|
3875
3900
|
/**
|
@@ -4167,6 +4192,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4167
4192
|
isClosedCaptionActive: MeetingUtil.isClosedCaptionActive(this.userDisplayHints),
|
4168
4193
|
canStartManualCaption: MeetingUtil.canStartManualCaption(this.userDisplayHints),
|
4169
4194
|
canStopManualCaption: MeetingUtil.canStopManualCaption(this.userDisplayHints),
|
4195
|
+
isLocalRecordingStarted: MeetingUtil.isLocalRecordingStarted(this.userDisplayHints),
|
4196
|
+
isLocalRecordingStopped: MeetingUtil.isLocalRecordingStopped(this.userDisplayHints),
|
4197
|
+
isLocalRecordingPaused: MeetingUtil.isLocalRecordingPaused(this.userDisplayHints),
|
4170
4198
|
isManualCaptionActive: MeetingUtil.isManualCaptionActive(this.userDisplayHints),
|
4171
4199
|
isSaveTranscriptsEnabled: MeetingUtil.isSaveTranscriptsEnabled(this.userDisplayHints),
|
4172
4200
|
isWebexAssistantActive: MeetingUtil.isWebexAssistantActive(this.userDisplayHints),
|
@@ -5924,15 +5952,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
5924
5952
|
this.meetingFiniteStateMachine.fail(error);
|
5925
5953
|
LoggerProxy.logger.error('Meeting:index#join --> Failed', error);
|
5926
5954
|
|
5927
|
-
// @ts-ignore
|
5928
|
-
this.webex.internal.newMetrics.submitClientEvent({
|
5929
|
-
name: 'client.locus.join.response',
|
5930
|
-
payload: {
|
5931
|
-
identifiers: {meetingLookupUrl: this.meetingInfo?.meetingLookupUrl},
|
5932
|
-
},
|
5933
|
-
options: {meetingId: this.id, rawError: error},
|
5934
|
-
});
|
5935
|
-
|
5936
5955
|
// TODO: change this to error codes and pre defined dictionary
|
5937
5956
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_FAILURE, {
|
5938
5957
|
correlation_id: this.correlationId,
|
@@ -6082,8 +6101,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6082
6101
|
*/
|
6083
6102
|
private dialInPstn() {
|
6084
6103
|
if (this.isPhoneProvisioned(this.dialInDeviceStatus)) return Promise.resolve(); // prevent multiple dial in devices from being provisioned
|
6104
|
+
this.pstnCorrelationId = uuid.v4();
|
6085
6105
|
|
6086
|
-
const {
|
6106
|
+
const {pstnCorrelationId, locusUrl} = this;
|
6087
6107
|
|
6088
6108
|
if (!this.dialInUrl) this.dialInUrl = `dialin:///${uuid.v4()}`;
|
6089
6109
|
|
@@ -6091,7 +6111,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6091
6111
|
this.meetingRequest
|
6092
6112
|
// @ts-ignore
|
6093
6113
|
.dialIn({
|
6094
|
-
correlationId,
|
6114
|
+
correlationId: pstnCorrelationId,
|
6095
6115
|
dialInUrl: this.dialInUrl,
|
6096
6116
|
locusUrl,
|
6097
6117
|
clientUrl: this.deviceUrl,
|
@@ -6100,12 +6120,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6100
6120
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
|
6101
6121
|
correlation_id: this.correlationId,
|
6102
6122
|
dial_in_url: this.dialInUrl,
|
6123
|
+
dial_in_correlation_id: pstnCorrelationId,
|
6103
6124
|
locus_id: locusUrl.split('/').pop(),
|
6104
6125
|
client_url: this.deviceUrl,
|
6105
6126
|
reason: error.error?.message,
|
6106
6127
|
stack: error.stack,
|
6107
6128
|
});
|
6108
6129
|
|
6130
|
+
if (this.pstnCorrelationId === pstnCorrelationId) {
|
6131
|
+
this.pstnCorrelationId = undefined;
|
6132
|
+
}
|
6133
|
+
|
6109
6134
|
return Promise.reject(error);
|
6110
6135
|
})
|
6111
6136
|
);
|
@@ -6120,8 +6145,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6120
6145
|
*/
|
6121
6146
|
private dialOutPstn(phoneNumber: string) {
|
6122
6147
|
if (this.isPhoneProvisioned(this.dialOutDeviceStatus)) return Promise.resolve(); // prevent multiple dial out devices from being provisioned
|
6148
|
+
this.pstnCorrelationId = uuid.v4();
|
6123
6149
|
|
6124
|
-
const {
|
6150
|
+
const {locusUrl, pstnCorrelationId} = this;
|
6125
6151
|
|
6126
6152
|
if (!this.dialOutUrl) this.dialOutUrl = `dialout:///${uuid.v4()}`;
|
6127
6153
|
|
@@ -6129,7 +6155,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6129
6155
|
this.meetingRequest
|
6130
6156
|
// @ts-ignore
|
6131
6157
|
.dialOut({
|
6132
|
-
correlationId,
|
6158
|
+
correlationId: pstnCorrelationId,
|
6133
6159
|
dialOutUrl: this.dialOutUrl,
|
6134
6160
|
phoneNumber,
|
6135
6161
|
locusUrl,
|
@@ -6139,12 +6165,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6139
6165
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
|
6140
6166
|
correlation_id: this.correlationId,
|
6141
6167
|
dial_out_url: this.dialOutUrl,
|
6168
|
+
dial_out_correlation_id: pstnCorrelationId,
|
6142
6169
|
locus_id: locusUrl.split('/').pop(),
|
6143
6170
|
client_url: this.deviceUrl,
|
6144
6171
|
reason: error.error?.message,
|
6145
6172
|
stack: error.stack,
|
6146
6173
|
});
|
6147
6174
|
|
6175
|
+
if (this.pstnCorrelationId === pstnCorrelationId) {
|
6176
|
+
this.pstnCorrelationId = undefined;
|
6177
|
+
}
|
6178
|
+
|
6148
6179
|
return Promise.reject(error);
|
6149
6180
|
})
|
6150
6181
|
);
|
@@ -6158,6 +6189,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6158
6189
|
* @returns {Promise}
|
6159
6190
|
*/
|
6160
6191
|
public disconnectPhoneAudio() {
|
6192
|
+
const correlationToClear = this.pstnCorrelationId;
|
6193
|
+
|
6161
6194
|
return Promise.all([
|
6162
6195
|
this.isPhoneProvisioned(this.dialInDeviceStatus)
|
6163
6196
|
? MeetingUtil.disconnectPhoneAudio(this, this.dialInUrl)
|
@@ -6165,7 +6198,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6165
6198
|
this.isPhoneProvisioned(this.dialOutDeviceStatus)
|
6166
6199
|
? MeetingUtil.disconnectPhoneAudio(this, this.dialOutUrl)
|
6167
6200
|
: Promise.resolve(),
|
6168
|
-
])
|
6201
|
+
]).then(() => {
|
6202
|
+
if (this.pstnCorrelationId === correlationToClear) {
|
6203
|
+
this.pstnCorrelationId = undefined;
|
6204
|
+
}
|
6205
|
+
});
|
6169
6206
|
}
|
6170
6207
|
|
6171
6208
|
/**
|
@@ -8387,6 +8424,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8387
8424
|
}
|
8388
8425
|
|
8389
8426
|
if (whiteboard) {
|
8427
|
+
// @ts-ignore
|
8428
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
8429
|
+
key: 'internal.client.share.initiated',
|
8430
|
+
});
|
8390
8431
|
// @ts-ignore
|
8391
8432
|
this.webex.internal.newMetrics.submitClientEvent({
|
8392
8433
|
name: 'client.share.initiated',
|
@@ -8446,11 +8487,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8446
8487
|
const whiteboard = this.locusInfo.mediaShares.find((element) => element.name === 'whiteboard');
|
8447
8488
|
|
8448
8489
|
if (whiteboard) {
|
8490
|
+
// @ts-ignore
|
8491
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
8492
|
+
key: 'internal.client.share.stopped',
|
8493
|
+
});
|
8449
8494
|
// @ts-ignore
|
8450
8495
|
this.webex.internal.newMetrics.submitClientEvent({
|
8451
8496
|
name: 'client.share.stopped',
|
8452
8497
|
payload: {
|
8453
8498
|
mediaType: 'whiteboard',
|
8499
|
+
// @ts-ignore
|
8500
|
+
shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
|
8454
8501
|
},
|
8455
8502
|
options: {
|
8456
8503
|
meetingId: this.id,
|
@@ -8608,12 +8655,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8608
8655
|
}
|
8609
8656
|
this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
|
8610
8657
|
if (content) {
|
8658
|
+
// @ts-ignore
|
8659
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
8660
|
+
key: 'internal.client.share.stopped',
|
8661
|
+
});
|
8611
8662
|
// @ts-ignore
|
8612
8663
|
this.webex.internal.newMetrics.submitClientEvent({
|
8613
8664
|
name: 'client.share.stopped',
|
8614
8665
|
payload: {
|
8615
8666
|
mediaType: 'share',
|
8616
8667
|
shareInstanceId: this.localShareInstanceId,
|
8668
|
+
// @ts-ignore
|
8669
|
+
shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
|
8617
8670
|
},
|
8618
8671
|
options: {meetingId: this.id},
|
8619
8672
|
});
|
@@ -9590,6 +9643,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
9590
9643
|
this.shareCAEventSentStatus.transmitStart = false;
|
9591
9644
|
this.shareCAEventSentStatus.transmitStop = false;
|
9592
9645
|
|
9646
|
+
// @ts-ignore
|
9647
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
9648
|
+
key: 'internal.client.share.initiated',
|
9649
|
+
});
|
9650
|
+
|
9593
9651
|
// @ts-ignore
|
9594
9652
|
this.webex.internal.newMetrics.submitClientEvent({
|
9595
9653
|
name: 'client.share.initiated',
|
@@ -9763,4 +9821,73 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
9763
9821
|
selected_subnet: selectedSubnetFirstOctet ? `${selectedSubnetFirstOctet}.X.X.X` : null,
|
9764
9822
|
};
|
9765
9823
|
}
|
9824
|
+
|
9825
|
+
/**
|
9826
|
+
* Set the stage for the meeting
|
9827
|
+
*
|
9828
|
+
* @param {SetStageOptions} options Options to use when setting the stage
|
9829
|
+
* @returns {Promise} The locus request
|
9830
|
+
*/
|
9831
|
+
setStage({
|
9832
|
+
activeSpeakerProportion = 0.5,
|
9833
|
+
customBackground,
|
9834
|
+
customLogo,
|
9835
|
+
customNameLabel,
|
9836
|
+
importantParticipants,
|
9837
|
+
lockAttendeeViewOnStage = false,
|
9838
|
+
showActiveSpeaker = false,
|
9839
|
+
}: SetStageOptions = {}) {
|
9840
|
+
const videoLayout: SetStageVideoLayout = {
|
9841
|
+
overrideDefault: true,
|
9842
|
+
lockAttendeeViewOnStageOnly: lockAttendeeViewOnStage,
|
9843
|
+
stageParameters: {
|
9844
|
+
activeSpeakerProportion,
|
9845
|
+
showActiveSpeaker: {show: showActiveSpeaker, order: 0},
|
9846
|
+
stageManagerType: 0,
|
9847
|
+
},
|
9848
|
+
};
|
9849
|
+
|
9850
|
+
if (importantParticipants?.length) {
|
9851
|
+
videoLayout.stageParameters.importantParticipants = importantParticipants.map(
|
9852
|
+
(importantParticipant, index) => ({...importantParticipant, order: index + 1})
|
9853
|
+
);
|
9854
|
+
}
|
9855
|
+
|
9856
|
+
if (customLogo) {
|
9857
|
+
if (!videoLayout.customLayouts) {
|
9858
|
+
videoLayout.customLayouts = {};
|
9859
|
+
}
|
9860
|
+
videoLayout.customLayouts.logo = customLogo;
|
9861
|
+
// eslint-disable-next-line no-bitwise
|
9862
|
+
videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.LOGO;
|
9863
|
+
}
|
9864
|
+
|
9865
|
+
if (customBackground) {
|
9866
|
+
if (!videoLayout.customLayouts) {
|
9867
|
+
videoLayout.customLayouts = {};
|
9868
|
+
}
|
9869
|
+
videoLayout.customLayouts.background = customBackground;
|
9870
|
+
// eslint-disable-next-line no-bitwise
|
9871
|
+
videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.BACKGROUND;
|
9872
|
+
}
|
9873
|
+
|
9874
|
+
if (customNameLabel) {
|
9875
|
+
videoLayout.nameLabelStyle = customNameLabel;
|
9876
|
+
// eslint-disable-next-line no-bitwise
|
9877
|
+
videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.NAME_LABEL;
|
9878
|
+
}
|
9879
|
+
|
9880
|
+
return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
|
9881
|
+
}
|
9882
|
+
|
9883
|
+
/**
|
9884
|
+
* Unset the stage for the meeting
|
9885
|
+
*
|
9886
|
+
* @returns {Promise} The locus request
|
9887
|
+
*/
|
9888
|
+
unsetStage() {
|
9889
|
+
const videoLayout: UnsetStageVideoLayout = {overrideDefault: false};
|
9890
|
+
|
9891
|
+
return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
|
9892
|
+
}
|
9766
9893
|
}
|
package/src/meeting/request.ts
CHANGED
@@ -32,6 +32,7 @@ import {
|
|
32
32
|
BrbOptions,
|
33
33
|
ToggleReactionsOptions,
|
34
34
|
PostMeetingDataConsentOptions,
|
35
|
+
SynchronizeVideoLayout,
|
35
36
|
} from './request.type';
|
36
37
|
import MeetingUtil from './util';
|
37
38
|
import {AnnotationInfo} from '../annotation/annotation.types';
|
@@ -969,4 +970,19 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
969
970
|
},
|
970
971
|
});
|
971
972
|
}
|
973
|
+
|
974
|
+
/**
|
975
|
+
* Synchronize the stage for a meeting
|
976
|
+
*
|
977
|
+
* @param {LocusUrl} locusUrl The locus URL
|
978
|
+
* @param {SetStageVideoLayout} videoLayout The video layout to synchronize
|
979
|
+
* @returns {Promise} The locus request
|
980
|
+
*/
|
981
|
+
synchronizeStage(locusUrl: string, videoLayout: SynchronizeVideoLayout) {
|
982
|
+
return this.locusDeltaRequest({
|
983
|
+
method: HTTP_VERBS.PATCH,
|
984
|
+
uri: `${locusUrl}/${CONTROLS}`,
|
985
|
+
body: {videoLayout},
|
986
|
+
});
|
987
|
+
}
|
972
988
|
}
|
@@ -25,3 +25,67 @@ export type PostMeetingDataConsentOptions = {
|
|
25
25
|
deviceUrl: string;
|
26
26
|
selfId: string;
|
27
27
|
};
|
28
|
+
|
29
|
+
export type StageCustomLogoPositions =
|
30
|
+
| 'LowerLeft'
|
31
|
+
| 'LowerMiddle'
|
32
|
+
| 'LowerRight'
|
33
|
+
| 'UpperLeft'
|
34
|
+
| 'UpperMiddle'
|
35
|
+
| 'UpperRight';
|
36
|
+
|
37
|
+
export type StageNameLabelType = 'Primary' | 'PrimaryInverted' | 'Secondary' | 'SecondaryInverted';
|
38
|
+
|
39
|
+
export type StageCustomBackground = {
|
40
|
+
url: string;
|
41
|
+
[others: string]: unknown;
|
42
|
+
};
|
43
|
+
|
44
|
+
export type StageCustomLogo = {
|
45
|
+
url: string;
|
46
|
+
position: StageCustomLogoPositions;
|
47
|
+
[others: string]: unknown;
|
48
|
+
};
|
49
|
+
|
50
|
+
export type StageCustomNameLabel = {
|
51
|
+
accentColor: string;
|
52
|
+
background: {color: string};
|
53
|
+
border: {color: string};
|
54
|
+
content: {displayName: {color: string}; subtitle: {color: string}};
|
55
|
+
decoration: {color: string};
|
56
|
+
fadeOut?: {delay: number};
|
57
|
+
type: StageNameLabelType;
|
58
|
+
[others: string]: unknown;
|
59
|
+
};
|
60
|
+
|
61
|
+
export type SetStageOptions = {
|
62
|
+
activeSpeakerProportion?: number;
|
63
|
+
customBackground?: StageCustomBackground;
|
64
|
+
customLogo?: StageCustomLogo;
|
65
|
+
customNameLabel?: StageCustomNameLabel;
|
66
|
+
importantParticipants?: {mainCsi: number; participantId: string}[];
|
67
|
+
lockAttendeeViewOnStage?: boolean;
|
68
|
+
showActiveSpeaker?: boolean;
|
69
|
+
};
|
70
|
+
|
71
|
+
export type SetStageVideoLayout = {
|
72
|
+
overrideDefault: true;
|
73
|
+
lockAttendeeViewOnStageOnly: boolean;
|
74
|
+
stageParameters: {
|
75
|
+
importantParticipants?: {participantId: string; mainCsi: number; order: number}[];
|
76
|
+
showActiveSpeaker: {show: boolean; order: number};
|
77
|
+
activeSpeakerProportion: number;
|
78
|
+
stageManagerType: number;
|
79
|
+
};
|
80
|
+
customLayouts?: {
|
81
|
+
background?: StageCustomBackground;
|
82
|
+
logo?: StageCustomLogo;
|
83
|
+
};
|
84
|
+
nameLabelStyle?: StageCustomNameLabel;
|
85
|
+
};
|
86
|
+
|
87
|
+
export type UnsetStageVideoLayout = {
|
88
|
+
overrideDefault: false;
|
89
|
+
};
|
90
|
+
|
91
|
+
export type SynchronizeVideoLayout = SetStageVideoLayout | UnsetStageVideoLayout;
|
package/src/meeting/util.ts
CHANGED
@@ -197,6 +197,17 @@ const MeetingUtil = {
|
|
197
197
|
});
|
198
198
|
|
199
199
|
return parsed;
|
200
|
+
})
|
201
|
+
.catch((err) => {
|
202
|
+
webex.internal.newMetrics.submitClientEvent({
|
203
|
+
name: 'client.locus.join.response',
|
204
|
+
payload: {
|
205
|
+
identifiers: {meetingLookupUrl: meeting.meetingInfo?.meetingLookupUrl},
|
206
|
+
},
|
207
|
+
options: {meetingId: meeting.id, rawError: err},
|
208
|
+
});
|
209
|
+
|
210
|
+
throw err;
|
200
211
|
});
|
201
212
|
},
|
202
213
|
|
@@ -208,6 +219,10 @@ const MeetingUtil = {
|
|
208
219
|
meeting.simultaneousInterpretation.cleanUp();
|
209
220
|
meeting.locusMediaRequest = undefined;
|
210
221
|
|
222
|
+
meeting.webex?.internal?.newMetrics?.callDiagnosticMetrics?.clearEventLimitsForCorrelationId(
|
223
|
+
meeting.correlationId
|
224
|
+
);
|
225
|
+
|
211
226
|
// make sure we send last metrics before we close the peerconnection
|
212
227
|
const stopStatsAnalyzer = meeting.statsAnalyzer
|
213
228
|
? meeting.statsAnalyzer.stopAnalyzer()
|
@@ -328,10 +343,57 @@ const MeetingUtil = {
|
|
328
343
|
meeting.resourceId = meeting.resourceId || options.resourceId;
|
329
344
|
|
330
345
|
if (meeting.requiredCaptcha) {
|
331
|
-
|
346
|
+
const errorToThrow = new CaptchaError();
|
347
|
+
|
348
|
+
// @ts-ignore
|
349
|
+
webex.internal.newMetrics.submitClientEvent({
|
350
|
+
name: 'client.meetinginfo.response',
|
351
|
+
options: {
|
352
|
+
meetingId: meeting.id,
|
353
|
+
},
|
354
|
+
payload: {
|
355
|
+
errors: [
|
356
|
+
{
|
357
|
+
fatal: false,
|
358
|
+
category: 'expected',
|
359
|
+
name: 'other',
|
360
|
+
shownToUser: false,
|
361
|
+
errorCode: errorToThrow.code,
|
362
|
+
errorDescription: errorToThrow.name,
|
363
|
+
rawErrorMessage: errorToThrow.sdkMessage,
|
364
|
+
},
|
365
|
+
],
|
366
|
+
},
|
367
|
+
});
|
368
|
+
|
369
|
+
return Promise.reject(errorToThrow);
|
332
370
|
}
|
371
|
+
|
333
372
|
if (meeting.passwordStatus === PASSWORD_STATUS.REQUIRED) {
|
334
|
-
|
373
|
+
const errorToThrow = new PasswordError();
|
374
|
+
|
375
|
+
// @ts-ignore
|
376
|
+
webex.internal.newMetrics.submitClientEvent({
|
377
|
+
name: 'client.meetinginfo.response',
|
378
|
+
options: {
|
379
|
+
meetingId: meeting.id,
|
380
|
+
},
|
381
|
+
payload: {
|
382
|
+
errors: [
|
383
|
+
{
|
384
|
+
fatal: false,
|
385
|
+
category: 'expected',
|
386
|
+
name: 'other',
|
387
|
+
shownToUser: false,
|
388
|
+
errorCode: errorToThrow.code,
|
389
|
+
errorDescription: errorToThrow.name,
|
390
|
+
rawErrorMessage: errorToThrow.sdkMessage,
|
391
|
+
},
|
392
|
+
],
|
393
|
+
},
|
394
|
+
});
|
395
|
+
|
396
|
+
return Promise.reject(errorToThrow);
|
335
397
|
}
|
336
398
|
|
337
399
|
if (options.pin) {
|
@@ -542,6 +604,15 @@ const MeetingUtil = {
|
|
542
604
|
canStartManualCaption: (displayHints) =>
|
543
605
|
displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_START),
|
544
606
|
|
607
|
+
isLocalRecordingStarted: (displayHints) =>
|
608
|
+
displayHints.includes(DISPLAY_HINTS.LOCAL_RECORDING_STATUS_STARTED),
|
609
|
+
|
610
|
+
isLocalRecordingStopped: (displayHints) =>
|
611
|
+
displayHints.includes(DISPLAY_HINTS.LOCAL_RECORDING_STATUS_STOPPED),
|
612
|
+
|
613
|
+
isLocalRecordingPaused: (displayHints) =>
|
614
|
+
displayHints.includes(DISPLAY_HINTS.LOCAL_RECORDING_STATUS_PAUSED),
|
615
|
+
|
545
616
|
canStopManualCaption: (displayHints) => displayHints.includes(DISPLAY_HINTS.MANUAL_CAPTION_STOP),
|
546
617
|
|
547
618
|
isManualCaptionActive: (displayHints) =>
|
package/src/meetings/index.ts
CHANGED
@@ -1560,11 +1560,12 @@ export default class Meetings extends WebexPlugin {
|
|
1560
1560
|
{
|
1561
1561
|
// @ts-ignore
|
1562
1562
|
parent: this.webex,
|
1563
|
+
},
|
1564
|
+
(newMeeting) => {
|
1565
|
+
this.meetingCollection.set(newMeeting);
|
1563
1566
|
}
|
1564
1567
|
);
|
1565
1568
|
|
1566
|
-
this.meetingCollection.set(meeting);
|
1567
|
-
|
1568
1569
|
try {
|
1569
1570
|
// if no participant has joined the scheduled meeting (meaning meeting is not active) and we get a locusEvent,
|
1570
1571
|
// it means the meeting will start in 5-6 min. In that case, we want to fetchMeetingInfo
|
package/src/member/index.ts
CHANGED