@webex/plugin-meetings 3.0.0-beta.43 → 3.0.0-beta.45

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.
Files changed (57) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +12 -3
  3. package/dist/breakouts/index.js.map +1 -1
  4. package/dist/constants.js +15 -3
  5. package/dist/constants.js.map +1 -1
  6. package/dist/locus-info/controlsUtils.js +6 -2
  7. package/dist/locus-info/controlsUtils.js.map +1 -1
  8. package/dist/locus-info/index.js +35 -1
  9. package/dist/locus-info/index.js.map +1 -1
  10. package/dist/locus-info/selfUtils.js +28 -0
  11. package/dist/locus-info/selfUtils.js.map +1 -1
  12. package/dist/meeting/in-meeting-actions.js +9 -1
  13. package/dist/meeting/in-meeting-actions.js.map +1 -1
  14. package/dist/meeting/index.js +43 -4
  15. package/dist/meeting/index.js.map +1 -1
  16. package/dist/meeting/muteState.js +45 -20
  17. package/dist/meeting/muteState.js.map +1 -1
  18. package/dist/meeting/util.js +15 -0
  19. package/dist/meeting/util.js.map +1 -1
  20. package/dist/members/index.js +15 -3
  21. package/dist/members/index.js.map +1 -1
  22. package/dist/members/util.js +33 -12
  23. package/dist/members/util.js.map +1 -1
  24. package/dist/multistream/remoteMediaManager.js +112 -55
  25. package/dist/multistream/remoteMediaManager.js.map +1 -1
  26. package/dist/types/constants.d.ts +11 -0
  27. package/dist/types/locus-info/index.d.ts +7 -0
  28. package/dist/types/meeting/in-meeting-actions.d.ts +8 -0
  29. package/dist/types/meeting/index.d.ts +12 -2
  30. package/dist/types/meeting/muteState.d.ts +16 -0
  31. package/dist/types/members/index.d.ts +7 -2
  32. package/dist/types/multistream/remoteMediaManager.d.ts +20 -2
  33. package/package.json +18 -18
  34. package/src/breakouts/index.ts +8 -1
  35. package/src/constants.ts +13 -0
  36. package/src/locus-info/controlsUtils.ts +8 -0
  37. package/src/locus-info/index.ts +42 -1
  38. package/src/locus-info/selfUtils.ts +34 -0
  39. package/src/meeting/in-meeting-actions.ts +16 -0
  40. package/src/meeting/index.ts +53 -4
  41. package/src/meeting/muteState.ts +49 -30
  42. package/src/meeting/util.ts +15 -0
  43. package/src/members/index.ts +12 -4
  44. package/src/members/util.ts +21 -8
  45. package/src/multistream/remoteMediaManager.ts +57 -26
  46. package/test/unit/spec/breakouts/index.ts +2 -2
  47. package/test/unit/spec/locus-info/controlsUtils.js +104 -46
  48. package/test/unit/spec/locus-info/index.js +131 -16
  49. package/test/unit/spec/locus-info/selfConstant.js +9 -5
  50. package/test/unit/spec/locus-info/selfUtils.js +39 -16
  51. package/test/unit/spec/meeting/in-meeting-actions.ts +9 -1
  52. package/test/unit/spec/meeting/index.js +208 -79
  53. package/test/unit/spec/meeting/muteState.js +72 -6
  54. package/test/unit/spec/meeting/utils.js +35 -0
  55. package/test/unit/spec/members/index.js +75 -0
  56. package/test/unit/spec/members/utils.js +112 -0
  57. package/test/unit/spec/multistream/remoteMediaManager.ts +127 -0
@@ -82,6 +82,7 @@ describe('plugin-meetings', () => {
82
82
  meetingContainerUrl: 'http://new-url.com',
83
83
  },
84
84
  entryExitTone: {enabled: true, mode: 'foo'},
85
+ video: {enabled: true},
85
86
  };
86
87
  });
87
88
 
@@ -291,7 +292,7 @@ describe('plugin-meetings', () => {
291
292
  },
292
293
  LOCUSINFO.EVENTS.CONTROLS_MEETING_BREAKOUT_UPDATED,
293
294
  {
294
- breakout: 'new breakout'
295
+ breakout: 'new breakout',
295
296
  }
296
297
  );
297
298
  });
