@webex/plugin-meetings 3.9.0-webinar5k.1 → 3.9.0
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 +16 -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 +40 -328
- package/dist/locus-info/index.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 +196 -160
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +5 -2
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/type.js +7 -0
- package/dist/meeting/type.js.map +1 -0
- package/dist/meeting/util.js +79 -10
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +37 -39
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/members/collection.js +0 -13
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +21 -40
- package/dist/members/index.js.map +1 -1
- 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/types/constants.d.ts +16 -0
- package/dist/types/locus-info/index.d.ts +3 -102
- package/dist/types/meeting/in-meeting-actions.d.ts +6 -0
- package/dist/types/meeting/index.d.ts +23 -28
- package/dist/types/meeting/type.d.ts +9 -0
- package/dist/types/meeting/util.d.ts +6 -3
- package/dist/types/member/types.d.ts +0 -1
- package/dist/types/members/collection.d.ts +0 -6
- package/dist/types/members/index.d.ts +7 -16
- package/dist/types/members/util.d.ts +2 -1
- package/dist/types/multistream/remoteMedia.d.ts +20 -1
- package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -24
- package/src/constants.ts +16 -2
- package/src/locus-info/index.ts +39 -409
- package/src/meeting/in-meeting-actions.ts +13 -0
- package/src/meeting/index.ts +92 -63
- package/src/meeting/muteState.ts +6 -2
- package/src/meeting/type.ts +9 -0
- package/src/meeting/util.ts +93 -19
- package/src/meetings/index.ts +6 -19
- package/src/member/types.ts +0 -1
- package/src/members/collection.ts +0 -11
- package/src/members/index.ts +10 -33
- package/src/members/util.ts +2 -1
- package/src/multistream/mediaRequestManager.ts +7 -7
- package/src/multistream/remoteMedia.ts +34 -4
- package/src/multistream/remoteMediaGroup.ts +37 -2
- package/test/unit/spec/locus-info/index.js +8 -365
- package/test/unit/spec/meeting/in-meeting-actions.ts +6 -0
- package/test/unit/spec/meeting/index.js +254 -38
- 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 +37 -1
- package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
- package/test/unit/spec/multistream/remoteMedia.ts +66 -2
- package/dist/hashTree/constants.js +0 -23
- package/dist/hashTree/constants.js.map +0 -1
- package/dist/hashTree/hashTree.js +0 -516
- package/dist/hashTree/hashTree.js.map +0 -1
- package/dist/hashTree/hashTreeParser.js +0 -521
- package/dist/hashTree/hashTreeParser.js.map +0 -1
- package/dist/types/hashTree/constants.d.ts +0 -8
- package/dist/types/hashTree/hashTree.d.ts +0 -128
- package/dist/types/hashTree/hashTreeParser.d.ts +0 -152
- package/src/hashTree/constants.ts +0 -12
- package/src/hashTree/hashTree.ts +0 -460
- package/src/hashTree/hashTreeParser.ts +0 -556
- package/test/unit/spec/hashTree/hashTree.ts +0 -394
- package/test/unit/spec/hashTree/hashTreeParser.ts +0 -156
@@ -39,17 +39,6 @@ export default class MembersCollection {
|
|
39
39
|
return this.members;
|
40
40
|
}
|
41
41
|
|
42
|
-
/**
|
43
|
-
* Removes a member from the collection
|
44
|
-
* @param {String} id
|
45
|
-
* @returns {void}
|
46
|
-
*/
|
47
|
-
remove(id: string) {
|
48
|
-
if (this.members[id]) {
|
49
|
-
delete this.members[id];
|
50
|
-
}
|
51
|
-
}
|
52
|
-
|
53
42
|
/**
|
54
43
|
* @returns {void}
|
55
44
|
* reset members
|
package/src/members/index.ts
CHANGED
@@ -30,6 +30,7 @@ import MembersUtil from './util';
|
|
30
30
|
import {ReceiveSlotManager} from '../multistream/receiveSlotManager';
|
31
31
|
import {MediaRequestManager} from '../multistream/mediaRequestManager';
|
32
32
|
import {ServerRoleShape} from './types';
|
33
|
+
import {Invitee} from '../meeting/type';
|
33
34
|
|
34
35
|
/**
|
35
36
|
* Members Update Event
|
@@ -73,11 +74,7 @@ import {ServerRoleShape} from './types';
|
|
73
74
|
* @memberof Members
|
74
75
|
*/
|
75
76
|
|
76
|
-
type UpdatedMembers = {
|
77
|
-
added: Array<Member>;
|
78
|
-
updated: Array<Member>;
|
79
|
-
removedIds?: Array<string>; // removed member ids
|
80
|
-
};
|
77
|
+
type UpdatedMembers = {added: Array<Member>; updated: Array<Member>};
|
81
78
|
/**
|
82
79
|
* @class Members
|
83
80
|
*/
|
@@ -392,11 +389,7 @@ export default class Members extends StatelessWebexPlugin {
|
|
392
389
|
* @private
|
393
390
|
* @memberof Members
|
394
391
|
*/
|
395
|
-
locusParticipantsUpdate(payload: {
|
396
|
-
participants: object;
|
397
|
-
isReplace?: boolean;
|
398
|
-
removedParticipantIds?: Array<string>;
|
399
|
-
}) {
|
392
|
+
locusParticipantsUpdate(payload: {participants: object; isReplace?: boolean}) {
|
400
393
|
if (payload) {
|
401
394
|
if (payload.isReplace) {
|
402
395
|
this.clearMembers();
|
@@ -554,22 +547,10 @@ export default class Members extends StatelessWebexPlugin {
|
|
554
547
|
private handleMembersUpdate(membersUpdate: UpdatedMembers) {
|
555
548
|
this.constructMembers(membersUpdate.updated, true);
|
556
549
|
this.constructMembers(membersUpdate.added, false);
|
557
|
-
this.removeMembers(membersUpdate.removedIds);
|
558
550
|
|
559
551
|
return this.membersCollection.getAll();
|
560
552
|
}
|
561
553
|
|
562
|
-
/**
|
563
|
-
* removes members from the collection
|
564
|
-
* @param {Array<string>} removedMembers removed members ids
|
565
|
-
* @returns {void}
|
566
|
-
*/
|
567
|
-
private removeMembers(removedMembers: Array<string>) {
|
568
|
-
removedMembers.forEach((memberId) => {
|
569
|
-
this.membersCollection.remove(memberId);
|
570
|
-
});
|
571
|
-
}
|
572
|
-
|
573
554
|
/**
|
574
555
|
* set members to the member collection from each updated/added lists as passed in
|
575
556
|
* @param {Array} list
|
@@ -619,10 +600,6 @@ export default class Members extends StatelessWebexPlugin {
|
|
619
600
|
}
|
620
601
|
const memberUpdate = this.update(payload.participants);
|
621
602
|
|
622
|
-
// this code depends on memberIds being the same as participantIds
|
623
|
-
// if MemberUtil.extractId() ever changes, this will need to be updated
|
624
|
-
memberUpdate.removedIds = payload.removedParticipantIds || [];
|
625
|
-
|
626
603
|
return memberUpdate;
|
627
604
|
}
|
628
605
|
|
@@ -824,18 +801,18 @@ export default class Members extends StatelessWebexPlugin {
|
|
824
801
|
|
825
802
|
/**
|
826
803
|
* Adds a guest Member to the associated meeting
|
827
|
-
* @param {
|
804
|
+
* @param {Invitee} invitee
|
828
805
|
* @param {Boolean} [alertIfActive]
|
829
806
|
* @returns {Promise}
|
830
807
|
* @memberof Members
|
831
808
|
*/
|
832
|
-
addMember(invitee:
|
809
|
+
addMember(invitee: Invitee, alertIfActive?: boolean) {
|
833
810
|
if (!this.locusUrl) {
|
834
811
|
return Promise.reject(
|
835
812
|
new ParameterError('The associated locus url for this meeting object must be defined.')
|
836
813
|
);
|
837
814
|
}
|
838
|
-
if (MembersUtil.isInvalidInvitee(invitee)) {
|
815
|
+
if (invitee?.skipEmailValidation !== true && MembersUtil.isInvalidInvitee(invitee)) {
|
839
816
|
return Promise.reject(
|
840
817
|
new ParameterError(
|
841
818
|
'The invitee must be defined with either a valid email, emailAddress or phoneNumber property.'
|
@@ -849,11 +826,11 @@ export default class Members extends StatelessWebexPlugin {
|
|
849
826
|
|
850
827
|
/**
|
851
828
|
* Cancels an outgoing PSTN call to the associated meeting
|
852
|
-
* @param {
|
829
|
+
* @param {Invitee} invitee
|
853
830
|
* @returns {Promise}
|
854
831
|
* @memberof Members
|
855
832
|
*/
|
856
|
-
cancelPhoneInvite(invitee:
|
833
|
+
cancelPhoneInvite(invitee: Invitee) {
|
857
834
|
if (!this.locusUrl) {
|
858
835
|
return Promise.reject(
|
859
836
|
new ParameterError('The associated locus url for this meeting object must be defined.')
|
@@ -871,13 +848,13 @@ export default class Members extends StatelessWebexPlugin {
|
|
871
848
|
|
872
849
|
/**
|
873
850
|
* Cancels an SIP/phone call to the associated meeting
|
874
|
-
* @param {
|
851
|
+
* @param {Invitee} invitee
|
875
852
|
* @param {String} invitee.memberId - The memberId of the invitee
|
876
853
|
* @param {Boolean} [invitee.isInternalNumber] - When cancel phone invitation, if the number is internal
|
877
854
|
* @returns {Promise}
|
878
855
|
* @memberof Members
|
879
856
|
*/
|
880
|
-
cancelInviteByMemberId(invitee:
|
857
|
+
cancelInviteByMemberId(invitee: Invitee) {
|
881
858
|
if (!this.locusUrl) {
|
882
859
|
return Promise.reject(
|
883
860
|
new ParameterError('The associated locus url for this meeting object must be defined.')
|
package/src/members/util.ts
CHANGED
@@ -14,6 +14,7 @@ import {
|
|
14
14
|
} from '../constants';
|
15
15
|
|
16
16
|
import {RoleAssignmentOptions, RoleAssignmentRequest, ServerRoleShape} from './types';
|
17
|
+
import {Invitee} from '../meeting/type';
|
17
18
|
|
18
19
|
const MembersUtil = {
|
19
20
|
/**
|
@@ -105,7 +106,7 @@ const MembersUtil = {
|
|
105
106
|
return requestParams;
|
106
107
|
},
|
107
108
|
|
108
|
-
isInvalidInvitee: (invitee) => {
|
109
|
+
isInvalidInvitee: (invitee: Invitee) => {
|
109
110
|
if (!(invitee && (invitee.email || invitee.emailAddress || invitee.phoneNumber))) {
|
110
111
|
return true;
|
111
112
|
}
|
@@ -15,7 +15,7 @@ import {cloneDeepWith, debounce, isEmpty} from 'lodash';
|
|
15
15
|
import LoggerProxy from '../common/logs/logger-proxy';
|
16
16
|
|
17
17
|
import {ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';
|
18
|
-
import {
|
18
|
+
import {MAX_FS_VALUES} from './remoteMedia';
|
19
19
|
|
20
20
|
export interface ActiveSpeakerPolicyInfo {
|
21
21
|
policy: 'active-speaker';
|
@@ -123,12 +123,12 @@ export class MediaRequestManager {
|
|
123
123
|
|
124
124
|
private getDegradedClientRequests(clientRequests: ClientRequestsMap) {
|
125
125
|
const maxFsLimits = [
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
126
|
+
MAX_FS_VALUES['1080p'],
|
127
|
+
MAX_FS_VALUES['720p'],
|
128
|
+
MAX_FS_VALUES['540p'],
|
129
|
+
MAX_FS_VALUES['360p'],
|
130
|
+
MAX_FS_VALUES['180p'],
|
131
|
+
MAX_FS_VALUES['90p'],
|
132
132
|
];
|
133
133
|
|
134
134
|
// reduce max-fs until total macroblocks is below limit
|
@@ -19,17 +19,18 @@ export type RemoteVideoResolution =
|
|
19
19
|
| 'large' // 1080p or less
|
20
20
|
| 'best'; // highest possible resolution
|
21
21
|
|
22
|
-
const MAX_FS_VALUES = {
|
22
|
+
export const MAX_FS_VALUES = {
|
23
23
|
'90p': 60,
|
24
24
|
'180p': 240,
|
25
25
|
'360p': 920,
|
26
|
+
'540p': 2040,
|
26
27
|
'720p': 3600,
|
27
28
|
'1080p': 8192,
|
28
29
|
};
|
29
30
|
|
30
31
|
/**
|
31
32
|
* Converts pane size into h264 maxFs
|
32
|
-
* @param {
|
33
|
+
* @param {RemoteVideoResolution} paneSize
|
33
34
|
* @returns {number}
|
34
35
|
*/
|
35
36
|
export function getMaxFs(paneSize: RemoteVideoResolution): number {
|
@@ -89,6 +90,13 @@ export class RemoteMedia extends EventsScope {
|
|
89
90
|
|
90
91
|
public readonly id: RemoteMediaId;
|
91
92
|
|
93
|
+
/**
|
94
|
+
* The max frame size of the media request, used for logging and media requests.
|
95
|
+
* Set by setSizeHint() based on video element dimensions.
|
96
|
+
* When > 0, this value takes precedence over options.resolution in sendMediaRequest().
|
97
|
+
*/
|
98
|
+
private maxFrameSize = 0;
|
99
|
+
|
92
100
|
/**
|
93
101
|
* Constructs RemoteMedia instance
|
94
102
|
*
|
@@ -136,15 +144,34 @@ export class RemoteMedia extends EventsScope {
|
|
136
144
|
fs = MAX_FS_VALUES['180p'];
|
137
145
|
} else if (height < getThresholdHeight(360)) {
|
138
146
|
fs = MAX_FS_VALUES['360p'];
|
147
|
+
} else if (height < getThresholdHeight(540)) {
|
148
|
+
fs = MAX_FS_VALUES['540p'];
|
139
149
|
} else if (height <= 720) {
|
140
150
|
fs = MAX_FS_VALUES['720p'];
|
141
151
|
} else {
|
142
152
|
fs = MAX_FS_VALUES['1080p'];
|
143
153
|
}
|
144
154
|
|
155
|
+
this.maxFrameSize = fs;
|
145
156
|
this.receiveSlot?.setMaxFs(fs);
|
146
157
|
}
|
147
158
|
|
159
|
+
/**
|
160
|
+
* Get the current effective maxFs value that would be used in media requests
|
161
|
+
* @returns {number | undefined} The maxFs value, or undefined if no constraints
|
162
|
+
*/
|
163
|
+
public getEffectiveMaxFs(): number | undefined {
|
164
|
+
if (this.maxFrameSize > 0) {
|
165
|
+
return this.maxFrameSize;
|
166
|
+
}
|
167
|
+
|
168
|
+
if (this.options.resolution) {
|
169
|
+
return getMaxFs(this.options.resolution);
|
170
|
+
}
|
171
|
+
|
172
|
+
return undefined;
|
173
|
+
}
|
174
|
+
|
148
175
|
/**
|
149
176
|
* Invalidates the remote media by clearing the reference to a receive slot and
|
150
177
|
* cancelling the media request.
|
@@ -185,6 +212,9 @@ export class RemoteMedia extends EventsScope {
|
|
185
212
|
throw new Error('sendMediaRequest() called on an invalidated RemoteMedia instance');
|
186
213
|
}
|
187
214
|
|
215
|
+
// Use maxFrameSize from setSizeHint if available, otherwise fallback to options.resolution
|
216
|
+
const maxFs = this.getEffectiveMaxFs();
|
217
|
+
|
188
218
|
this.mediaRequestId = this.mediaRequestManager.addRequest(
|
189
219
|
{
|
190
220
|
policyInfo: {
|
@@ -192,9 +222,9 @@ export class RemoteMedia extends EventsScope {
|
|
192
222
|
csi,
|
193
223
|
},
|
194
224
|
receiveSlots: [this.receiveSlot],
|
195
|
-
codecInfo:
|
225
|
+
codecInfo: maxFs && {
|
196
226
|
codec: 'h264',
|
197
|
-
maxFs
|
227
|
+
maxFs,
|
198
228
|
},
|
199
229
|
},
|
200
230
|
commit
|
@@ -215,6 +215,9 @@ export class RemoteMediaGroup {
|
|
215
215
|
private sendActiveSpeakerMediaRequest(commit: boolean) {
|
216
216
|
this.cancelActiveSpeakerMediaRequest(false);
|
217
217
|
|
218
|
+
// Calculate the effective maxFs based on all unpinned RemoteMedia instances
|
219
|
+
const effectiveMaxFs = this.getEffectiveMaxFsForActiveSpeaker();
|
220
|
+
|
218
221
|
this.mediaRequestId = this.mediaRequestManager.addRequest(
|
219
222
|
{
|
220
223
|
policyInfo: {
|
@@ -230,9 +233,9 @@ export class RemoteMediaGroup {
|
|
230
233
|
receiveSlots: this.unpinnedRemoteMedia.map((remoteMedia) =>
|
231
234
|
remoteMedia.getUnderlyingReceiveSlot()
|
232
235
|
) as ReceiveSlot[],
|
233
|
-
codecInfo:
|
236
|
+
codecInfo: effectiveMaxFs && {
|
234
237
|
codec: 'h264',
|
235
|
-
maxFs:
|
238
|
+
maxFs: effectiveMaxFs,
|
236
239
|
},
|
237
240
|
},
|
238
241
|
commit
|
@@ -300,4 +303,36 @@ export class RemoteMediaGroup {
|
|
300
303
|
this.unpinnedRemoteMedia.includes(remoteMedia) || this.pinnedRemoteMedia.includes(remoteMedia)
|
301
304
|
);
|
302
305
|
}
|
306
|
+
|
307
|
+
/**
|
308
|
+
* Calculate the effective maxFs for the active speaker media request based on unpinned RemoteMedia instances
|
309
|
+
* @returns {number | undefined} The calculated maxFs value, or undefined if no constraints
|
310
|
+
* @private
|
311
|
+
*/
|
312
|
+
private getEffectiveMaxFsForActiveSpeaker(): number | undefined {
|
313
|
+
// Get all effective maxFs values from unpinned RemoteMedia instances
|
314
|
+
const maxFsValues = this.unpinnedRemoteMedia
|
315
|
+
.map((remoteMedia) => remoteMedia.getEffectiveMaxFs())
|
316
|
+
.filter((maxFs) => maxFs !== undefined);
|
317
|
+
|
318
|
+
// Use the highest maxFs value to ensure we don't under-request resolution for any instance
|
319
|
+
if (maxFsValues.length > 0) {
|
320
|
+
return Math.max(...maxFsValues);
|
321
|
+
}
|
322
|
+
|
323
|
+
// Fall back to group's resolution option
|
324
|
+
if (this.options.resolution) {
|
325
|
+
return getMaxFs(this.options.resolution);
|
326
|
+
}
|
327
|
+
|
328
|
+
return undefined;
|
329
|
+
}
|
330
|
+
|
331
|
+
/**
|
332
|
+
* Get the current effective maxFs that would be used for the active speaker media request
|
333
|
+
* @returns {number | undefined} The effective maxFs value
|
334
|
+
*/
|
335
|
+
public getEffectiveMaxFs(): number | undefined {
|
336
|
+
return this.getEffectiveMaxFsForActiveSpeaker();
|
337
|
+
}
|
303
338
|
}
|