@webex/plugin-meetings 3.8.0-next.8 → 3.8.0-next.80

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 (171) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +70 -6
  3. package/dist/breakouts/index.js.map +1 -1
  4. package/dist/common/errors/webex-errors.js +12 -2
  5. package/dist/common/errors/webex-errors.js.map +1 -1
  6. package/dist/config.js +5 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/constants.js +20 -123
  9. package/dist/constants.js.map +1 -1
  10. package/dist/controls-options-manager/enums.js +2 -0
  11. package/dist/controls-options-manager/enums.js.map +1 -1
  12. package/dist/controls-options-manager/types.js.map +1 -1
  13. package/dist/controls-options-manager/util.js +52 -0
  14. package/dist/controls-options-manager/util.js.map +1 -1
  15. package/dist/interpretation/index.js +1 -1
  16. package/dist/interpretation/siLanguage.js +1 -1
  17. package/dist/locus-info/controlsUtils.js +28 -10
  18. package/dist/locus-info/controlsUtils.js.map +1 -1
  19. package/dist/locus-info/index.js +62 -12
  20. package/dist/locus-info/index.js.map +1 -1
  21. package/dist/locus-info/selfUtils.js +432 -418
  22. package/dist/locus-info/selfUtils.js.map +1 -1
  23. package/dist/media/index.js +17 -17
  24. package/dist/media/index.js.map +1 -1
  25. package/dist/media/properties.js +94 -6
  26. package/dist/media/properties.js.map +1 -1
  27. package/dist/meeting/brbState.js +6 -0
  28. package/dist/meeting/brbState.js.map +1 -1
  29. package/dist/meeting/in-meeting-actions.js +17 -1
  30. package/dist/meeting/in-meeting-actions.js.map +1 -1
  31. package/dist/meeting/index.js +570 -302
  32. package/dist/meeting/index.js.map +1 -1
  33. package/dist/meeting/locusMediaRequest.js +0 -17
  34. package/dist/meeting/locusMediaRequest.js.map +1 -1
  35. package/dist/meeting/muteState.js +0 -2
  36. package/dist/meeting/muteState.js.map +1 -1
  37. package/dist/meeting/request.js +30 -0
  38. package/dist/meeting/request.js.map +1 -1
  39. package/dist/meeting/request.type.js.map +1 -1
  40. package/dist/meeting/util.js +13 -2
  41. package/dist/meeting/util.js.map +1 -1
  42. package/dist/meeting-info/meeting-info-v2.js +373 -68
  43. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  44. package/dist/meeting-info/utilv2.js +5 -1
  45. package/dist/meeting-info/utilv2.js.map +1 -1
  46. package/dist/meetings/index.js +136 -1
  47. package/dist/meetings/index.js.map +1 -1
  48. package/dist/meetings/util.js +14 -0
  49. package/dist/meetings/util.js.map +1 -1
  50. package/dist/member/index.js +10 -0
  51. package/dist/member/index.js.map +1 -1
  52. package/dist/member/util.js +330 -353
  53. package/dist/member/util.js.map +1 -1
  54. package/dist/members/index.js +42 -0
  55. package/dist/members/index.js.map +1 -1
  56. package/dist/members/request.js +38 -0
  57. package/dist/members/request.js.map +1 -1
  58. package/dist/members/util.js +36 -1
  59. package/dist/members/util.js.map +1 -1
  60. package/dist/metrics/constants.js +9 -0
  61. package/dist/metrics/constants.js.map +1 -1
  62. package/dist/reachability/clusterReachability.js +63 -27
  63. package/dist/reachability/clusterReachability.js.map +1 -1
  64. package/dist/reachability/index.js +112 -47
  65. package/dist/reachability/index.js.map +1 -1
  66. package/dist/reachability/reachability.types.js +14 -0
  67. package/dist/reachability/reachability.types.js.map +1 -1
  68. package/dist/reachability/request.js +19 -3
  69. package/dist/reachability/request.js.map +1 -1
  70. package/dist/reconnection-manager/index.js +2 -2
  71. package/dist/reconnection-manager/index.js.map +1 -1
  72. package/dist/roap/index.js.map +1 -1
  73. package/dist/roap/turnDiscovery.js +45 -27
  74. package/dist/roap/turnDiscovery.js.map +1 -1
  75. package/dist/roap/types.js +17 -0
  76. package/dist/roap/types.js.map +1 -0
  77. package/dist/types/common/errors/webex-errors.d.ts +7 -1
  78. package/dist/types/config.d.ts +3 -0
  79. package/dist/types/constants.d.ts +13 -85
  80. package/dist/types/controls-options-manager/enums.d.ts +3 -1
  81. package/dist/types/controls-options-manager/types.d.ts +7 -1
  82. package/dist/types/locus-info/index.d.ts +3 -3
  83. package/dist/types/locus-info/selfUtils.d.ts +216 -1
  84. package/dist/types/media/properties.d.ts +15 -0
  85. package/dist/types/meeting/in-meeting-actions.d.ts +16 -0
  86. package/dist/types/meeting/index.d.ts +43 -1
  87. package/dist/types/meeting/muteState.d.ts +0 -1
  88. package/dist/types/meeting/request.d.ts +12 -1
  89. package/dist/types/meeting/request.type.d.ts +6 -0
  90. package/dist/types/meeting/util.d.ts +3 -1
  91. package/dist/types/meeting-info/meeting-info-v2.d.ts +82 -1
  92. package/dist/types/meetings/index.d.ts +57 -0
  93. package/dist/types/member/index.d.ts +1 -0
  94. package/dist/types/member/util.d.ts +159 -1
  95. package/dist/types/members/index.d.ts +15 -0
  96. package/dist/types/members/request.d.ts +26 -0
  97. package/dist/types/members/util.d.ts +27 -0
  98. package/dist/types/metrics/constants.d.ts +9 -0
  99. package/dist/types/reachability/clusterReachability.d.ts +15 -7
  100. package/dist/types/reachability/index.d.ts +10 -1
  101. package/dist/types/reachability/reachability.types.d.ts +5 -0
  102. package/dist/types/roap/index.d.ts +3 -2
  103. package/dist/types/roap/turnDiscovery.d.ts +5 -17
  104. package/dist/types/roap/types.d.ts +16 -0
  105. package/dist/webinar/index.js +1 -1
  106. package/package.json +24 -23
  107. package/src/breakouts/index.ts +69 -0
  108. package/src/common/errors/webex-errors.ts +8 -1
  109. package/src/config.ts +3 -0
  110. package/src/constants.ts +20 -90
  111. package/src/controls-options-manager/enums.ts +2 -0
  112. package/src/controls-options-manager/types.ts +11 -1
  113. package/src/controls-options-manager/util.ts +62 -0
  114. package/src/locus-info/controlsUtils.ts +44 -14
  115. package/src/locus-info/index.ts +56 -13
  116. package/src/locus-info/selfUtils.ts +496 -442
  117. package/src/media/index.ts +23 -21
  118. package/src/media/properties.ts +96 -0
  119. package/src/meeting/brbState.ts +7 -0
  120. package/src/meeting/in-meeting-actions.ts +32 -0
  121. package/src/meeting/index.ts +382 -93
  122. package/src/meeting/locusMediaRequest.ts +0 -18
  123. package/src/meeting/muteState.ts +0 -2
  124. package/src/meeting/request.ts +36 -1
  125. package/src/meeting/request.type.ts +7 -0
  126. package/src/meeting/util.ts +11 -2
  127. package/src/meeting-info/meeting-info-v2.ts +254 -8
  128. package/src/meeting-info/utilv2.ts +5 -0
  129. package/src/meetings/index.ts +148 -1
  130. package/src/meetings/util.ts +18 -0
  131. package/src/member/index.ts +13 -2
  132. package/src/member/util.ts +351 -348
  133. package/src/members/index.ts +47 -0
  134. package/src/members/request.ts +44 -0
  135. package/src/members/util.ts +43 -1
  136. package/src/metrics/constants.ts +9 -0
  137. package/src/reachability/clusterReachability.ts +73 -26
  138. package/src/reachability/index.ts +70 -1
  139. package/src/reachability/reachability.types.ts +6 -0
  140. package/src/reachability/request.ts +7 -0
  141. package/src/reconnection-manager/index.ts +2 -2
  142. package/src/roap/index.ts +3 -7
  143. package/src/roap/turnDiscovery.ts +34 -39
  144. package/src/roap/types.ts +23 -0
  145. package/test/unit/spec/breakouts/index.ts +167 -95
  146. package/test/unit/spec/controls-options-manager/util.js +120 -0
  147. package/test/unit/spec/locus-info/controlsUtils.js +103 -9
  148. package/test/unit/spec/locus-info/index.js +167 -73
  149. package/test/unit/spec/locus-info/selfUtils.js +98 -24
  150. package/test/unit/spec/media/index.ts +150 -18
  151. package/test/unit/spec/media/properties.ts +130 -0
  152. package/test/unit/spec/meeting/brbState.ts +19 -0
  153. package/test/unit/spec/meeting/in-meeting-actions.ts +19 -4
  154. package/test/unit/spec/meeting/index.js +557 -35
  155. package/test/unit/spec/meeting/locusMediaRequest.ts +0 -30
  156. package/test/unit/spec/meeting/muteState.js +0 -2
  157. package/test/unit/spec/meeting/request.js +32 -1
  158. package/test/unit/spec/meeting/utils.js +119 -18
  159. package/test/unit/spec/meeting-info/meetinginfov2.js +484 -114
  160. package/test/unit/spec/meeting-info/utilv2.js +19 -0
  161. package/test/unit/spec/meetings/index.js +146 -2
  162. package/test/unit/spec/member/index.js +7 -0
  163. package/test/unit/spec/member/util.js +24 -0
  164. package/test/unit/spec/members/index.js +140 -26
  165. package/test/unit/spec/members/request.js +68 -22
  166. package/test/unit/spec/members/utils.js +75 -0
  167. package/test/unit/spec/reachability/clusterReachability.ts +88 -56
  168. package/test/unit/spec/reachability/index.ts +101 -0
  169. package/test/unit/spec/reachability/request.js +47 -2
  170. package/test/unit/spec/reconnection-manager/index.js +4 -4
  171. package/test/unit/spec/roap/turnDiscovery.ts +110 -28