@@ -417,6 +418,39 @@ describe('plugin-meetings', () => {
417
418
  assert.notEqual(x.args[1], LOCUSINFO.EVENTS.CONTROLS_ENTRY_EXIT_TONE_UPDATED);
418
419
  });
419
420
  });
421
+
422
+ it('should update videoEnabled when changed', () => {
423
+ locusInfo.controls = {};
424
+
425
+ locusInfo.emitScoped = sinon.stub();
426
+ locusInfo.updateControls(newControls);
427
+
428
+ assert.calledWith(
429
+ locusInfo.emitScoped,
430
+ {
431
+ file: 'locus-info',
432
+ function: 'updateControls',
433
+ },
434
+ LOCUSINFO.EVENTS.CONTROLS_VIDEO_ENABLED_UPDATED,
435
+ {unmuteAllowed: true}
436
+ );
437
+
438
+ assert.equal(mockMeeting.unmuteVideoAllowed, true);
439
+ });
440
+
441
+ it('should not update videoEnabled when unchanged', () => {
442
+ locusInfo.controls = {videoEnabled: true};
443
+
444
+ locusInfo.emitScoped = sinon.stub();
445
+ locusInfo.updateControls(newControls);
446
+
447
+ locusInfo.emitScoped.getCalls().forEach((x) => {
448
+ // check that no calls in emitScoped are for CONTROLS_VIDEO_ENABLED_UPDATED
449
+ assert.notEqual(x.args[1], LOCUSINFO.EVENTS.CONTROLS_VIDEO_ENABLED_UPDATED);
450
+ });
451
+
452
+ assert.equal(mockMeeting.unmuteVideoAllowed, undefined);
453
+ });
420
454
  });
421
455
 
