@webex/plugin-meetings 3.8.1-web-workers-keepalive.1 → 3.9.0-multipleLLM.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 +26 -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 +77 -95
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +4 -1
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/media/properties.js +53 -5
- package/dist/media/properties.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 +8 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +443 -225
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +2 -5
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +44 -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 +98 -13
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +29 -21
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +18 -10
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/members/collection.js +13 -0
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +53 -29
- 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 +25 -8
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.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/reachability/index.js +3 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/types/constants.d.ts +24 -0
- package/dist/types/locus-info/index.d.ts +54 -10
- package/dist/types/media/properties.d.ts +21 -0
- package/dist/types/meeting/brbState.d.ts +0 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +8 -0
- package/dist/types/meeting/index.d.ts +51 -20
- package/dist/types/meeting/request.d.ts +18 -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 +13 -3
- package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
- package/dist/types/meetings/index.d.ts +3 -1
- package/dist/types/member/types.d.ts +1 -0
- package/dist/types/members/collection.d.ts +6 -0
- package/dist/types/members/index.d.ts +22 -9
- package/dist/types/members/request.d.ts +1 -1
- package/dist/types/members/util.d.ts +13 -6
- package/dist/types/metrics/constants.d.ts +1 -0
- 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 +23 -24
- package/src/constants.ts +25 -2
- package/src/locus-info/index.ts +133 -96
- package/src/locus-info/parser.ts +5 -1
- package/src/media/properties.ts +43 -0
- package/src/meeting/brbState.ts +9 -7
- package/src/meeting/in-meeting-actions.ts +17 -0
- package/src/meeting/index.ts +273 -42
- package/src/meeting/muteState.ts +2 -6
- package/src/meeting/request.ts +39 -0
- package/src/meeting/request.type.ts +64 -0
- package/src/meeting/type.ts +9 -0
- package/src/meeting/util.ts +114 -22
- package/src/meeting-info/meeting-info-v2.ts +24 -5
- package/src/meetings/index.ts +12 -5
- package/src/member/index.ts +1 -0
- package/src/member/types.ts +1 -0
- package/src/members/collection.ts +11 -0
- package/src/members/index.ts +51 -15
- package/src/members/request.ts +2 -2
- package/src/members/util.ts +34 -6
- package/src/metrics/constants.ts +1 -0
- 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/src/reachability/index.ts +3 -3
- package/test/unit/spec/locus-info/index.js +229 -98
- package/test/unit/spec/locus-info/parser.js +3 -2
- package/test/unit/spec/media/properties.ts +137 -0
- package/test/unit/spec/meeting/brbState.ts +9 -9
- package/test/unit/spec/meeting/in-meeting-actions.ts +8 -0
- package/test/unit/spec/meeting/index.js +1022 -93
- package/test/unit/spec/meeting/muteState.js +32 -6
- package/test/unit/spec/meeting/request.js +92 -0
- package/test/unit/spec/meeting/utils.js +167 -17
- package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
- package/test/unit/spec/meetings/index.js +12 -1
- package/test/unit/spec/members/collection.js +120 -0
- package/test/unit/spec/members/index.js +140 -12
- package/test/unit/spec/members/request.js +57 -2
- package/test/unit/spec/members/utils.js +139 -17
- 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 +158 -1
package/src/meeting/index.ts
CHANGED
@@ -28,6 +28,8 @@ import {
|
|
28
28
|
StatsAnalyzerEventNames,
|
29
29
|
NetworkQualityEventNames,
|
30
30
|
NetworkQualityMonitor,
|
31
|
+
StatsMonitor,
|
32
|
+
StatsMonitorEventNames,
|
31
33
|
} from '@webex/internal-media-core';
|
32
34
|
|
33
35
|
import {
|
@@ -121,6 +123,7 @@ import {
|
|
121
123
|
WEBINAR_ERROR_REGISTRATION_ID,
|
122
124
|
JOIN_BEFORE_HOST,
|
123
125
|
REGISTRATION_ID_STATUS,
|
126
|
+
STAGE_MANAGER_TYPE,
|
124
127
|
} from '../constants';
|
125
128
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
126
129
|
import ParameterError from '../common/errors/parameter';
|
@@ -164,6 +167,8 @@ import {BrbState, createBrbState} from './brbState';
|
|
164
167
|
import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error';
|
165
168
|
import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
166
169
|
import {ReachabilityMetrics} from '../reachability/reachability.types';
|
170
|
+
import {SetStageOptions, SetStageVideoLayout, UnsetStageVideoLayout} from './request.type';
|
171
|
+
import {Invitee} from './type';
|
167
172
|
|
168
173
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
169
174
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
@@ -248,6 +253,7 @@ export type CallStateForMetrics = {
|
|
248
253
|
loginType?: string;
|
249
254
|
userNameInput?: string;
|
250
255
|
emailInput?: string;
|
256
|
+
pstnCorrelationId?: string;
|
251
257
|
};
|
252
258
|
|
253
259
|
export const MEDIA_UPDATE_TYPE = {
|
@@ -265,6 +271,7 @@ export enum ScreenShareFloorStatus {
|
|
265
271
|
type FetchMeetingInfoParams = {
|
266
272
|
password?: string;
|
267
273
|
registrationId?: string;
|
274
|
+
classificationId?: string;
|
268
275
|
captchaCode?: string;
|
269
276
|
extraParams?: Record<string, any>;
|
270
277
|
sendCAevents?: boolean;
|
@@ -629,6 +636,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
629
636
|
shareStatus: string;
|
630
637
|
screenShareFloorState: ScreenShareFloorStatus;
|
631
638
|
statsAnalyzer: StatsAnalyzer;
|
639
|
+
statsMonitor: StatsMonitor;
|
632
640
|
transcription: Transcription;
|
633
641
|
updateMediaConnections: (mediaConnections: any[]) => void;
|
634
642
|
userDisplayHints: any;
|
@@ -741,10 +749,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
741
749
|
/**
|
742
750
|
* @param {Object} attrs
|
743
751
|
* @param {Object} options
|
752
|
+
* @param {Function} callback - if provided, it will be called with the newly created meeting object as soon as the meeting.id is set
|
744
753
|
* @constructor
|
745
754
|
* @memberof Meeting
|
746
755
|
*/
|
747
|
-
constructor(attrs: any, options: object) {
|
756
|
+
constructor(attrs: any, options: object, callback: (meeting: Meeting) => void) {
|
748
757
|
super({}, options);
|
749
758
|
/**
|
750
759
|
* @instance
|
@@ -770,6 +779,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
770
779
|
* @memberof Meeting
|
771
780
|
*/
|
772
781
|
this.id = uuid.v4();
|
782
|
+
|
783
|
+
if (callback) {
|
784
|
+
callback(this);
|
785
|
+
}
|
786
|
+
|
773
787
|
/**
|
774
788
|
* Call state used for metrics
|
775
789
|
* @instance
|
@@ -1276,6 +1290,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1276
1290
|
* @memberof Meeting
|
1277
1291
|
*/
|
1278
1292
|
this.networkQualityMonitor = null;
|
1293
|
+
/**
|
1294
|
+
* @instance
|
1295
|
+
* @type {StatsMonitor}
|
1296
|
+
* @private
|
1297
|
+
* @memberof Meeting
|
1298
|
+
*/
|
1299
|
+
this.statsMonitor = null;
|
1279
1300
|
/**
|
1280
1301
|
* Indicates network status of the webrtc media connection
|
1281
1302
|
* @instance
|
@@ -1674,6 +1695,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1674
1695
|
this.callStateForMetrics.correlationId = correlationId;
|
1675
1696
|
}
|
1676
1697
|
|
1698
|
+
/**
|
1699
|
+
* Getter - Returns callStateForMetrics.pstnCorrelationId
|
1700
|
+
* @returns {string | undefined}
|
1701
|
+
*/
|
1702
|
+
get pstnCorrelationId(): string | undefined {
|
1703
|
+
return this.callStateForMetrics.pstnCorrelationId;
|
1704
|
+
}
|
1705
|
+
|
1706
|
+
/**
|
1707
|
+
* Setter - sets callStateForMetrics.pstnCorrelationId
|
1708
|
+
* @param {string | undefined} correlationId
|
1709
|
+
*/
|
1710
|
+
set pstnCorrelationId(correlationId: string | undefined) {
|
1711
|
+
this.callStateForMetrics.pstnCorrelationId = correlationId;
|
1712
|
+
}
|
1713
|
+
|
1677
1714
|
/**
|
1678
1715
|
* Getter - Returns callStateForMetrics.userNameInput
|
1679
1716
|
* @returns {string}
|
@@ -1876,6 +1913,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1876
1913
|
extraParams = {},
|
1877
1914
|
sendCAevents = false,
|
1878
1915
|
registrationId = null,
|
1916
|
+
classificationId = null,
|
1879
1917
|
}): Promise<void> {
|
1880
1918
|
try {
|
1881
1919
|
const captchaInfo = captchaCode
|
@@ -1892,7 +1930,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1892
1930
|
this.locusId,
|
1893
1931
|
extraParams,
|
1894
1932
|
{meetingId: this.id, sendCAevents},
|
1895
|
-
registrationId
|
1933
|
+
registrationId,
|
1934
|
+
null,
|
1935
|
+
classificationId
|
1896
1936
|
);
|
1897
1937
|
|
1898
1938
|
this.parseMeetingInfo(info?.body, this.destination, info?.errors);
|
@@ -3056,12 +3096,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3056
3096
|
// There is no concept of local/remote share for whiteboard
|
3057
3097
|
// It does not matter who requested to share the whiteboard, everyone gets the same view
|
3058
3098
|
else if (whiteboardShare.disposition === FLOOR_ACTION.GRANTED) {
|
3059
|
-
|
3060
|
-
|
3061
|
-
|
3062
|
-
|
3063
|
-
|
3064
|
-
|
3099
|
+
if (this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee) {
|
3100
|
+
// WHITEBOARD - sharing whiteboard
|
3101
|
+
// Webinar attendee should receive whiteboard as remote share
|
3102
|
+
newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
|
3103
|
+
} else if (this.guest) {
|
3104
|
+
// If user is a guest to a meeting, they should receive whiteboard as remote share
|
3105
|
+
newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
|
3106
|
+
} else {
|
3107
|
+
newShareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
3108
|
+
}
|
3065
3109
|
}
|
3066
3110
|
// or if content share is either released or null and whiteboard share is either released or null, no one is sharing
|
3067
3111
|
else if (
|
@@ -3119,6 +3163,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3119
3163
|
},
|
3120
3164
|
EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD
|
3121
3165
|
);
|
3166
|
+
// @ts-ignore
|
3167
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
3168
|
+
key: 'internal.client.share.stopped',
|
3169
|
+
});
|
3170
|
+
// @ts-ignore
|
3171
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
3172
|
+
name: 'client.share.stopped',
|
3173
|
+
payload: {
|
3174
|
+
mediaType: 'whiteboard',
|
3175
|
+
shareDuration:
|
3176
|
+
// @ts-ignore
|
3177
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
|
3178
|
+
},
|
3179
|
+
options: {
|
3180
|
+
meetingId: this.id,
|
3181
|
+
},
|
3182
|
+
});
|
3122
3183
|
break;
|
3123
3184
|
|
3124
3185
|
case SHARE_STATUS.NO_SHARE:
|
@@ -3137,6 +3198,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3137
3198
|
this.shareCAEventSentStatus.receiveStart = false;
|
3138
3199
|
this.shareCAEventSentStatus.receiveStop = false;
|
3139
3200
|
|
3201
|
+
let finalBeneficiaryId = contentShare.beneficiaryId;
|
3202
|
+
// In case of attendee in webinar, the whiteboard is shared by other participants
|
3203
|
+
if (this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee) {
|
3204
|
+
if (!finalBeneficiaryId && whiteboardShare.beneficiaryId) {
|
3205
|
+
finalBeneficiaryId = whiteboardShare.beneficiaryId;
|
3206
|
+
}
|
3207
|
+
}
|
3208
|
+
|
3140
3209
|
Trigger.trigger(
|
3141
3210
|
this,
|
3142
3211
|
{
|
@@ -3145,7 +3214,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3145
3214
|
},
|
3146
3215
|
EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
3147
3216
|
{
|
3148
|
-
memberId:
|
3217
|
+
memberId: finalBeneficiaryId,
|
3149
3218
|
url: contentShare.url,
|
3150
3219
|
shareInstanceId: this.remoteShareInstanceId,
|
3151
3220
|
annotationInfo: contentShare.annotation,
|
@@ -3827,49 +3896,44 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3827
3896
|
|
3828
3897
|
/**
|
3829
3898
|
* Invite a guest to the call that isn't normally part of this call
|
3830
|
-
* @param {
|
3899
|
+
* @param {Invitee} invitee
|
3831
3900
|
* @param {String} invitee.emailAddress
|
3832
3901
|
* @param {String} invitee.email
|
3833
3902
|
* @param {String} invitee.phoneNumber
|
3834
3903
|
* @param {Boolean} [alertIfActive]
|
3904
|
+
* @param {Boolean} [invitee.skipEmailValidation]
|
3905
|
+
* @param {Boolean} [invitee.isInternalNumber]
|
3835
3906
|
* @returns {Promise} see #members.addMember
|
3836
3907
|
* @public
|
3837
3908
|
* @memberof Meeting
|
3838
3909
|
*/
|
3839
|
-
public invite(
|
3840
|
-
invitee: {
|
3841
|
-
emailAddress: string;
|
3842
|
-
email: string;
|
3843
|
-
phoneNumber: string;
|
3844
|
-
roles: Array<string>;
|
3845
|
-
},
|
3846
|
-
alertIfActive = true
|
3847
|
-
) {
|
3910
|
+
public invite(invitee: Invitee, alertIfActive = true) {
|
3848
3911
|
return this.members.addMember(invitee, alertIfActive);
|
3849
3912
|
}
|
3850
3913
|
|
3851
3914
|
/**
|
3852
3915
|
* Cancel an outgoing phone call invitation made during a meeting
|
3853
|
-
* @param {
|
3916
|
+
* @param {Invitee} invitee
|
3854
3917
|
* @param {String} invitee.phoneNumber
|
3855
3918
|
* @returns {Promise} see #members.cancelPhoneInvite
|
3856
3919
|
* @public
|
3857
3920
|
* @memberof Meeting
|
3858
3921
|
*/
|
3859
|
-
public cancelPhoneInvite(invitee:
|
3922
|
+
public cancelPhoneInvite(invitee: Invitee) {
|
3860
3923
|
return this.members.cancelPhoneInvite(invitee);
|
3861
3924
|
}
|
3862
3925
|
|
3863
3926
|
/**
|
3864
|
-
* Cancel an SIP call invitation made during a meeting
|
3865
|
-
* @param {
|
3927
|
+
* Cancel an SIP/phone call invitation made during a meeting
|
3928
|
+
* @param {Invitee} invitee
|
3866
3929
|
* @param {String} invitee.memberId
|
3867
|
-
* @
|
3930
|
+
* @param {Boolean} [invitee.isInternalNumber] - When cancel phone invitation, if the number is internal
|
3931
|
+
* @returns {Promise} see #members.cancelInviteByMemberId
|
3868
3932
|
* @public
|
3869
3933
|
* @memberof Meeting
|
3870
3934
|
*/
|
3871
|
-
public
|
3872
|
-
return this.members.
|
3935
|
+
public cancelInviteByMemberId(invitee: Invitee) {
|
3936
|
+
return this.members.cancelInviteByMemberId(invitee);
|
3873
3937
|
}
|
3874
3938
|
|
3875
3939
|
/**
|
@@ -4167,8 +4231,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4167
4231
|
isClosedCaptionActive: MeetingUtil.isClosedCaptionActive(this.userDisplayHints),
|
4168
4232
|
canStartManualCaption: MeetingUtil.canStartManualCaption(this.userDisplayHints),
|
4169
4233
|
canStopManualCaption: MeetingUtil.canStopManualCaption(this.userDisplayHints),
|
4234
|
+
isLocalRecordingStarted: MeetingUtil.isLocalRecordingStarted(this.userDisplayHints),
|
4235
|
+
isLocalRecordingStopped: MeetingUtil.isLocalRecordingStopped(this.userDisplayHints),
|
4236
|
+
isLocalRecordingPaused: MeetingUtil.isLocalRecordingPaused(this.userDisplayHints),
|
4170
4237
|
isManualCaptionActive: MeetingUtil.isManualCaptionActive(this.userDisplayHints),
|
4171
4238
|
isSaveTranscriptsEnabled: MeetingUtil.isSaveTranscriptsEnabled(this.userDisplayHints),
|
4239
|
+
isSpokenLanguageAutoDetectionEnabled: MeetingUtil.isSpokenLanguageAutoDetectionEnabled(
|
4240
|
+
this.userDisplayHints
|
4241
|
+
),
|
4172
4242
|
isWebexAssistantActive: MeetingUtil.isWebexAssistantActive(this.userDisplayHints),
|
4173
4243
|
canViewCaptionPanel: MeetingUtil.canViewCaptionPanel(this.userDisplayHints),
|
4174
4244
|
isRealTimeTranslationEnabled: MeetingUtil.isRealTimeTranslationEnabled(
|
@@ -5924,15 +5994,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
5924
5994
|
this.meetingFiniteStateMachine.fail(error);
|
5925
5995
|
LoggerProxy.logger.error('Meeting:index#join --> Failed', error);
|
5926
5996
|
|
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
5997
|
// TODO: change this to error codes and pre defined dictionary
|
5937
5998
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_FAILURE, {
|
5938
5999
|
correlation_id: this.correlationId,
|
@@ -6082,8 +6143,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6082
6143
|
*/
|
6083
6144
|
private dialInPstn() {
|
6084
6145
|
if (this.isPhoneProvisioned(this.dialInDeviceStatus)) return Promise.resolve(); // prevent multiple dial in devices from being provisioned
|
6146
|
+
this.pstnCorrelationId = uuid.v4();
|
6085
6147
|
|
6086
|
-
const {
|
6148
|
+
const {pstnCorrelationId, locusUrl} = this;
|
6087
6149
|
|
6088
6150
|
if (!this.dialInUrl) this.dialInUrl = `dialin:///${uuid.v4()}`;
|
6089
6151
|
|
@@ -6091,7 +6153,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6091
6153
|
this.meetingRequest
|
6092
6154
|
// @ts-ignore
|
6093
6155
|
.dialIn({
|
6094
|
-
correlationId,
|
6156
|
+
correlationId: pstnCorrelationId,
|
6095
6157
|
dialInUrl: this.dialInUrl,
|
6096
6158
|
locusUrl,
|
6097
6159
|
clientUrl: this.deviceUrl,
|
@@ -6100,12 +6162,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6100
6162
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
|
6101
6163
|
correlation_id: this.correlationId,
|
6102
6164
|
dial_in_url: this.dialInUrl,
|
6165
|
+
dial_in_correlation_id: pstnCorrelationId,
|
6103
6166
|
locus_id: locusUrl.split('/').pop(),
|
6104
6167
|
client_url: this.deviceUrl,
|
6105
6168
|
reason: error.error?.message,
|
6106
6169
|
stack: error.stack,
|
6107
6170
|
});
|
6108
6171
|
|
6172
|
+
if (this.pstnCorrelationId === pstnCorrelationId) {
|
6173
|
+
this.pstnCorrelationId = undefined;
|
6174
|
+
}
|
6175
|
+
|
6109
6176
|
return Promise.reject(error);
|
6110
6177
|
})
|
6111
6178
|
);
|
@@ -6120,8 +6187,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6120
6187
|
*/
|
6121
6188
|
private dialOutPstn(phoneNumber: string) {
|
6122
6189
|
if (this.isPhoneProvisioned(this.dialOutDeviceStatus)) return Promise.resolve(); // prevent multiple dial out devices from being provisioned
|
6190
|
+
this.pstnCorrelationId = uuid.v4();
|
6123
6191
|
|
6124
|
-
const {
|
6192
|
+
const {locusUrl, pstnCorrelationId} = this;
|
6125
6193
|
|
6126
6194
|
if (!this.dialOutUrl) this.dialOutUrl = `dialout:///${uuid.v4()}`;
|
6127
6195
|
|
@@ -6129,7 +6197,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6129
6197
|
this.meetingRequest
|
6130
6198
|
// @ts-ignore
|
6131
6199
|
.dialOut({
|
6132
|
-
correlationId,
|
6200
|
+
correlationId: pstnCorrelationId,
|
6133
6201
|
dialOutUrl: this.dialOutUrl,
|
6134
6202
|
phoneNumber,
|
6135
6203
|
locusUrl,
|
@@ -6139,12 +6207,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6139
6207
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
|
6140
6208
|
correlation_id: this.correlationId,
|
6141
6209
|
dial_out_url: this.dialOutUrl,
|
6210
|
+
dial_out_correlation_id: pstnCorrelationId,
|
6142
6211
|
locus_id: locusUrl.split('/').pop(),
|
6143
6212
|
client_url: this.deviceUrl,
|
6144
6213
|
reason: error.error?.message,
|
6145
6214
|
stack: error.stack,
|
6146
6215
|
});
|
6147
6216
|
|
6217
|
+
if (this.pstnCorrelationId === pstnCorrelationId) {
|
6218
|
+
this.pstnCorrelationId = undefined;
|
6219
|
+
}
|
6220
|
+
|
6148
6221
|
return Promise.reject(error);
|
6149
6222
|
})
|
6150
6223
|
);
|
@@ -6158,6 +6231,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6158
6231
|
* @returns {Promise}
|
6159
6232
|
*/
|
6160
6233
|
public disconnectPhoneAudio() {
|
6234
|
+
const correlationToClear = this.pstnCorrelationId;
|
6235
|
+
|
6161
6236
|
return Promise.all([
|
6162
6237
|
this.isPhoneProvisioned(this.dialInDeviceStatus)
|
6163
6238
|
? MeetingUtil.disconnectPhoneAudio(this, this.dialInUrl)
|
@@ -6165,7 +6240,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6165
6240
|
this.isPhoneProvisioned(this.dialOutDeviceStatus)
|
6166
6241
|
? MeetingUtil.disconnectPhoneAudio(this, this.dialOutUrl)
|
6167
6242
|
: Promise.resolve(),
|
6168
|
-
])
|
6243
|
+
]).then(() => {
|
6244
|
+
if (this.pstnCorrelationId === correlationToClear) {
|
6245
|
+
this.pstnCorrelationId = undefined;
|
6246
|
+
}
|
6247
|
+
});
|
6169
6248
|
}
|
6170
6249
|
|
6171
6250
|
/**
|
@@ -6742,6 +6821,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6742
6821
|
// @ts-ignore
|
6743
6822
|
this.webex.internal.newMetrics.submitClientEvent({
|
6744
6823
|
name: 'client.ice.start',
|
6824
|
+
payload: {
|
6825
|
+
// @ts-ignore
|
6826
|
+
labels: MeetingUtil.getCaEventLabelsForIpVersion(this.webex),
|
6827
|
+
},
|
6745
6828
|
options: {
|
6746
6829
|
meetingId: this.id,
|
6747
6830
|
},
|
@@ -6911,10 +6994,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6911
6994
|
}
|
6912
6995
|
}
|
6913
6996
|
|
6914
|
-
// Count members that are in the meeting.
|
6997
|
+
// Count members that are in the meeting or in the lobby.
|
6915
6998
|
const {members} = this.getMembers().membersCollection;
|
6916
6999
|
event.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
|
6917
|
-
(member: Member) => member.isInMeeting
|
7000
|
+
(member: Member) => member.isInMeeting || member.isInLobby
|
6918
7001
|
).length;
|
6919
7002
|
|
6920
7003
|
// @ts-ignore
|
@@ -7273,10 +7356,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7273
7356
|
if (this.config.stats.enableStatsAnalyzer) {
|
7274
7357
|
// @ts-ignore - config coming from registerPlugin
|
7275
7358
|
this.networkQualityMonitor = new NetworkQualityMonitor(this.config.stats);
|
7359
|
+
this.statsMonitor = new StatsMonitor();
|
7276
7360
|
this.statsAnalyzer = new StatsAnalyzer({
|
7277
7361
|
// @ts-ignore - config coming from registerPlugin
|
7278
7362
|
config: this.config.stats,
|
7279
7363
|
networkQualityMonitor: this.networkQualityMonitor,
|
7364
|
+
statsMonitor: this.statsMonitor,
|
7280
7365
|
isMultistream: this.isMultistream,
|
7281
7366
|
});
|
7282
7367
|
this.shareCAEventSentStatus = {
|
@@ -7290,6 +7375,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7290
7375
|
NetworkQualityEventNames.NETWORK_QUALITY,
|
7291
7376
|
this.sendNetworkQualityEvent.bind(this)
|
7292
7377
|
);
|
7378
|
+
|
7379
|
+
this.statsMonitor.on(StatsMonitorEventNames.INBOUND_AUDIO_ISSUE, (data) => {
|
7380
|
+
// Before forwarding any inbound audio issues to the app, make sure that we have at least one other
|
7381
|
+
// participant in the meeting with unmuted audio.
|
7382
|
+
// We don't check this.mediaProperties.mediaDirection here, because that's already handled in statsAnalyzer,
|
7383
|
+
// so we won't get this event if we are not setup to receive any audio
|
7384
|
+
const atLeastOneUnmutedOtherMember = Object.values(
|
7385
|
+
this.members.membersCollection.getAll()
|
7386
|
+
).find((member) => {
|
7387
|
+
return !member.isSelf && !member.isPairedWithSelf && !member.isAudioMuted;
|
7388
|
+
});
|
7389
|
+
|
7390
|
+
if (atLeastOneUnmutedOtherMember) {
|
7391
|
+
this.mediaProperties.sendMediaIssueMetric(
|
7392
|
+
'inbound_audio',
|
7393
|
+
data.issueSubType,
|
7394
|
+
this.correlationId
|
7395
|
+
);
|
7396
|
+
|
7397
|
+
Trigger.trigger(
|
7398
|
+
this,
|
7399
|
+
{file: 'meeting/index', function: 'createStatsAnalyzer'},
|
7400
|
+
EVENT_TRIGGERS.MEDIA_INBOUND_AUDIO_ISSUE_DETECTED,
|
7401
|
+
data
|
7402
|
+
);
|
7403
|
+
}
|
7404
|
+
});
|
7293
7405
|
}
|
7294
7406
|
}
|
7295
7407
|
|
@@ -7588,6 +7700,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7588
7700
|
}
|
7589
7701
|
|
7590
7702
|
this.statsAnalyzer = null;
|
7703
|
+
this.networkQualityMonitor?.removeAllListeners();
|
7704
|
+
this.networkQualityMonitor = null;
|
7705
|
+
this.statsMonitor?.removeAllListeners();
|
7706
|
+
this.statsMonitor = null;
|
7591
7707
|
|
7592
7708
|
// when media fails, we want to upload a webrtc dump to see whats going on
|
7593
7709
|
// this function is async, but returns once the stats have been gathered
|
@@ -7611,6 +7727,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7611
7727
|
await this.statsAnalyzer.stopAnalyzer();
|
7612
7728
|
}
|
7613
7729
|
this.statsAnalyzer = null;
|
7730
|
+
this.networkQualityMonitor?.removeAllListeners();
|
7731
|
+
this.networkQualityMonitor = null;
|
7732
|
+
this.statsMonitor?.removeAllListeners();
|
7733
|
+
this.statsMonitor = null;
|
7614
7734
|
|
7615
7735
|
this.isMultistream = false;
|
7616
7736
|
|
@@ -7782,6 +7902,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7782
7902
|
|
7783
7903
|
this.allowMediaInLobby = options?.allowMediaInLobby;
|
7784
7904
|
|
7905
|
+
// @ts-ignore
|
7906
|
+
const ipver = MeetingUtil.getIpVersion(this.webex); // used just for metrics
|
7907
|
+
|
7785
7908
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
7786
7909
|
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
7787
7910
|
if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
|
@@ -7880,6 +8003,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7880
8003
|
locus_id: this.locusUrl.split('/').pop(),
|
7881
8004
|
connectionType,
|
7882
8005
|
ipVersion,
|
8006
|
+
ipver,
|
7883
8007
|
selectedCandidatePairChanges,
|
7884
8008
|
numTransports,
|
7885
8009
|
isMultistream: this.isMultistream,
|
@@ -7948,6 +8072,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7948
8072
|
...reachabilityMetrics,
|
7949
8073
|
...iceCandidateErrors,
|
7950
8074
|
iceCandidatesCount: this.iceCandidatesCount,
|
8075
|
+
ipver,
|
7951
8076
|
});
|
7952
8077
|
|
7953
8078
|
await this.cleanUpOnAddMediaFailure();
|
@@ -8387,6 +8512,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8387
8512
|
}
|
8388
8513
|
|
8389
8514
|
if (whiteboard) {
|
8515
|
+
// @ts-ignore
|
8516
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
8517
|
+
key: 'internal.client.share.initiated',
|
8518
|
+
});
|
8390
8519
|
// @ts-ignore
|
8391
8520
|
this.webex.internal.newMetrics.submitClientEvent({
|
8392
8521
|
name: 'client.share.initiated',
|
@@ -8446,11 +8575,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8446
8575
|
const whiteboard = this.locusInfo.mediaShares.find((element) => element.name === 'whiteboard');
|
8447
8576
|
|
8448
8577
|
if (whiteboard) {
|
8578
|
+
// @ts-ignore
|
8579
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
8580
|
+
key: 'internal.client.share.stopped',
|
8581
|
+
});
|
8449
8582
|
// @ts-ignore
|
8450
8583
|
this.webex.internal.newMetrics.submitClientEvent({
|
8451
8584
|
name: 'client.share.stopped',
|
8452
8585
|
payload: {
|
8453
8586
|
mediaType: 'whiteboard',
|
8587
|
+
// @ts-ignore
|
8588
|
+
shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
|
8454
8589
|
},
|
8455
8590
|
options: {
|
8456
8591
|
meetingId: this.id,
|
@@ -8608,12 +8743,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8608
8743
|
}
|
8609
8744
|
this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
|
8610
8745
|
if (content) {
|
8746
|
+
// @ts-ignore
|
8747
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
8748
|
+
key: 'internal.client.share.stopped',
|
8749
|
+
});
|
8611
8750
|
// @ts-ignore
|
8612
8751
|
this.webex.internal.newMetrics.submitClientEvent({
|
8613
8752
|
name: 'client.share.stopped',
|
8614
8753
|
payload: {
|
8615
8754
|
mediaType: 'share',
|
8616
8755
|
shareInstanceId: this.localShareInstanceId,
|
8756
|
+
// @ts-ignore
|
8757
|
+
shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
|
8617
8758
|
},
|
8618
8759
|
options: {meetingId: this.id},
|
8619
8760
|
});
|
@@ -9590,6 +9731,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
9590
9731
|
this.shareCAEventSentStatus.transmitStart = false;
|
9591
9732
|
this.shareCAEventSentStatus.transmitStop = false;
|
9592
9733
|
|
9734
|
+
// @ts-ignore
|
9735
|
+
this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
|
9736
|
+
key: 'internal.client.share.initiated',
|
9737
|
+
});
|
9738
|
+
|
9593
9739
|
// @ts-ignore
|
9594
9740
|
this.webex.internal.newMetrics.submitClientEvent({
|
9595
9741
|
name: 'client.share.initiated',
|
@@ -9763,4 +9909,89 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
9763
9909
|
selected_subnet: selectedSubnetFirstOctet ? `${selectedSubnetFirstOctet}.X.X.X` : null,
|
9764
9910
|
};
|
9765
9911
|
}
|
9912
|
+
|
9913
|
+
/**
|
9914
|
+
* Set the stage for the meeting
|
9915
|
+
*
|
9916
|
+
* @param {SetStageOptions} options Options to use when setting the stage
|
9917
|
+
* @returns {Promise} The locus request
|
9918
|
+
*/
|
9919
|
+
setStage({
|
9920
|
+
activeSpeakerProportion = 0.5,
|
9921
|
+
customBackground,
|
9922
|
+
customLogo,
|
9923
|
+
customNameLabel,
|
9924
|
+
importantParticipants,
|
9925
|
+
lockAttendeeViewOnStage = false,
|
9926
|
+
showActiveSpeaker = false,
|
9927
|
+
}: SetStageOptions = {}) {
|
9928
|
+
const videoLayout: SetStageVideoLayout = {
|
9929
|
+
overrideDefault: true,
|
9930
|
+
lockAttendeeViewOnStageOnly: lockAttendeeViewOnStage,
|
9931
|
+
stageParameters: {
|
9932
|
+
activeSpeakerProportion,
|
9933
|
+
showActiveSpeaker: {show: showActiveSpeaker, order: 0},
|
9934
|
+
stageManagerType: 0,
|
9935
|
+
},
|
9936
|
+
};
|
9937
|
+
|
9938
|
+
if (importantParticipants?.length) {
|
9939
|
+
videoLayout.stageParameters.importantParticipants = importantParticipants.map(
|
9940
|
+
(importantParticipant, index) => ({...importantParticipant, order: index + 1})
|
9941
|
+
);
|
9942
|
+
}
|
9943
|
+
|
9944
|
+
if (customLogo) {
|
9945
|
+
if (!videoLayout.customLayouts) {
|
9946
|
+
videoLayout.customLayouts = {};
|
9947
|
+
}
|
9948
|
+
videoLayout.customLayouts.logo = customLogo;
|
9949
|
+
// eslint-disable-next-line no-bitwise
|
9950
|
+
videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.LOGO;
|
9951
|
+
}
|
9952
|
+
|
9953
|
+
if (customBackground) {
|
9954
|
+
if (!videoLayout.customLayouts) {
|
9955
|
+
videoLayout.customLayouts = {};
|
9956
|
+
}
|
9957
|
+
videoLayout.customLayouts.background = customBackground;
|
9958
|
+
// eslint-disable-next-line no-bitwise
|
9959
|
+
videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.BACKGROUND;
|
9960
|
+
}
|
9961
|
+
|
9962
|
+
if (customNameLabel) {
|
9963
|
+
videoLayout.nameLabelStyle = customNameLabel;
|
9964
|
+
// eslint-disable-next-line no-bitwise
|
9965
|
+
videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.NAME_LABEL;
|
9966
|
+
}
|
9967
|
+
|
9968
|
+
return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
|
9969
|
+
}
|
9970
|
+
|
9971
|
+
/**
|
9972
|
+
* Unset the stage for the meeting
|
9973
|
+
*
|
9974
|
+
* @returns {Promise} The locus request
|
9975
|
+
*/
|
9976
|
+
unsetStage() {
|
9977
|
+
const videoLayout: UnsetStageVideoLayout = {overrideDefault: false};
|
9978
|
+
|
9979
|
+
return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
|
9980
|
+
}
|
9981
|
+
|
9982
|
+
/**
|
9983
|
+
* Notifies the host with the given meeting UUID and display names.
|
9984
|
+
*
|
9985
|
+
* @param {string} meetingUuid - The UUID of the meeting.
|
9986
|
+
* @param {string[]} displayName - An array of display names to notify the host with.
|
9987
|
+
* @returns {Promise<any>} The result of the notifyHost request.
|
9988
|
+
*/
|
9989
|
+
notifyHost(meetingUuid: string, displayName: string[]) {
|
9990
|
+
return this.meetingRequest.notifyHost(
|
9991
|
+
this.meetingInfo.siteFullUrl,
|
9992
|
+
this.locusId,
|
9993
|
+
meetingUuid,
|
9994
|
+
displayName
|
9995
|
+
);
|
9996
|
+
}
|
9766
9997
|
}
|
package/src/meeting/muteState.ts
CHANGED
@@ -291,18 +291,14 @@ export class MuteState {
|
|
291
291
|
);
|
292
292
|
|
293
293
|
return MeetingUtil.remoteUpdateAudioVideo(meeting, audioMuted, videoMuted)
|
294
|
-
.then((
|
294
|
+
.then((response) => {
|
295
295
|
LoggerProxy.logger.info(
|
296
296
|
`Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: local mute (audio=${audioMuted}, video=${videoMuted}) applied to server`
|
297
297
|
);
|
298
298
|
|
299
299
|
this.state.server.localMute = this.type === AUDIO ? audioMuted : videoMuted;
|
300
300
|
|
301
|
-
|
302
|
-
meeting.locusInfo.handleLocusDelta(locus, meeting);
|
303
|
-
}
|
304
|
-
|
305
|
-
return locus;
|
301
|
+
return MeetingUtil.updateLocusFromApiResponse(meeting, response);
|
306
302
|
})
|
307
303
|
.catch((remoteUpdateError) => {
|
308
304
|
LoggerProxy.logger.warn(
|