@@ -111,6 +111,8 @@ describe('plugin-meetings', () => {
111
111
  },
112
112
  webcastControl: {streaming: false},
113
113
  practiceSession: {enabled: true},
114
+ annotationControl: {enabled: true},
115
+ rdcControl: {enabled: true},
114
116
  };
115
117
  });
116
118
 
@@ -278,6 +280,32 @@ describe('plugin-meetings', () => {
278
280
  });
279
281
  });
280
282
 
283
+ it('should trigger the CONTROLS_ANNOTATION_CHANGED event when necessary', () => {
284
+ locusInfo.controls = {};
285
+ locusInfo.emitScoped = sinon.stub();
286
+ locusInfo.updateControls(newControls);
287
+
288
+ assert.calledWith(
289
+ locusInfo.emitScoped,
290
+ {file: 'locus-info', function: 'updateControls'},
291
+ LOCUSINFO.EVENTS.CONTROLS_ANNOTATION_CHANGED,
292
+ {state: newControls.annotationControl}
293
+ );
294
+ });
295
+
296
+ it('should trigger the CONTROLS_REMOTE_DESKTOP_CONTROL_CHANGED event when necessary', () => {
297
+ locusInfo.controls = {};
298
+ locusInfo.emitScoped = sinon.stub();
299
+ locusInfo.updateControls(newControls);
300
+
301
+ assert.calledWith(
302
+ locusInfo.emitScoped,
303
+ {file: 'locus-info', function: 'updateControls'},
304
+ LOCUSINFO.EVENTS.CONTROLS_REMOTE_DESKTOP_CONTROL_CHANGED,
305
+ {state: newControls.rdcControl}
306
+ );
307
+ });
308
+
281
309
  it('should keep the recording state to `IDLE`', () => {
282
310
  locusInfo.controls = {
283
311
  record: {
@@ -797,6 +825,32 @@ describe('plugin-meetings', () => {
797
825
 
798
826
  assert.isTrue(locusInfo.deltaParticipants.length === 0);
799
827
  });
828
+
829
+ it('should call with participant display name', () => {
830
+ const failureParticipant = [
831
+ {
832
+ person: {
833
+ id: 5678,
834
+ primaryDisplayString: 'Test User',
835
+ },
836
+ reason: 'FAILURE',
837
+ },
838
+ ];
839
+
840
+ locusInfo.emitScoped = sinon.stub();
841
+ locusInfo.updateParticipants(failureParticipant);
842
+ assert.calledWith(
843
+ locusInfo.emitScoped,
844
+ {
845
+ file: 'locus-info',
846
+ function: 'updateParticipants',
847
+ },
848
+ LOCUSINFO.EVENTS.PARTICIPANT_REASON_CHANGED,
849
+ {
850
+ displayName: 'Test User',
851
+ }
852
+ );
853
+ })
800
854
  });
801
855
 
802
856
  describe('#updateSelf', () => {
@@ -808,7 +862,7 @@ describe('plugin-meetings', () => {
808
862
  selfWithBrbChanged.controls.brb = enabled;
809
863
 
810
864
  locusInfo.emitScoped = sinon.stub();
811
- locusInfo.updateSelf(selfWithBrbChanged, []);
865
+ locusInfo.updateSelf(selfWithBrbChanged);
812
866
 
813
867
  assert.calledWith(
814
868
  locusInfo.emitScoped,
@@ -828,14 +882,15 @@ describe('plugin-meetings', () => {
828
882
 
829
883
  const selfWithBrbChanged = cloneDeep(self);
830
884
  selfWithBrbChanged.controls.brb = value;
831
- locusInfo.self = selfWithBrbChanged;
885
+
886
+ locusInfo.updateSelf(selfWithBrbChanged);
832
887
 
833
888
  locusInfo.emitScoped = sinon.stub();
834
889
 
835
890
  const newSelf = cloneDeep(self);
836
891
  newSelf.controls.brb = value;
837
892
 
838
- locusInfo.updateSelf(newSelf, []);
893
+ locusInfo.updateSelf(newSelf);
839
894
 
840
895
  assert.neverCalledWith(
841
896
  locusInfo.emitScoped,
@@ -852,14 +907,14 @@ describe('plugin-meetings', () => {
852
907
  it('should not trigger SELF_MEETING_BRB_CHANGED when brb state is undefined', () => {
853
908
  const selfWithBrbChanged = cloneDeep(self);
854
909
  selfWithBrbChanged.controls.brb = false;
855
- locusInfo.self = selfWithBrbChanged;
910
+ locusInfo.updateSelf(selfWithBrbChanged);
856
911
 
857
912
  locusInfo.emitScoped = sinon.stub();
858
913
 
859
914
  const newSelf = cloneDeep(self);
860
915
  newSelf.controls.brb = undefined;
861
916
 
862
- locusInfo.updateSelf(newSelf, []);
917
+ locusInfo.updateSelf(newSelf);
863
918
 
864
919
  assert.neverCalledWith(
865
920
  locusInfo.emitScoped,
@@ -882,7 +937,7 @@ describe('plugin-meetings', () => {
882
937
  ];
883
938
 
884
939
  locusInfo.emitScoped = sinon.stub();
885
- locusInfo.updateSelf(selfWithLayoutChanged, []);
940
+ locusInfo.updateSelf(selfWithLayoutChanged);
886
941
 
887
942
  assert.calledWith(
888
943
  locusInfo.emitScoped,
@@ -908,11 +963,11 @@ describe('plugin-meetings', () => {
908
963
  ];
909
964
 
910
965
  // Set the layout prior to stubbing to validate it does not change.
911
- locusInfo.updateSelf(selfWithLayoutChanged, []);
966
+ locusInfo.updateSelf(selfWithLayoutChanged);
912
967
 
913
968
  locusInfo.emitScoped = sinon.stub();
914
969
 
915
- locusInfo.updateSelf(selfWithLayoutChanged, []);
970
+ locusInfo.updateSelf(selfWithLayoutChanged);
916
971
 
917
972
  assert.neverCalledWith(
918
973
  locusInfo.emitScoped,
@@ -926,11 +981,11 @@ describe('plugin-meetings', () => {
926
981
  });
927
982
 
928
983
  it('should trigger MEDIA_INACTIVITY on server media inactivity', () => {
929
- locusInfo.self = self;
930
-
931
984
  locusInfo.webex.internal.device.url = selfWithInactivity.deviceUrl;
985
+ locusInfo.updateSelf(self);
986
+
932
987
  locusInfo.emitScoped = sinon.stub();
933
- locusInfo.updateSelf(selfWithInactivity, []);
988
+ locusInfo.updateSelf(selfWithInactivity);
934
989
 
935
990
  assert.calledWith(
936
991
  locusInfo.emitScoped,
@@ -952,7 +1007,7 @@ describe('plugin-meetings', () => {
952
1007
 
953
1008
  locusInfo.webex.internal.device.url = self.deviceUrl;
954
1009
  locusInfo.emitScoped = sinon.stub();
955
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1010
+ locusInfo.updateSelf(selfWithMutedByOthers);
956
1011
 
957
1012
  assert.calledWith(
958
1013
  locusInfo.emitScoped,
@@ -965,10 +1020,10 @@ describe('plugin-meetings', () => {
965
1020
  );
966
1021
 
967
1022
  // but sometimes "previous self" is defined, but without controls.audio.muted, so we test this here:
968
- locusInfo.self = cloneDeep(self);
1023
+ locusInfo.updateSelf(self);
969
1024
  locusInfo.self.controls.audio = {};
970
1025
 
971
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1026
+ locusInfo.updateSelf(selfWithMutedByOthers);
972
1027
  assert.calledWith(
973
1028
  locusInfo.emitScoped,
974
1029
  {
@@ -988,7 +1043,7 @@ describe('plugin-meetings', () => {
988
1043
 
989
1044
  locusInfo.webex.internal.device.url = self.deviceUrl;
990
1045
  locusInfo.emitScoped = sinon.stub();
991
- locusInfo.updateSelf(selfWithMutedByOthersFalse, []);
1046
+ locusInfo.updateSelf(selfWithMutedByOthersFalse);
992
1047
 
993
1048
  // we might get some calls to emitScoped, but we need to check that none of them are for SELF_REMOTE_MUTE_STATUS_UPDATED
994
1049
  locusInfo.emitScoped.getCalls().forEach((x) => {
@@ -997,20 +1052,20 @@ describe('plugin-meetings', () => {
997
1052
  });
998
1053
 
999
1054
  it('should not trigger SELF_REMOTE_MUTE_STATUS_UPDATED when being removed from meeting', () => {
1055
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1000
1056
  const selfWithMutedByOthers = cloneDeep(self);
1001
1057
 
1002
1058
  selfWithMutedByOthers.controls.audio.muted = true;
1003
1059
 
1004
- locusInfo.self = selfWithMutedByOthers;
1060
+ locusInfo.updateSelf(selfWithMutedByOthers);
1005
1061
 
1006
1062
  // when user gets removed from meeting we receive a Locus DTO without any self.controls
1007
1063
  const selfWithoutControls = cloneDeep(self);
1008
1064
 
1009
1065
  selfWithoutControls.controls = undefined;
1010
1066
 
1011
- locusInfo.webex.internal.device.url = self.deviceUrl;
1012
1067
  locusInfo.emitScoped = sinon.stub();
1013
- locusInfo.updateSelf(selfWithoutControls, []);
1068
+ locusInfo.updateSelf(selfWithoutControls);
1014
1069
 
1015
1070
  // we might get some calls to emitScoped, but we need to check that none of them are for SELF_REMOTE_MUTE_STATUS_UPDATED
1016
1071
  locusInfo.emitScoped.getCalls().forEach((x) => {
@@ -1019,14 +1074,14 @@ describe('plugin-meetings', () => {
1019
1074
  });
1020
1075
 
1021
1076
  it('should trigger SELF_REMOTE_MUTE_STATUS_UPDATED on othersMuted', () => {
1022
- locusInfo.self = self;
1077
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1078
+ locusInfo.updateSelf(self);
1023
1079
  const selfWithMutedByOthers = cloneDeep(self);
1024
1080
 
1025
1081
  selfWithMutedByOthers.controls.audio.muted = true;
1026
1082
 
1027
- locusInfo.webex.internal.device.url = self.deviceUrl;
1028
1083
  locusInfo.emitScoped = sinon.stub();
1029
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1084
+ locusInfo.updateSelf(selfWithMutedByOthers);
1030
1085
 
1031
1086
  assert.calledWith(
1032
1087
  locusInfo.emitScoped,
@@ -1050,7 +1105,7 @@ describe('plugin-meetings', () => {
1050
1105
 
1051
1106
  locusInfo.webex.internal.device.url = self.deviceUrl;
1052
1107
  locusInfo.emitScoped = sinon.stub();
1053
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1108
+ locusInfo.updateSelf(selfWithMutedByOthers);
1054
1109
 
1055
1110
  assert.calledWith(
1056
1111
  locusInfo.emitScoped,
@@ -1063,10 +1118,10 @@ describe('plugin-meetings', () => {
1063
1118
  );
1064
1119
 
1065
1120
  // but sometimes "previous self" is defined, but without controls.audio.muted, so we test this here:
1066
- locusInfo.self = cloneDeep(self);
1121
+ locusInfo.updateSelf(self);
1067
1122
  locusInfo.self.controls.video = {};
1068
1123
 
1069
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1124
+ locusInfo.updateSelf(selfWithMutedByOthers);
1070
1125
  assert.calledWith(
1071
1126
  locusInfo.emitScoped,
1072
1127
  {
@@ -1086,7 +1141,7 @@ describe('plugin-meetings', () => {
1086
1141
 
1087
1142
  locusInfo.webex.internal.device.url = self.deviceUrl;
1088
1143
  locusInfo.emitScoped = sinon.stub();
1089
- locusInfo.updateSelf(selfWithMutedByOthersFalse, []);
1144
+ locusInfo.updateSelf(selfWithMutedByOthersFalse);
1090
1145
 
1091
1146
  // we might get some calls to emitScoped, but we need to check that none of them are for SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED
1092
1147
  locusInfo.emitScoped.getCalls().forEach((x) => {
@@ -1095,14 +1150,14 @@ describe('plugin-meetings', () => {
1095
1150
  });
1096
1151
 
1097
1152
  it('should emit event when remoteVideoMuted changed', () => {
1098
- locusInfo.self = self;
1153
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1154
+ locusInfo.updateSelf(self);
1099
1155
  const selfWithMutedByOthers = cloneDeep(self);
1100
1156
 
1101
1157
  selfWithMutedByOthers.controls.video.muted = true;
1102
1158
 
1103
- locusInfo.webex.internal.device.url = self.deviceUrl;
1104
1159
  locusInfo.emitScoped = sinon.stub();
1105
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1160
+ locusInfo.updateSelf(selfWithMutedByOthers);
1106
1161
 
1107
1162
  assert.calledWith(
1108
1163
  locusInfo.emitScoped,
@@ -1117,13 +1172,13 @@ describe('plugin-meetings', () => {
1117
1172
  });
1118
1173
 
1119
1174
  it('should trigger SELF_MEETING_BREAKOUTS_CHANGED when breakouts changed', () => {
1120
- locusInfo.self = self;
1175
+ locusInfo.updateSelf(self);
1121
1176
  const selfWithBreakoutsChanged = cloneDeep(self);
1122
1177
 
1123
1178
  selfWithBreakoutsChanged.controls.breakout.sessions.active[0].name = 'new name';
1124
1179
 
1125
1180
  locusInfo.emitScoped = sinon.stub();
1126
- locusInfo.updateSelf(selfWithBreakoutsChanged, []);
1181
+ locusInfo.updateSelf(selfWithBreakoutsChanged);
1127
1182
 
1128
1183
  assert.calledWith(
1129
1184
  locusInfo.emitScoped,
@@ -1156,16 +1211,16 @@ describe('plugin-meetings', () => {
1156
1211
  });
1157
1212
 
1158
1213
  it('should trigger SELF_REMOTE_MUTE_STATUS_UPDATED if muted and disallowUnmute changed', () => {
1159
- locusInfo.self = self;
1214
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1215
+ locusInfo.updateSelf(self);
1160
1216
  const selfWithMutedByOthersAndDissalowUnmute = cloneDeep(self);
1161
1217
 
1162
1218
  // first simulate remote mute
1163
1219
  selfWithMutedByOthersAndDissalowUnmute.controls.audio.muted = true;
1164
1220
  selfWithMutedByOthersAndDissalowUnmute.controls.audio.disallowUnmute = true;
1165
1221
 
1166
- locusInfo.webex.internal.device.url = self.deviceUrl;
1167
1222
  locusInfo.emitScoped = sinon.stub();
1168
- locusInfo.updateSelf(selfWithMutedByOthersAndDissalowUnmute, []);
1223
+ locusInfo.updateSelf(selfWithMutedByOthersAndDissalowUnmute);
1169
1224
 
1170
1225
  assert.calledWith(
1171
1226
  locusInfo.emitScoped,
@@ -1183,7 +1238,7 @@ describe('plugin-meetings', () => {
1183
1238
  selfWithMutedByOthers.controls.audio.muted = true;
1184
1239
  selfWithMutedByOthers.controls.audio.disallowUnmute = false;
1185
1240
 
1186
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1241
+ locusInfo.updateSelf(selfWithMutedByOthers);
1187
1242
 
1188
1243
  assert.calledWith(
1189
1244
  locusInfo.emitScoped,
@@ -1197,15 +1252,15 @@ describe('plugin-meetings', () => {
1197
1252
  });
1198
1253
 
1199
1254
  it('should trigger LOCAL_UNMUTE_REQUIRED on localAudioUnmuteRequired', () => {
1200
- locusInfo.self = self;
1255
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1256
+ locusInfo.updateSelf(self);
1201
1257
  const selfWithLocalUnmuteRequired = cloneDeep(self);
1202
1258
 
1203
1259
  selfWithLocalUnmuteRequired.controls.audio.muted = false;
1204
1260
  selfWithLocalUnmuteRequired.controls.audio.localAudioUnmuteRequired = true;
1205
1261
 
1206
- locusInfo.webex.internal.device.url = self.deviceUrl;
1207
1262
  locusInfo.emitScoped = sinon.stub();
1208
- locusInfo.updateSelf(selfWithLocalUnmuteRequired, []);
1263
+ locusInfo.updateSelf(selfWithLocalUnmuteRequired);
1209
1264
 
1210
1265
  assert.calledWith(
1211
1266
  locusInfo.emitScoped,
@@ -1222,16 +1277,16 @@ describe('plugin-meetings', () => {
1222
1277
  });
1223
1278
 
1224
1279
  it('should trigger LOCAL_UNMUTE_REQUESTED when receiving requestedToUnmute=true', () => {
1225
- locusInfo.self = self;
1280
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1281
+ locusInfo.updateSelf(self);
1226
1282
  const selfWithRequestedToUnmute = cloneDeep(self);
1227
1283
 
1228
1284
  selfWithRequestedToUnmute.controls.audio.requestedToUnmute = true;
1229
1285
  selfWithRequestedToUnmute.controls.audio.lastModifiedRequestedToUnmute =
1230
1286
  '2023-06-16T19:25:04.369Z';
1231
1287
 
1232
- locusInfo.webex.internal.device.url = self.deviceUrl;
1233
1288
  locusInfo.emitScoped = sinon.stub();
1234
- locusInfo.updateSelf(selfWithRequestedToUnmute, []);
1289
+ locusInfo.updateSelf(selfWithRequestedToUnmute);
1235
1290
 
1236
1291
  assert.calledWith(
1237
1292
  locusInfo.emitScoped,
@@ -1249,7 +1304,7 @@ describe('plugin-meetings', () => {
1249
1304
  selfWithoutRequestedToUnmute.controls.audio.requestedToUnmute = false;
1250
1305
 
1251
1306
  locusInfo.emitScoped.resetHistory();
1252
- locusInfo.updateSelf(selfWithoutRequestedToUnmute, []);
1307
+ locusInfo.updateSelf(selfWithoutRequestedToUnmute);
1253
1308
 
1254
1309
  assert.neverCalledWith(
1255
1310
  locusInfo.emitScoped,
@@ -1263,15 +1318,14 @@ describe('plugin-meetings', () => {
1263
1318
  });
1264
1319
 
1265
1320
  it('should trigger SELF_OBSERVING when moving meeting to DX', () => {
1266
- locusInfo.self = self;
1321
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1322
+ locusInfo.updateSelf(self);
1267
1323
  const selfInitiatedMove = cloneDeep(self);
1268
1324
 
1269
1325
  // Inital move meeting is iniated
1270
1326
  selfInitiatedMove.devices[0].intent.type = 'MOVE_MEDIA';
1271
1327
 
1272
- locusInfo.webex.internal.device.url = self.deviceUrl;
1273
-
1274
- locusInfo.updateSelf(selfInitiatedMove, []);
1328
+ locusInfo.updateSelf(selfInitiatedMove);
1275
1329
 
1276
1330
  locusInfo.emitScoped = sinon.stub();
1277
1331
  // When dx joined the meeting after move
@@ -1279,7 +1333,7 @@ describe('plugin-meetings', () => {
1279
1333
 
1280
1334
  selfAfterDxJoins.devices[0].intent.type = 'OBSERVE';
1281
1335
 
1282
- locusInfo.updateSelf(selfAfterDxJoins, []);
1336
+ locusInfo.updateSelf(selfAfterDxJoins);
1283
1337
 
1284
1338
  assert.calledWith(
1285
1339
  locusInfo.emitScoped,
@@ -1297,11 +1351,11 @@ describe('plugin-meetings', () => {
1297
1351
  selfClone.canNotViewTheParticipantList = false; // same
1298
1352
 
1299
1353
  // Set the layout prior to stubbing to validate it does not change.
1300
- locusInfo.updateSelf(self, []);
1354
+ locusInfo.updateSelf(self);
1301
1355
 
1302
1356
  locusInfo.emitScoped = sinon.stub();
1303
1357
 
1304
- locusInfo.updateSelf(selfClone, []);
1358
+ locusInfo.updateSelf(selfClone);
1305
1359
 
1306
1360
  assert.neverCalledWith(
1307
1361
  locusInfo.emitScoped,
@@ -1320,11 +1374,11 @@ describe('plugin-meetings', () => {
1320
1374
  selfClone.canNotViewTheParticipantList = true; // different
1321
1375
 
1322
1376
  // Set the layout prior to stubbing to validate it does not change.
1323
- locusInfo.updateSelf(self, []);
1377
+ locusInfo.updateSelf(self);
1324
1378
 
1325
1379
  locusInfo.emitScoped = sinon.stub();
1326
1380
 
1327
- locusInfo.updateSelf(selfClone, []);
1381
+ locusInfo.updateSelf(selfClone);
1328
1382
 
1329
1383
  assert.calledWith(
1330
1384
  locusInfo.emitScoped,
@@ -1343,11 +1397,11 @@ describe('plugin-meetings', () => {
1343
1397
  selfClone.isSharingBlocked = false; // same
1344
1398
 
1345
1399
  // Set the layout prior to stubbing to validate it does not change.
1346
- locusInfo.updateSelf(self, []);
1400
+ locusInfo.updateSelf(self);
1347
1401
 
1348
1402
  locusInfo.emitScoped = sinon.stub();
1349
1403
 
1350
- locusInfo.updateSelf(selfClone, []);
1404
+ locusInfo.updateSelf(selfClone);
1351
1405
 
1352
1406
  assert.neverCalledWith(
1353
1407
  locusInfo.emitScoped,
@@ -1366,11 +1420,11 @@ describe('plugin-meetings', () => {
1366
1420
  selfClone.isSharingBlocked = true; // different
1367
1421
 
1368
1422
  // Set the layout prior to stubbing to validate it does not change.
1369
- locusInfo.updateSelf(self, []);
1423
+ locusInfo.updateSelf(self);
1370
1424
 
1371
1425
  locusInfo.emitScoped = sinon.stub();
1372
1426
 
1373
- locusInfo.updateSelf(selfClone, []);
1427
+ locusInfo.updateSelf(selfClone);
1374
1428
 
1375
1429
  assert.calledWith(
1376
1430
  locusInfo.emitScoped,
@@ -1384,12 +1438,12 @@ describe('plugin-meetings', () => {
1384
1438
  });
1385
1439
 
1386
1440
  it('should trigger SELF_ROLES_CHANGED if self roles changed', () => {
1387
- locusInfo.self = self;
1441
+ locusInfo.updateSelf(self);
1388
1442
  locusInfo.emitScoped = sinon.stub();
1389
1443
  const sampleNewSelf = cloneDeep(self);
1390
1444
  sampleNewSelf.controls.role.roles = [{type: 'COHOST', hasRole: true}];
1391
1445
 
1392
- locusInfo.updateSelf(sampleNewSelf, []);
1446
+ locusInfo.updateSelf(sampleNewSelf);
1393
1447
 
1394
1448
  assert.calledWith(
1395
1449
  locusInfo.emitScoped,
@@ -1403,12 +1457,12 @@ describe('plugin-meetings', () => {
1403
1457
  });
1404
1458
 
1405
1459
  it('should not trigger SELF_ROLES_CHANGED if self roles not changed', () => {
1406
- locusInfo.self = self;
1460
+ locusInfo.updateSelf(self);
1407
1461
  locusInfo.emitScoped = sinon.stub();
1408
1462
  const sampleNewSelf = cloneDeep(self);
1409
1463
  sampleNewSelf.controls.role.roles = [{type: 'PRESENTER', hasRole: true}];
1410
1464
 
1411
- locusInfo.updateSelf(sampleNewSelf, []);
1465
+ locusInfo.updateSelf(sampleNewSelf);
1412
1466
 
1413
1467
  assert.neverCalledWith(
1414
1468
  locusInfo.emitScoped,
@@ -1422,12 +1476,12 @@ describe('plugin-meetings', () => {
1422
1476
  });
1423
1477
 
1424
1478
  it('should trigger SELF_MEETING_INTERPRETATION_CHANGED if self interpretation info changed', () => {
1425
- locusInfo.self = self;
1479
+ locusInfo.updateSelf(self);
1426
1480
  locusInfo.emitScoped = sinon.stub();
1427
1481
  const sampleNewSelf = cloneDeep(self);
1428
1482
  sampleNewSelf.controls.interpretation.targetLanguage = 'it';
1429
1483
 
1430
- locusInfo.updateSelf(sampleNewSelf, []);
1484
+ locusInfo.updateSelf(sampleNewSelf);
1431
1485
 
1432
1486
  assert.calledWith(
1433
1487
  locusInfo.emitScoped,
@@ -1444,12 +1498,12 @@ describe('plugin-meetings', () => {
1444
1498
  });
1445
1499
 
1446
1500
  it('should not trigger SELF_MEETING_INTERPRETATION_CHANGED if self interpretation info not changed', () => {
1447
- locusInfo.self = self;
1501
+ locusInfo.updateSelf(self);
1448
1502
  locusInfo.emitScoped = sinon.stub();
1449
1503
  const sampleNewSelf = cloneDeep(self);
1450
1504
  sampleNewSelf.controls.interpretation.targetLanguage = 'cn'; // same with previous one
1451
1505
 
1452
- locusInfo.updateSelf(sampleNewSelf, []);
1506
+ locusInfo.updateSelf(sampleNewSelf);
1453
1507
 
1454
1508
  assert.neverCalledWith(
1455
1509
  locusInfo.emitScoped,
@@ -1466,12 +1520,12 @@ describe('plugin-meetings', () => {
1466
1520
  });
1467
1521
 
1468
1522
  it('should not trigger any events if controls is undefined', () => {
1469
- locusInfo.self = self;
1523
+ locusInfo.updateSelf(self);
1470
1524
  locusInfo.emitScoped = sinon.stub();
1471
1525
  const newSelf = cloneDeep(self);
1472
1526
  newSelf.controls = undefined;
1473
1527
 
1474
- locusInfo.updateSelf(newSelf, []);
1528
+ locusInfo.updateSelf(newSelf);
1475
1529
 
1476
1530
  const eventsSet = new Set([
1477
1531
  LOCUSINFO.EVENTS.CONTROLS_MEETING_LAYOUT_UPDATED,
@@ -1488,6 +1542,31 @@ describe('plugin-meetings', () => {
1488
1542
  assert.isFalse(eventsSet.has(eventName));
1489
1543
  });
1490
1544
  });
1545
+
1546
+ it('calls getSelves with correct parameters', () => {
1547
+ const getSelvesStub = sinon.stub(SelfUtils, 'getSelves').returns({
1548
+ current: {},
1549
+ previous: {},
1550
+ updates: {},
1551
+ });
1552
+
1553
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1554
+ locusInfo.participants = [{id: '1'}, {id: '2'}];
1555
+ locusInfo.parsedLocus.self = {id: 'fake parsed locus self id'};
1556
+
1557
+ const parsedLocusSelf = locusInfo.parsedLocus.self; // need to store it before it's updated in updateSelf
1558
+ locusInfo.updateSelf(self);
1559
+
1560
+ assert.calledWith(
1561
+ getSelvesStub,
1562
+ parsedLocusSelf,
1563
+ self,
1564
+ locusInfo.webex.internal.device.url,
1565
+ locusInfo.participants
1566
+ );
1567
+
1568
+ getSelvesStub.restore();
1569
+ });
1491
1570
  });
1492
1571
 
1493
1572
  describe('#updateMeetingInfo', () => {
@@ -1754,11 +1833,11 @@ describe('plugin-meetings', () => {
1754
1833
  });
1755
1834
 
1756
1835
  it('should update media shares and emit LOCUS_INFO_UPDATE_MEDIA_SHARES when mediaShares change', () => {
1757
- const initialMediaShares = { audio: true, video: false };
1758
- const newMediaShares = { audio: false, video: true };
1836
+ const initialMediaShares = {audio: true, video: false};
1837
+ const newMediaShares = {audio: false, video: true};
1759
1838
 
1760
1839
  locusInfo.mediaShares = initialMediaShares;
1761
- locusInfo.parsedLocus = { mediaShares: null };
1840
+ locusInfo.parsedLocus = {mediaShares: null};
1762
1841
 
1763
1842
  const parsedMediaShares = {
1764
1843
  current: newMediaShares,
@@ -1795,9 +1874,9 @@ describe('plugin-meetings', () => {
1795
1874
  });
1796
1875
 
1797
1876
  it('should force update media shares and emit LOCUS_INFO_UPDATE_MEDIA_SHARES even if shares are the same', () => {
1798
- const initialMediaShares = { audio: true, video: false };
1877
+ const initialMediaShares = {audio: true, video: false};
1799
1878
  locusInfo.mediaShares = initialMediaShares;
1800
- locusInfo.parsedLocus = { mediaShares: null };
1879
+ locusInfo.parsedLocus = {mediaShares: null};
1801
1880
 
1802
1881
  const parsedMediaShares = {
1803
1882
  current: initialMediaShares,
@@ -1829,7 +1908,7 @@ describe('plugin-meetings', () => {
1829
1908
  });
1830
1909
 
1831
1910
  it('should not emit LOCUS_INFO_UPDATE_MEDIA_SHARES if mediaShares do not change and forceUpdate is false', () => {
1832
- const initialMediaShares = { audio: true, video: false };
1911
+ const initialMediaShares = {audio: true, video: false};
1833
1912
  locusInfo.mediaShares = initialMediaShares;
1834
1913
 
1835
1914
  // Call the function with the same mediaShares and forceUpdate = false
@@ -1843,11 +1922,11 @@ describe('plugin-meetings', () => {
1843
1922
  });
1844
1923
 
1845
1924
  it('should update internal state correctly when mediaShares are updated', () => {
1846
- const initialMediaShares = { audio: true, video: false };
1847
- const newMediaShares = { audio: false, video: true };
1925
+ const initialMediaShares = {audio: true, video: false};
1926
+ const newMediaShares = {audio: false, video: true};
1848
1927
 
1849
1928
  locusInfo.mediaShares = initialMediaShares;
1850
- locusInfo.parsedLocus = { mediaShares: null };
1929
+ locusInfo.parsedLocus = {mediaShares: null};
1851
1930
 
1852
1931
  const parsedMediaShares = {
1853
1932
  current: newMediaShares,
@@ -2386,6 +2465,21 @@ describe('plugin-meetings', () => {
2386
2465
  locusInfo.onDeltaLocus(fakeLocus);
2387
2466
  assert.calledWith(locusInfo.updateParticipants, {}, true);
2388
2467
  });
2468
+
2469
+ it('onDeltaLocus merges delta participants with existing participants', () => {
2470
+ const FAKE_DELTA_PARTICIPANTS = [
2471
+ {id: '1111'}, {id: '2222'}
2472
+ ]
2473
+ fakeLocus.participants = FAKE_DELTA_PARTICIPANTS;
2474
+
2475
+ sinon.spy(locusInfo, 'mergeParticipants');
2476
+ locusInfo.updateParticipants = sinon.stub();
2477
+ const existingParticipants = locusInfo.participants;
2478
+
2479
+ locusInfo.onDeltaLocus(fakeLocus);
2480
+ assert.calledOnceWithExactly(locusInfo.mergeParticipants, existingParticipants, FAKE_DELTA_PARTICIPANTS);
2481
+ assert.calledWith(locusInfo.updateParticipants, FAKE_DELTA_PARTICIPANTS, false);
2482
+ });
2389
2483
  });
2390
2484
 
2391
2485
  describe('#updateLocusCache', () => {