422
456
  describe('#updateParticipants()', () => {
@@ -683,6 +717,83 @@ describe('plugin-meetings', () => {
683
717
  );
684
718
  });
685
719
 
720
+ describe('SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED', () => {
721
+ it('should emit event when video muted on entry', () => {
722
+ // usually "previous self" is just undefined when we get first self from locus
723
+ locusInfo.self = undefined;
724
+ const selfWithMutedByOthers = cloneDeep(self);
725
+
726
+ // remoteVideoMuted
727
+ selfWithMutedByOthers.controls.video.muted = true;
728
+
729
+ locusInfo.webex.internal.device.url = self.deviceUrl;
730
+ locusInfo.emitScoped = sinon.stub();
731
+ locusInfo.updateSelf(selfWithMutedByOthers, []);
732
+
733
+ assert.calledWith(
734
+ locusInfo.emitScoped,
735
+ {
736
+ file: 'locus-info',
737
+ function: 'updateSelf',
738
+ },
739
+ LOCUSINFO.EVENTS.SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED,
740
+ {muted: true}
741
+ );
742
+
743
+ // but sometimes "previous self" is defined, but without controls.audio.muted, so we test this here:
744
+ locusInfo.self = cloneDeep(self);
745
+ locusInfo.self.controls.video = {};
746
+
747
+ locusInfo.updateSelf(selfWithMutedByOthers, []);
748
+ assert.calledWith(
749
+ locusInfo.emitScoped,
750
+ {
751
+ file: 'locus-info',
752
+ function: 'updateSelf',
753
+ },
754
+ LOCUSINFO.EVENTS.SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED,
755
+ {muted: true}
756
+ );
757
+ });
758
+
759
+ it('should not emit event when not muted on entry', () => {
760
+ locusInfo.self = undefined;
761
+ const selfWithMutedByOthersFalse = cloneDeep(self);
762
+
763
+ selfWithMutedByOthersFalse.controls.video.muted = false;
764
+
765
+ locusInfo.webex.internal.device.url = self.deviceUrl;
766
+ locusInfo.emitScoped = sinon.stub();
767
+ locusInfo.updateSelf(selfWithMutedByOthersFalse, []);
768
+
769
+ // we might get some calls to emitScoped, but we need to check that none of them are for SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED
770
+ locusInfo.emitScoped.getCalls().forEach((x) => {
771
+ assert.notEqual(x.args[1], LOCUSINFO.EVENTS.SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED);
772
+ });
773
+ });
774
+
775
+ it('should emit event when remoteVideoMuted changed', () => {
776
+ locusInfo.self = self;
777
+ const selfWithMutedByOthers = cloneDeep(self);
778
+
779
+ selfWithMutedByOthers.controls.video.muted = true;
780
+
781
+ locusInfo.webex.internal.device.url = self.deviceUrl;
782
+ locusInfo.emitScoped = sinon.stub();
783
+ locusInfo.updateSelf(selfWithMutedByOthers, []);
784
+
785
+ assert.calledWith(
786
+ locusInfo.emitScoped,
787
+ {
788
+ file: 'locus-info',
789
+ function: 'updateSelf',
790
+ },
791
+ LOCUSINFO.EVENTS.SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED,
792
+ {muted: true}
793
+ );
794
+ });
795
+ });
796
+
686
797
  it('should trigger SELF_MEETING_BREAKOUTS_CHANGED when breakouts changed', () => {
687
798
  locusInfo.self = self;
688
799
  const selfWithBreakoutsChanged = cloneDeep(self);
@@ -701,19 +812,23 @@ describe('plugin-meetings', () => {
701
812
  LOCUSINFO.EVENTS.SELF_MEETING_BREAKOUTS_CHANGED,
702
813
  {
703
814
  breakoutSessions: {
704
- active: [{
705
- name: 'new name',
706
- groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
707
- sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
708
- sessionType: 'BREAKOUT'
709
- }],
710
- allowed: [{
711
- name: 'Breakout session 2',
712
- groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
713
- sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
714
- sessionType: 'BREAKOUT'
715
- }]
716
- }
815
+ active: [
816
+ {
817
+ name: 'new name',
818
+ groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
819
+ sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
820
+ sessionType: 'BREAKOUT',
821
+ },
822
+ ],
823
+ allowed: [
824
+ {
825
+ name: 'Breakout session 2',
826
+ groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
827
+ sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
828
+ sessionType: 'BREAKOUT',
829
+ },
830
+ ],
831
+ },
717
832
  }
718
833
  );
719
834
  });
@@ -1205,8 +1320,8 @@ describe('plugin-meetings', () => {
1205
1320
  const newLocus = {
1206
1321
  self: {
1207
1322
  reason: 'MOVED',
1208
- state: 'LEFT'
1209
- }
1323
+ state: 'LEFT',
1324
+ },
1210
1325
  };
1211
1326
 
1212
1327
  locusInfo.updateControls = sinon.stub();
@@ -109,6 +109,10 @@ export const self = {
109
109
  requestedToUnmute: false,
110
110
  meta: {},
111
111
  },
112
+ video: {
113
+ muted: false,
114
+ meta: {},
115
+ },
112
116
  breakout: {
113
117
  sessions: {
114
118
  active: [
@@ -116,7 +120,7 @@ export const self = {
116
120
  name: 'Breakout session 2',
117
121
  groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
118
122
  sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
119
- sessionType: 'BREAKOUT'
123
+ sessionType: 'BREAKOUT',
120
124
  },
121
125
  ],
122
126
  allowed: [
@@ -124,15 +128,15 @@ export const self = {
124
128
  name: 'Breakout session 2',
125
129
  groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
126
130
  sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
127
- sessionType: 'BREAKOUT'
131
+ sessionType: 'BREAKOUT',
128
132
  },
129
- ]
133
+ ],
130
134
  },
131
135
  meta: {
132
136
  modifiedBy: '347ef89e-e1be-40a3-849c-731bdd935e62',
133
137
  lastModified: '2023-01-10T10:10:06.813Z',
134
- readOnly: true
135
- }
138
+ readOnly: true,
139
+ },
136
140
  },
137
141
  localRecord: {
138
142
  recording: false,
@@ -39,7 +39,7 @@ describe('plugin-meetings', () => {
39
39
  name: 'Breakout session 2',
40
40
  groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
41
41
  sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
42
- sessionType: 'BREAKOUT'
42
+ sessionType: 'BREAKOUT',
43
43
  },
44
44
  ],
45
45
  allowed: [
@@ -47,9 +47,9 @@ describe('plugin-meetings', () => {
47
47
  name: 'Breakout session 2',
48
48
  groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
49
49
  sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
50
- sessionType: 'BREAKOUT'
50
+ sessionType: 'BREAKOUT',
51
51
  },
52
- ]
52
+ ],
53
53
  });
54
54
  });
55
55
 
