@webex/plugin-meetings 3.7.0-next.21 → 3.7.0-next.23
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 +2 -0
- 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 +8 -0
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/selfUtils.js +20 -11
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/meeting/index.js +718 -646
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +30 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +39 -28
- package/dist/member/util.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +24 -0
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/types/constants.d.ts +2 -0
- package/dist/types/meeting/index.d.ts +8 -0
- package/dist/types/meeting/request.d.ts +12 -1
- package/dist/types/meeting/request.type.d.ts +6 -0
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/types.d.ts +7 -0
- package/dist/types/multistream/sendSlotManager.d.ts +8 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +3 -3
- package/src/constants.ts +2 -0
- package/src/locus-info/index.ts +13 -0
- package/src/locus-info/selfUtils.ts +6 -0
- package/src/meeting/index.ts +67 -0
- package/src/meeting/request.ts +26 -1
- package/src/meeting/request.type.ts +7 -0
- package/src/member/index.ts +9 -0
- package/src/member/types.ts +8 -0
- package/src/member/util.ts +34 -24
- package/src/multistream/sendSlotManager.ts +31 -0
- package/test/unit/spec/locus-info/index.js +93 -0
- package/test/unit/spec/locus-info/selfConstant.js +7 -0
- package/test/unit/spec/locus-info/selfUtils.js +39 -0
- package/test/unit/spec/meeting/index.js +153 -0
- package/test/unit/spec/member/util.js +46 -11
|
@@ -66,6 +66,7 @@ SelfUtils.parse = (self: any, deviceId: string) => {
|
|
|
66
66
|
breakoutSessions: SelfUtils.getBreakoutSessions(self),
|
|
67
67
|
breakout: SelfUtils.getBreakout(self),
|
|
68
68
|
interpretation: SelfUtils.getInterpretation(self),
|
|
69
|
+
brb: SelfUtils.getBrb(self),
|
|
69
70
|
};
|
|
70
71
|
}
|
|
71
72
|
|
|
@@ -75,6 +76,7 @@ SelfUtils.parse = (self: any, deviceId: string) => {
|
|
|
75
76
|
SelfUtils.getBreakoutSessions = (self) => self?.controls?.breakout?.sessions;
|
|
76
77
|
SelfUtils.getBreakout = (self) => self?.controls?.breakout;
|
|
77
78
|
SelfUtils.getInterpretation = (self) => self?.controls?.interpretation;
|
|
79
|
+
SelfUtils.getBrb = (self) => self?.controls?.brb;
|
|
78
80
|
|
|
79
81
|
SelfUtils.getLayout = (self) =>
|
|
80
82
|
Array.isArray(self?.controls?.layouts) ? self.controls.layouts[0].type : undefined;
|
|
@@ -128,6 +130,7 @@ SelfUtils.getSelves = (oldSelf, newSelf, deviceId) => {
|
|
|
128
130
|
updates.isSharingBlockedChanged = previous?.isSharingBlocked !== current.isSharingBlocked;
|
|
129
131
|
updates.breakoutsChanged = SelfUtils.breakoutsChanged(previous, current);
|
|
130
132
|
updates.interpretationChanged = SelfUtils.interpretationChanged(previous, current);
|
|
133
|
+
updates.brbChanged = SelfUtils.brbChanged(previous, current);
|
|
131
134
|
|
|
132
135
|
return {
|
|
133
136
|
previous,
|
|
@@ -159,6 +162,9 @@ SelfUtils.breakoutsChanged = (previous, current) =>
|
|
|
159
162
|
SelfUtils.interpretationChanged = (previous, current) =>
|
|
160
163
|
!isEqual(previous?.interpretation, current?.interpretation) && !!current?.interpretation;
|
|
161
164
|
|
|
165
|
+
SelfUtils.brbChanged = (previous, current) =>
|
|
166
|
+
!isEqual(previous?.brb, current?.brb) && current?.brb !== undefined;
|
|
167
|
+
|
|
162
168
|
SelfUtils.isMediaInactive = (previous, current) => {
|
|
163
169
|
if (
|
|
164
170
|
previous &&
|
package/src/meeting/index.ts
CHANGED
|
@@ -160,6 +160,7 @@ import PermissionError from '../common/errors/permission';
|
|
|
160
160
|
import {LocusMediaRequest} from './locusMediaRequest';
|
|
161
161
|
import {ConnectionStateHandler, ConnectionStateEvent} from './connectionStateHandler';
|
|
162
162
|
import JoinWebinarError from '../common/errors/join-webinar-error';
|
|
163
|
+
import Member from '../member';
|
|
163
164
|
|
|
164
165
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
|
165
166
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
|
@@ -3387,6 +3388,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3387
3388
|
}
|
|
3388
3389
|
});
|
|
3389
3390
|
|
|
3391
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED, (payload) => {
|
|
3392
|
+
Trigger.trigger(
|
|
3393
|
+
this,
|
|
3394
|
+
{
|
|
3395
|
+
file: 'meeting/index',
|
|
3396
|
+
function: 'setUpLocusInfoSelfListener',
|
|
3397
|
+
},
|
|
3398
|
+
EVENT_TRIGGERS.MEETING_SELF_BRB_UPDATE,
|
|
3399
|
+
{
|
|
3400
|
+
payload,
|
|
3401
|
+
}
|
|
3402
|
+
);
|
|
3403
|
+
});
|
|
3404
|
+
|
|
3390
3405
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ROLES_CHANGED, (payload) => {
|
|
3391
3406
|
const isModeratorOrCohost =
|
|
3392
3407
|
payload.newRoles?.includes(SELF_ROLES.MODERATOR) ||
|
|
@@ -3591,6 +3606,50 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3591
3606
|
return this.members.admitMembers(memberIds, locusUrls);
|
|
3592
3607
|
}
|
|
3593
3608
|
|
|
3609
|
+
/**
|
|
3610
|
+
* Manages be right back status updates for the current participant.
|
|
3611
|
+
*
|
|
3612
|
+
* @param {boolean} enabled - Indicates whether the user enabled brb or not.
|
|
3613
|
+
* @returns {Promise<void>} resolves when the brb status is updated or does nothing if not in a multistream meeting.
|
|
3614
|
+
* @throws {Error} - Throws an error if the request fails.
|
|
3615
|
+
*/
|
|
3616
|
+
public async beRightBack(enabled: boolean): Promise<void> {
|
|
3617
|
+
if (!this.isMultistream) {
|
|
3618
|
+
const errorMessage = 'Meeting:index#beRightBack --> Not a multistream meeting';
|
|
3619
|
+
const error = new Error(errorMessage);
|
|
3620
|
+
|
|
3621
|
+
LoggerProxy.logger.error(error);
|
|
3622
|
+
|
|
3623
|
+
return Promise.reject(error);
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3626
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
3627
|
+
const errorMessage = 'Meeting:index#beRightBack --> WebRTC media connection is not defined';
|
|
3628
|
+
const error = new Error(errorMessage);
|
|
3629
|
+
|
|
3630
|
+
LoggerProxy.logger.error(error);
|
|
3631
|
+
|
|
3632
|
+
return Promise.reject(error);
|
|
3633
|
+
}
|
|
3634
|
+
|
|
3635
|
+
// this logic should be applied only to multistream meetings
|
|
3636
|
+
return this.meetingRequest
|
|
3637
|
+
.setBrb({
|
|
3638
|
+
enabled,
|
|
3639
|
+
locusUrl: this.locusUrl,
|
|
3640
|
+
deviceUrl: this.deviceUrl,
|
|
3641
|
+
selfId: this.selfId,
|
|
3642
|
+
})
|
|
3643
|
+
.then(() => {
|
|
3644
|
+
this.sendSlotManager.setSourceStateOverride(MediaType.VideoMain, enabled ? 'away' : null);
|
|
3645
|
+
})
|
|
3646
|
+
.catch((error) => {
|
|
3647
|
+
LoggerProxy.logger.error('Meeting:index#beRightBack --> Error ', error);
|
|
3648
|
+
|
|
3649
|
+
return Promise.reject(error);
|
|
3650
|
+
});
|
|
3651
|
+
}
|
|
3652
|
+
|
|
3594
3653
|
/**
|
|
3595
3654
|
* Remove the member from the meeting, boot them
|
|
3596
3655
|
* @param {String} memberId
|
|
@@ -6472,6 +6531,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6472
6531
|
this.webex.meetings.geoHintInfo?.clientAddress ||
|
|
6473
6532
|
options.data.intervalMetadata.peerReflexiveIP ||
|
|
6474
6533
|
MQA_STATS.DEFAULT_IP;
|
|
6534
|
+
|
|
6535
|
+
const {members} = this.getMembers().membersCollection;
|
|
6536
|
+
|
|
6537
|
+
// Count members that are in the meeting
|
|
6538
|
+
options.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
|
|
6539
|
+
(member: Member) => member.isInMeeting
|
|
6540
|
+
).length;
|
|
6541
|
+
|
|
6475
6542
|
// @ts-ignore
|
|
6476
6543
|
this.webex.internal.newMetrics.submitMQE({
|
|
6477
6544
|
name: 'client.mediaquality.event',
|
package/src/meeting/request.ts
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
_SLIDES_,
|
|
28
28
|
ANNOTATION,
|
|
29
29
|
} from '../constants';
|
|
30
|
-
import {SendReactionOptions, ToggleReactionsOptions} from './request.type';
|
|
30
|
+
import {SendReactionOptions, BrbOptions, ToggleReactionsOptions} from './request.type';
|
|
31
31
|
import MeetingUtil from './util';
|
|
32
32
|
import {AnnotationInfo} from '../annotation/annotation.types';
|
|
33
33
|
import {ClientMediaPreferences} from '../reachability/reachability.types';
|
|
@@ -909,4 +909,29 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
909
909
|
uri: locusUrl,
|
|
910
910
|
});
|
|
911
911
|
}
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* Sends a request to set be right back status.
|
|
915
|
+
*
|
|
916
|
+
* @param {Object} options - The options for brb request.
|
|
917
|
+
* @param {boolean} options.enabled - Whether brb status is enabled.
|
|
918
|
+
* @param {string} options.locusUrl - The URL of the locus.
|
|
919
|
+
* @param {string} options.deviceUrl - The URL of the device.
|
|
920
|
+
* @param {string} options.selfId - The ID of the participant.
|
|
921
|
+
* @returns {Promise}
|
|
922
|
+
*/
|
|
923
|
+
setBrb({enabled, locusUrl, deviceUrl, selfId}: BrbOptions) {
|
|
924
|
+
const uri = `${locusUrl}/${PARTICIPANT}/${selfId}/${CONTROLS}`;
|
|
925
|
+
|
|
926
|
+
return this.locusDeltaRequest({
|
|
927
|
+
method: HTTP_VERBS.PATCH,
|
|
928
|
+
uri,
|
|
929
|
+
body: {
|
|
930
|
+
brb: {
|
|
931
|
+
enabled,
|
|
932
|
+
deviceUrl,
|
|
933
|
+
},
|
|
934
|
+
},
|
|
935
|
+
});
|
|
936
|
+
}
|
|
912
937
|
}
|
package/src/member/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ export default class Member {
|
|
|
28
28
|
isRecording: any;
|
|
29
29
|
isRemovable: any;
|
|
30
30
|
isSelf: any;
|
|
31
|
+
isBrb: boolean;
|
|
31
32
|
isUser: any;
|
|
32
33
|
isVideoMuted: any;
|
|
33
34
|
roles: IExternalRoles;
|
|
@@ -227,6 +228,13 @@ export default class Member {
|
|
|
227
228
|
* @memberof Member
|
|
228
229
|
*/
|
|
229
230
|
this.isRemovable = null;
|
|
231
|
+
/**
|
|
232
|
+
* @instance
|
|
233
|
+
* @type {Boolean}
|
|
234
|
+
* @public
|
|
235
|
+
* @memberof Member
|
|
236
|
+
*/
|
|
237
|
+
this.isBrb = false;
|
|
230
238
|
/**
|
|
231
239
|
* @instance
|
|
232
240
|
* @type {String}
|
|
@@ -295,6 +303,7 @@ export default class Member {
|
|
|
295
303
|
this.supportsInterpretation = MemberUtil.isInterpretationSupported(participant);
|
|
296
304
|
this.supportLiveAnnotation = MemberUtil.isLiveAnnotationSupported(participant);
|
|
297
305
|
this.isGuest = MemberUtil.isGuest(participant);
|
|
306
|
+
this.isBrb = MemberUtil.isBrb(participant);
|
|
298
307
|
this.isUser = MemberUtil.isUser(participant);
|
|
299
308
|
this.isDevice = MemberUtil.isDevice(participant);
|
|
300
309
|
this.isModerator = MemberUtil.isModerator(participant);
|
package/src/member/types.ts
CHANGED
|
@@ -23,6 +23,14 @@ export type ParticipantWithRoles = {
|
|
|
23
23
|
};
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
export type ParticipantWithBrb = {
|
|
27
|
+
controls: {
|
|
28
|
+
brb?: {
|
|
29
|
+
enabled: boolean;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
26
34
|
// values are inherited from locus so don't update these
|
|
27
35
|
export enum MediaStatus {
|
|
28
36
|
RECVONLY = 'RECVONLY', // participant only receiving and not sending
|
package/src/member/util.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ServerRoles,
|
|
5
5
|
ServerRoleShape,
|
|
6
6
|
IMediaStatus,
|
|
7
|
+
ParticipantWithBrb,
|
|
7
8
|
} from './types';
|
|
8
9
|
import {
|
|
9
10
|
_USER_,
|
|
@@ -29,7 +30,7 @@ import ParameterError from '../common/errors/parameter';
|
|
|
29
30
|
const MemberUtil: any = {};
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
|
-
* @param {Object} participant
|
|
33
|
+
* @param {Object} participant - The locus participant object.
|
|
33
34
|
* @returns {Boolean}
|
|
34
35
|
*/
|
|
35
36
|
MemberUtil.canReclaimHost = (participant) => {
|
|
@@ -43,14 +44,23 @@ MemberUtil.canReclaimHost = (participant) => {
|
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
|
-
* @param {Object} participant
|
|
47
|
+
* @param {Object} participant - The locus participant object.
|
|
47
48
|
* @returns {[ServerRoleShape]}
|
|
48
49
|
*/
|
|
49
50
|
MemberUtil.getControlsRoles = (participant: ParticipantWithRoles): Array<ServerRoleShape> =>
|
|
50
51
|
participant?.controls?.role?.roles;
|
|
51
52
|
|
|
52
53
|
/**
|
|
53
|
-
*
|
|
54
|
+
* Checks if the participant has the brb status enabled.
|
|
55
|
+
*
|
|
56
|
+
* @param {ParticipantWithBrb} participant - The locus participant object.
|
|
57
|
+
* @returns {boolean} - True if the participant has brb enabled, false otherwise.
|
|
58
|
+
*/
|
|
59
|
+
MemberUtil.isBrb = (participant: ParticipantWithBrb): boolean =>
|
|
60
|
+
participant.controls.brb?.enabled || false;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {Object} participant - The locus participant object.
|
|
54
64
|
* @param {ServerRoles} controlRole the search role
|
|
55
65
|
* @returns {Boolean}
|
|
56
66
|
*/
|
|
@@ -60,28 +70,28 @@ MemberUtil.hasRole = (participant: any, controlRole: ServerRoles): boolean =>
|
|
|
60
70
|
);
|
|
61
71
|
|
|
62
72
|
/**
|
|
63
|
-
* @param {Object} participant
|
|
73
|
+
* @param {Object} participant - The locus participant object.
|
|
64
74
|
* @returns {Boolean}
|
|
65
75
|
*/
|
|
66
76
|
MemberUtil.hasCohost = (participant: ParticipantWithRoles): boolean =>
|
|
67
77
|
MemberUtil.hasRole(participant, ServerRoles.Cohost) || false;
|
|
68
78
|
|
|
69
79
|
/**
|
|
70
|
-
* @param {Object} participant
|
|
80
|
+
* @param {Object} participant - The locus participant object.
|
|
71
81
|
* @returns {Boolean}
|
|
72
82
|
*/
|
|
73
83
|
MemberUtil.hasModerator = (participant: ParticipantWithRoles): boolean =>
|
|
74
84
|
MemberUtil.hasRole(participant, ServerRoles.Moderator) || false;
|
|
75
85
|
|
|
76
86
|
/**
|
|
77
|
-
* @param {Object} participant
|
|
87
|
+
* @param {Object} participant - The locus participant object.
|
|
78
88
|
* @returns {Boolean}
|
|
79
89
|
*/
|
|
80
90
|
MemberUtil.hasPresenter = (participant: ParticipantWithRoles): boolean =>
|
|
81
91
|
MemberUtil.hasRole(participant, ServerRoles.Presenter) || false;
|
|
82
92
|
|
|
83
93
|
/**
|
|
84
|
-
* @param {Object} participant
|
|
94
|
+
* @param {Object} participant - The locus participant object.
|
|
85
95
|
* @returns {IExternalRoles}
|
|
86
96
|
*/
|
|
87
97
|
MemberUtil.extractControlRoles = (participant: ParticipantWithRoles): IExternalRoles => {
|
|
@@ -95,7 +105,7 @@ MemberUtil.extractControlRoles = (participant: ParticipantWithRoles): IExternalR
|
|
|
95
105
|
};
|
|
96
106
|
|
|
97
107
|
/**
|
|
98
|
-
* @param {Object} participant
|
|
108
|
+
* @param {Object} participant - The locus participant object.
|
|
99
109
|
* @returns {Boolean}
|
|
100
110
|
*/
|
|
101
111
|
MemberUtil.isUser = (participant: any) => participant && participant.type === _USER_;
|
|
@@ -103,13 +113,13 @@ MemberUtil.isUser = (participant: any) => participant && participant.type === _U
|
|
|
103
113
|
MemberUtil.isModerator = (participant) => participant && participant.moderator;
|
|
104
114
|
|
|
105
115
|
/**
|
|
106
|
-
* @param {Object} participant
|
|
116
|
+
* @param {Object} participant - The locus participant object.
|
|
107
117
|
* @returns {Boolean}
|
|
108
118
|
*/
|
|
109
119
|
MemberUtil.isGuest = (participant: any) => participant && participant.guest;
|
|
110
120
|
|
|
111
121
|
/**
|
|
112
|
-
* @param {Object} participant
|
|
122
|
+
* @param {Object} participant - The locus participant object.
|
|
113
123
|
* @returns {Boolean}
|
|
114
124
|
*/
|
|
115
125
|
MemberUtil.isDevice = (participant: any) => participant && participant.type === _RESOURCE_ROOM_;
|
|
@@ -120,7 +130,7 @@ MemberUtil.isModeratorAssignmentProhibited = (participant) =>
|
|
|
120
130
|
/**
|
|
121
131
|
* checks to see if the participant id is the same as the passed id
|
|
122
132
|
* there are multiple ids that can be used
|
|
123
|
-
* @param {Object} participant
|
|
133
|
+
* @param {Object} participant - The locus participant object.
|
|
124
134
|
* @param {String} id
|
|
125
135
|
* @returns {Boolean}
|
|
126
136
|
*/
|
|
@@ -130,7 +140,7 @@ MemberUtil.isSame = (participant: any, id: string) =>
|
|
|
130
140
|
/**
|
|
131
141
|
* checks to see if the participant id is the same as the passed id for associated devices
|
|
132
142
|
* there are multiple ids that can be used
|
|
133
|
-
* @param {Object} participant
|
|
143
|
+
* @param {Object} participant - The locus participant object.
|
|
134
144
|
* @param {String} id
|
|
135
145
|
* @returns {Boolean}
|
|
136
146
|
*/
|
|
@@ -142,7 +152,7 @@ MemberUtil.isAssociatedSame = (participant: any, id: string) =>
|
|
|
142
152
|
);
|
|
143
153
|
|
|
144
154
|
/**
|
|
145
|
-
* @param {Object} participant
|
|
155
|
+
* @param {Object} participant - The locus participant object.
|
|
146
156
|
* @param {Boolean} isGuest
|
|
147
157
|
* @param {String} status
|
|
148
158
|
* @returns {Boolean}
|
|
@@ -161,7 +171,7 @@ MemberUtil.isNotAdmitted = (participant: any, isGuest: boolean, status: string):
|
|
|
161
171
|
!status === _IN_MEETING_);
|
|
162
172
|
|
|
163
173
|
/**
|
|
164
|
-
* @param {Object} participant
|
|
174
|
+
* @param {Object} participant - The locus participant object.
|
|
165
175
|
* @returns {Boolean}
|
|
166
176
|
*/
|
|
167
177
|
MemberUtil.isAudioMuted = (participant: any) => {
|
|
@@ -173,7 +183,7 @@ MemberUtil.isAudioMuted = (participant: any) => {
|
|
|
173
183
|
};
|
|
174
184
|
|
|
175
185
|
/**
|
|
176
|
-
* @param {Object} participant
|
|
186
|
+
* @param {Object} participant - The locus participant object.
|
|
177
187
|
* @returns {Boolean}
|
|
178
188
|
*/
|
|
179
189
|
MemberUtil.isVideoMuted = (participant: any): boolean => {
|
|
@@ -185,7 +195,7 @@ MemberUtil.isVideoMuted = (participant: any): boolean => {
|
|
|
185
195
|
};
|
|
186
196
|
|
|
187
197
|
/**
|
|
188
|
-
* @param {Object} participant
|
|
198
|
+
* @param {Object} participant - The locus participant object.
|
|
189
199
|
* @returns {Boolean}
|
|
190
200
|
*/
|
|
191
201
|
MemberUtil.isHandRaised = (participant: any) => {
|
|
@@ -197,7 +207,7 @@ MemberUtil.isHandRaised = (participant: any) => {
|
|
|
197
207
|
};
|
|
198
208
|
|
|
199
209
|
/**
|
|
200
|
-
* @param {Object} participant
|
|
210
|
+
* @param {Object} participant - The locus participant object.
|
|
201
211
|
* @returns {Boolean}
|
|
202
212
|
*/
|
|
203
213
|
MemberUtil.isBreakoutsSupported = (participant) => {
|
|
@@ -209,7 +219,7 @@ MemberUtil.isBreakoutsSupported = (participant) => {
|
|
|
209
219
|
};
|
|
210
220
|
|
|
211
221
|
/**
|
|
212
|
-
* @param {Object} participant
|
|
222
|
+
* @param {Object} participant - The locus participant object.
|
|
213
223
|
* @returns {Boolean}
|
|
214
224
|
*/
|
|
215
225
|
MemberUtil.isInterpretationSupported = (participant) => {
|
|
@@ -223,7 +233,7 @@ MemberUtil.isInterpretationSupported = (participant) => {
|
|
|
223
233
|
};
|
|
224
234
|
|
|
225
235
|
/**
|
|
226
|
-
* @param {Object} participant
|
|
236
|
+
* @param {Object} participant - The locus participant object.
|
|
227
237
|
* @returns {Boolean}
|
|
228
238
|
*/
|
|
229
239
|
MemberUtil.isLiveAnnotationSupported = (participant) => {
|
|
@@ -279,7 +289,7 @@ MemberUtil.getRecordingMember = (controls: any) => {
|
|
|
279
289
|
};
|
|
280
290
|
|
|
281
291
|
/**
|
|
282
|
-
* @param {Object} participant
|
|
292
|
+
* @param {Object} participant - The locus participant object.
|
|
283
293
|
* @returns {Boolean}
|
|
284
294
|
*/
|
|
285
295
|
MemberUtil.isRecording = (participant: any) => {
|
|
@@ -325,7 +335,7 @@ MemberUtil.isMutable = (isSelf, isDevice, isInMeeting, isMuted, type) => {
|
|
|
325
335
|
};
|
|
326
336
|
|
|
327
337
|
/**
|
|
328
|
-
* @param {Object} participant
|
|
338
|
+
* @param {Object} participant - The locus participant object.
|
|
329
339
|
* @returns {String}
|
|
330
340
|
*/
|
|
331
341
|
MemberUtil.extractStatus = (participant: any) => {
|
|
@@ -355,7 +365,7 @@ MemberUtil.extractStatus = (participant: any) => {
|
|
|
355
365
|
};
|
|
356
366
|
|
|
357
367
|
/**
|
|
358
|
-
* @param {Object} participant
|
|
368
|
+
* @param {Object} participant - The locus participant object.
|
|
359
369
|
* @returns {String}
|
|
360
370
|
*/
|
|
361
371
|
MemberUtil.extractId = (participant: any) => {
|
|
@@ -368,7 +378,7 @@ MemberUtil.extractId = (participant: any) => {
|
|
|
368
378
|
|
|
369
379
|
/**
|
|
370
380
|
* extracts the media status from nested participant object
|
|
371
|
-
* @param {Object} participant
|
|
381
|
+
* @param {Object} participant - The locus participant object.
|
|
372
382
|
* @returns {Object}
|
|
373
383
|
*/
|
|
374
384
|
MemberUtil.extractMediaStatus = (participant: any): IMediaStatus => {
|
|
@@ -383,7 +393,7 @@ MemberUtil.extractMediaStatus = (participant: any): IMediaStatus => {
|
|
|
383
393
|
};
|
|
384
394
|
|
|
385
395
|
/**
|
|
386
|
-
* @param {Object} participant
|
|
396
|
+
* @param {Object} participant - The locus participant object.
|
|
387
397
|
* @returns {String}
|
|
388
398
|
*/
|
|
389
399
|
MemberUtil.extractName = (participant: any) => {
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
LocalStream,
|
|
5
5
|
MultistreamRoapMediaConnection,
|
|
6
6
|
NamedMediaGroup,
|
|
7
|
+
StreamState,
|
|
7
8
|
} from '@webex/internal-media-core';
|
|
8
9
|
|
|
9
10
|
export default class SendSlotManager {
|
|
@@ -83,6 +84,36 @@ export default class SendSlotManager {
|
|
|
83
84
|
);
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Sets the source state override for the given media type.
|
|
89
|
+
* @param {MediaType} mediaType - The type of media (must be MediaType.VideoMain to apply source state changes).
|
|
90
|
+
* @param {StreamState | null} state - The state to set or null to clear the override value.
|
|
91
|
+
* @returns {void}
|
|
92
|
+
*/
|
|
93
|
+
public setSourceStateOverride(mediaType: MediaType, state: StreamState | null) {
|
|
94
|
+
if (mediaType !== MediaType.VideoMain) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`sendSlotManager cannot set source state override which media type is ${mediaType}`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const slot = this.slots.get(mediaType);
|
|
101
|
+
|
|
102
|
+
if (!slot) {
|
|
103
|
+
throw new Error(`Slot for ${mediaType} does not exist`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (state) {
|
|
107
|
+
slot.setSourceStateOverride(state);
|
|
108
|
+
} else {
|
|
109
|
+
slot.clearSourceStateOverride();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.LoggerProxy.logger.info(
|
|
113
|
+
`SendSlotsManager->setSourceStateOverride#set source state override for ${mediaType} to ${state}`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
86
117
|
/**
|
|
87
118
|
* This method publishes the given stream to the sendSlot for the given mediaType
|
|
88
119
|
* @param {MediaType} mediaType MediaType of the sendSlot to which a stream needs to be published (AUDIO_MAIN/VIDEO_MAIN/AUDIO_SLIDES/VIDEO_SLIDES)
|
|
@@ -794,6 +794,75 @@ describe('plugin-meetings', () => {
|
|
|
794
794
|
});
|
|
795
795
|
|
|
796
796
|
describe('#updateSelf', () => {
|
|
797
|
+
it('should trigger SELF_MEETING_BRB_CHANGED when brb state changed', () => {
|
|
798
|
+
locusInfo.self = undefined;
|
|
799
|
+
|
|
800
|
+
const assertBrb = (enabled) => {
|
|
801
|
+
const selfWithBrbChanged = cloneDeep(self);
|
|
802
|
+
selfWithBrbChanged.controls.brb = enabled;
|
|
803
|
+
|
|
804
|
+
locusInfo.emitScoped = sinon.stub();
|
|
805
|
+
locusInfo.updateSelf(selfWithBrbChanged, []);
|
|
806
|
+
|
|
807
|
+
assert.calledWith(
|
|
808
|
+
locusInfo.emitScoped,
|
|
809
|
+
{file: 'locus-info', function: 'updateSelf'},
|
|
810
|
+
LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED,
|
|
811
|
+
{brb: enabled}
|
|
812
|
+
);
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
assertBrb(true);
|
|
816
|
+
assertBrb(false);
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
it('should not trigger SELF_MEETING_BRB_CHANGED when brb state did not change', () => {
|
|
820
|
+
const assertBrbUnchanged = (value) => {
|
|
821
|
+
locusInfo.self = undefined;
|
|
822
|
+
|
|
823
|
+
const selfWithBrbChanged = cloneDeep(self);
|
|
824
|
+
selfWithBrbChanged.controls.brb = value;
|
|
825
|
+
locusInfo.self = selfWithBrbChanged;
|
|
826
|
+
|
|
827
|
+
locusInfo.emitScoped = sinon.stub();
|
|
828
|
+
|
|
829
|
+
const newSelf = cloneDeep(self);
|
|
830
|
+
newSelf.controls.brb = value;
|
|
831
|
+
|
|
832
|
+
locusInfo.updateSelf(newSelf, []);
|
|
833
|
+
|
|
834
|
+
assert.neverCalledWith(
|
|
835
|
+
locusInfo.emitScoped,
|
|
836
|
+
{file: 'locus-info', function: 'updateSelf'},
|
|
837
|
+
LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED,
|
|
838
|
+
{brb: value}
|
|
839
|
+
);
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
assertBrbUnchanged(true);
|
|
843
|
+
assertBrbUnchanged(false);
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
it('should not trigger SELF_MEETING_BRB_CHANGED when brb state is undefined', () => {
|
|
847
|
+
const selfWithBrbChanged = cloneDeep(self);
|
|
848
|
+
selfWithBrbChanged.controls.brb = false;
|
|
849
|
+
locusInfo.self = selfWithBrbChanged;
|
|
850
|
+
|
|
851
|
+
locusInfo.emitScoped = sinon.stub();
|
|
852
|
+
|
|
853
|
+
const newSelf = cloneDeep(self);
|
|
854
|
+
newSelf.controls.brb = undefined;
|
|
855
|
+
|
|
856
|
+
locusInfo.updateSelf(newSelf, []);
|
|
857
|
+
|
|
858
|
+
assert.neverCalledWith(
|
|
859
|
+
locusInfo.emitScoped,
|
|
860
|
+
{file: 'locus-info', function: 'updateSelf'},
|
|
861
|
+
LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED,
|
|
862
|
+
{brb: undefined}
|
|
863
|
+
);
|
|
864
|
+
});
|
|
865
|
+
|
|
797
866
|
it('should trigger CONTROLS_MEETING_LAYOUT_UPDATED when the meeting layout controls change', () => {
|
|
798
867
|
const layoutType = 'EXAMPLE TYPE';
|
|
799
868
|
|
|
@@ -1389,6 +1458,30 @@ describe('plugin-meetings', () => {
|
|
|
1389
1458
|
}
|
|
1390
1459
|
);
|
|
1391
1460
|
});
|
|
1461
|
+
|
|
1462
|
+
it('should not trigger any events if controls is undefined', () => {
|
|
1463
|
+
locusInfo.self = self;
|
|
1464
|
+
locusInfo.emitScoped = sinon.stub();
|
|
1465
|
+
const newSelf = cloneDeep(self);
|
|
1466
|
+
newSelf.controls = undefined;
|
|
1467
|
+
|
|
1468
|
+
locusInfo.updateSelf(newSelf, []);
|
|
1469
|
+
|
|
1470
|
+
const eventsSet = new Set([
|
|
1471
|
+
LOCUSINFO.EVENTS.CONTROLS_MEETING_LAYOUT_UPDATED,
|
|
1472
|
+
LOCUSINFO.EVENTS.SELF_MEETING_BREAKOUTS_CHANGED,
|
|
1473
|
+
LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED,
|
|
1474
|
+
LOCUSINFO.EVENTS.SELF_MEETING_INTERPRETATION_CHANGED,
|
|
1475
|
+
LOCUSINFO.EVENTS.LOCAL_UNMUTE_REQUIRED,
|
|
1476
|
+
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
1477
|
+
]);
|
|
1478
|
+
|
|
1479
|
+
// check all events that contain logic on controls existence
|
|
1480
|
+
locusInfo.emitScoped.getCalls().forEach((call) => {
|
|
1481
|
+
const eventName = call.args[1];
|
|
1482
|
+
assert.isFalse(eventsSet.has(eventName));
|
|
1483
|
+
});
|
|
1484
|
+
});
|
|
1392
1485
|
});
|
|
1393
1486
|
|
|
1394
1487
|
describe('#updateMeetingInfo', () => {
|
|
@@ -304,6 +304,13 @@ export const selfWithInactivity = {
|
|
|
304
304
|
localRecord: {
|
|
305
305
|
recording: false,
|
|
306
306
|
},
|
|
307
|
+
brb: {
|
|
308
|
+
enabled: true,
|
|
309
|
+
meta: {
|
|
310
|
+
lastModified: '2024-10-24T14:05:58.526Z',
|
|
311
|
+
modifiedBy: '70978427-8238-4ffc-9227-8baf4b80b831',
|
|
312
|
+
},
|
|
313
|
+
},
|
|
307
314
|
layouts: [
|
|
308
315
|
{
|
|
309
316
|
type: 'activePresence',
|
|
@@ -60,6 +60,14 @@ describe('plugin-meetings', () => {
|
|
|
60
60
|
assert.calledWith(spy, self);
|
|
61
61
|
assert.deepEqual(parsedSelf.layout, self.controls.layouts[0].type);
|
|
62
62
|
});
|
|
63
|
+
|
|
64
|
+
it('calls getBrb and returns the resulting brb value', () => {
|
|
65
|
+
const spy = Sinon.spy(SelfUtils, 'getBrb');
|
|
66
|
+
const parsedSelf = SelfUtils.parse(self);
|
|
67
|
+
|
|
68
|
+
assert.calledWith(spy, self);
|
|
69
|
+
assert.deepEqual(parsedSelf.brb, self.controls.brb);
|
|
70
|
+
});
|
|
63
71
|
});
|
|
64
72
|
|
|
65
73
|
describe('getLayout', () => {
|
|
@@ -170,6 +178,37 @@ describe('plugin-meetings', () => {
|
|
|
170
178
|
});
|
|
171
179
|
});
|
|
172
180
|
|
|
181
|
+
describe('brbChanged', () => {
|
|
182
|
+
it('should return true if brb have changed', () => {
|
|
183
|
+
const current = {
|
|
184
|
+
brb: {enabled: true}
|
|
185
|
+
};
|
|
186
|
+
const previous = {
|
|
187
|
+
brb: {enabled: false}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
assert.isTrue(SelfUtils.brbChanged(previous, current));
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should return false if brb have not changed', () => {
|
|
194
|
+
const current = {
|
|
195
|
+
brb: {enabled: true}
|
|
196
|
+
};
|
|
197
|
+
const previous = {
|
|
198
|
+
brb: {enabled: true}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
assert.isFalse(SelfUtils.brbChanged(previous, current));
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should return false if brb in current is undefined', () => {
|
|
205
|
+
const current = {};
|
|
206
|
+
const previous = {brb: {enabled: true}};
|
|
207
|
+
|
|
208
|
+
assert.isFalse(SelfUtils.brbChanged(previous, current));
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
173
212
|
describe('canNotViewTheParticipantList', () => {
|
|
174
213
|
it('should return the correct value', () => {
|
|
175
214
|
assert.equal(
|