@@ -78,7 +78,10 @@ describe('plugin-meetings', () => {
78
78
 
79
79
  describe('getBreakouts', () => {
80
80
  it('should return breakout sessions', () => {
81
- assert.deepEqual(SelfUtils.getBreakouts({controls: {breakout: {sessions: 'SESSIONS'}}}), 'SESSIONS');
81
+ assert.deepEqual(
82
+ SelfUtils.getBreakouts({controls: {breakout: {sessions: 'SESSIONS'}}}),
83
+ 'SESSIONS'
84
+ );
82
85
  });
83
86
  });
84
87
 
@@ -91,10 +94,10 @@ describe('plugin-meetings', () => {
91
94
  name: 'Breakout session 2',
92
95
  groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
93
96
  sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
94
- sessionType: 'BREAKOUT'
97
+ sessionType: 'BREAKOUT',
95
98
  },
96
- ]
97
- }
99
+ ],
100
+ },
98
101
  };
99
102
  const previous = {
100
103
  breakoutSessions: {
@@ -103,10 +106,10 @@ describe('plugin-meetings', () => {
103
106
  name: 'Breakout session 2',
104
107
  groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
105
108
  sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
106
- sessionType: 'BREAKOUT'
109
+ sessionType: 'BREAKOUT',
107
110
  },
108
- ]
109
- }
111
+ ],
112
+ },
110
113
  };
111
114
 
112
115
  assert.isTrue(SelfUtils.breakoutsChanged(previous, current));
@@ -120,10 +123,10 @@ describe('plugin-meetings', () => {
120
123
  name: 'Breakout session 2',
121
124
  groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
122
125
  sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
123
- sessionType: 'BREAKOUT'
126
+ sessionType: 'BREAKOUT',
124
127
  },
125
- ]
126
- }
128
+ ],
129
+ },
127
130
  };
128
131
  const previous = {
129
132
  breakoutSessions: {
@@ -132,10 +135,10 @@ describe('plugin-meetings', () => {
132
135
  name: 'Breakout session 2',
133
136
  groupId: '0e73abb8-5584-49d8-be8d-806d2a8247ca',
134
137
  sessionId: '1cf41ab1-2e57-4d95-b7e9-5613acddfb0f',
135
- sessionType: 'BREAKOUT'
138
+ sessionType: 'BREAKOUT',
136
139
  },
137
- ]
138
- }
140
+ ],
141
+ },
139
142
  };
140
143
 
141
144
  assert.isFalse(SelfUtils.breakoutsChanged(previous, current));
@@ -266,4 +269,24 @@ describe('plugin-meetings', () => {
266
269
  assert.deepEqual(SelfUtils.isJoined(customSelf), false);
267
270
  });
268
271
  });
272
+
273
+ describe('videoMutedByOthersChanged', () => {
274
+ it('returns true if changed', () => {
275
+ assert.equal(
276
+ SelfUtils.videoMutedByOthersChanged({remoteVideoMuted: true}, {remoteVideoMuted: false}),
277
+ true
278
+ );
279
+ });
280
+
281
+ it('returns true if changed from undefined', () => {
282
+ assert.equal(SelfUtils.videoMutedByOthersChanged({}, {remoteVideoMuted: false}), true);
283
+ });
284
+
285
+ it('returns false if not changed', () => {
286
+ assert.equal(
287
+ SelfUtils.videoMutedByOthersChanged({remoteVideoMuted: false}, {remoteVideoMuted: false}),
288
+ false
289
+ );
290
+ });
291
+ });
269
292
  });
@@ -35,6 +35,10 @@ describe('plugin-meetings', () => {
35
35
  waitingForOthersToJoin: null,
36
36
  canEnableReactions: null,
37
37
  canSendReactions: null,
38
+ canManageBreakout: null,
39
+ canAdmitLobbyToBreakout: null,
40
+ canUserAskForHelp: null,
41
+ isBreakoutPreassignmentsEnabled: null,
38
42
  ...expected
39
43
  };
40
44
 
@@ -74,7 +78,11 @@ describe('plugin-meetings', () => {
74
78
  'canSelectSpokenLanguages',
75
79
  'waitingForOthersToJoin',
76
80
  'canEnableReactions',
77
- 'canSendReactions'
81
+ 'canSendReactions',
82
+ 'canManageBreakout',
83
+ 'canAdmitLobbyToBreakout',
84
+ 'canUserAskForHelp',
85
+ 'isBreakoutPreassignmentsEnabled'
78
86
  ].forEach((key) => {
79
87
  it(`get and set for ${key} work as expected`, () => {
80
88
  const inMeetingActions = new InMeetingActions();