@webex/plugin-meetings 3.8.0-next.7 → 3.8.0-next.71

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 (167) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/common/errors/webex-errors.js +12 -2
  4. package/dist/common/errors/webex-errors.js.map +1 -1
  5. package/dist/config.js +4 -1
  6. package/dist/config.js.map +1 -1
  7. package/dist/constants.js +17 -121
  8. package/dist/constants.js.map +1 -1
  9. package/dist/controls-options-manager/enums.js +2 -0
  10. package/dist/controls-options-manager/enums.js.map +1 -1
  11. package/dist/controls-options-manager/types.js.map +1 -1
  12. package/dist/controls-options-manager/util.js +52 -0
  13. package/dist/controls-options-manager/util.js.map +1 -1
  14. package/dist/interpretation/index.js +1 -1
  15. package/dist/interpretation/siLanguage.js +1 -1
  16. package/dist/locus-info/controlsUtils.js +28 -10
  17. package/dist/locus-info/controlsUtils.js.map +1 -1
  18. package/dist/locus-info/index.js +32 -12
  19. package/dist/locus-info/index.js.map +1 -1
  20. package/dist/locus-info/selfUtils.js +432 -418
  21. package/dist/locus-info/selfUtils.js.map +1 -1
  22. package/dist/media/index.js +14 -16
  23. package/dist/media/index.js.map +1 -1
  24. package/dist/media/properties.js +94 -6
  25. package/dist/media/properties.js.map +1 -1
  26. package/dist/meeting/brbState.js +6 -0
  27. package/dist/meeting/brbState.js.map +1 -1
  28. package/dist/meeting/in-meeting-actions.js +17 -1
  29. package/dist/meeting/in-meeting-actions.js.map +1 -1
  30. package/dist/meeting/index.js +541 -302
  31. package/dist/meeting/index.js.map +1 -1
  32. package/dist/meeting/locusMediaRequest.js +0 -17
  33. package/dist/meeting/locusMediaRequest.js.map +1 -1
  34. package/dist/meeting/muteState.js +0 -2
  35. package/dist/meeting/muteState.js.map +1 -1
  36. package/dist/meeting/request.js +30 -0
  37. package/dist/meeting/request.js.map +1 -1
  38. package/dist/meeting/request.type.js.map +1 -1
  39. package/dist/meeting/util.js +13 -2
  40. package/dist/meeting/util.js.map +1 -1
  41. package/dist/meeting-info/meeting-info-v2.js +359 -60
  42. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  43. package/dist/meetings/index.js +114 -1
  44. package/dist/meetings/index.js.map +1 -1
  45. package/dist/meetings/util.js +14 -0
  46. package/dist/meetings/util.js.map +1 -1
  47. package/dist/member/index.js +10 -0
  48. package/dist/member/index.js.map +1 -1
  49. package/dist/member/util.js +330 -353
  50. package/dist/member/util.js.map +1 -1
  51. package/dist/members/index.js +23 -0
  52. package/dist/members/index.js.map +1 -1
  53. package/dist/members/request.js +21 -0
  54. package/dist/members/request.js.map +1 -1
  55. package/dist/members/util.js +15 -0
  56. package/dist/members/util.js.map +1 -1
  57. package/dist/metrics/constants.js +9 -0
  58. package/dist/metrics/constants.js.map +1 -1
  59. package/dist/reachability/clusterReachability.js +63 -27
  60. package/dist/reachability/clusterReachability.js.map +1 -1
  61. package/dist/reachability/index.js +112 -47
  62. package/dist/reachability/index.js.map +1 -1
  63. package/dist/reachability/reachability.types.js +14 -0
  64. package/dist/reachability/reachability.types.js.map +1 -1
  65. package/dist/reachability/request.js +19 -3
  66. package/dist/reachability/request.js.map +1 -1
  67. package/dist/reconnection-manager/index.js +2 -2
  68. package/dist/reconnection-manager/index.js.map +1 -1
  69. package/dist/recording-controller/util.js +5 -5
  70. package/dist/recording-controller/util.js.map +1 -1
  71. package/dist/roap/index.js.map +1 -1
  72. package/dist/roap/turnDiscovery.js +45 -27
  73. package/dist/roap/turnDiscovery.js.map +1 -1
  74. package/dist/roap/types.js +17 -0
  75. package/dist/roap/types.js.map +1 -0
  76. package/dist/types/common/errors/webex-errors.d.ts +7 -1
  77. package/dist/types/config.d.ts +2 -0
  78. package/dist/types/constants.d.ts +12 -85
  79. package/dist/types/controls-options-manager/enums.d.ts +3 -1
  80. package/dist/types/controls-options-manager/types.d.ts +7 -1
  81. package/dist/types/locus-info/index.d.ts +3 -3
  82. package/dist/types/locus-info/selfUtils.d.ts +216 -1
  83. package/dist/types/media/properties.d.ts +15 -0
  84. package/dist/types/meeting/in-meeting-actions.d.ts +16 -0
  85. package/dist/types/meeting/index.d.ts +32 -1
  86. package/dist/types/meeting/muteState.d.ts +0 -1
  87. package/dist/types/meeting/request.d.ts +12 -1
  88. package/dist/types/meeting/request.type.d.ts +6 -0
  89. package/dist/types/meeting/util.d.ts +3 -1
  90. package/dist/types/meeting-info/meeting-info-v2.d.ts +80 -0
  91. package/dist/types/meetings/index.d.ts +48 -0
  92. package/dist/types/member/index.d.ts +1 -0
  93. package/dist/types/member/util.d.ts +159 -1
  94. package/dist/types/members/index.d.ts +8 -0
  95. package/dist/types/members/request.d.ts +19 -0
  96. package/dist/types/members/util.d.ts +13 -0
  97. package/dist/types/metrics/constants.d.ts +9 -0
  98. package/dist/types/reachability/clusterReachability.d.ts +15 -7
  99. package/dist/types/reachability/index.d.ts +10 -1
  100. package/dist/types/reachability/reachability.types.d.ts +5 -0
  101. package/dist/types/roap/index.d.ts +3 -2
  102. package/dist/types/roap/turnDiscovery.d.ts +5 -17
  103. package/dist/types/roap/types.d.ts +16 -0
  104. package/dist/webinar/index.js +1 -1
  105. package/package.json +24 -23
  106. package/src/common/errors/webex-errors.ts +8 -1
  107. package/src/config.ts +2 -0
  108. package/src/constants.ts +19 -90
  109. package/src/controls-options-manager/enums.ts +2 -0
  110. package/src/controls-options-manager/types.ts +11 -1
  111. package/src/controls-options-manager/util.ts +62 -0
  112. package/src/locus-info/controlsUtils.ts +44 -14
  113. package/src/locus-info/index.ts +38 -12
  114. package/src/locus-info/selfUtils.ts +496 -442
  115. package/src/media/index.ts +20 -21
  116. package/src/media/properties.ts +96 -0
  117. package/src/meeting/brbState.ts +7 -0
  118. package/src/meeting/in-meeting-actions.ts +32 -0
  119. package/src/meeting/index.ts +346 -93
  120. package/src/meeting/locusMediaRequest.ts +0 -18
  121. package/src/meeting/muteState.ts +0 -2
  122. package/src/meeting/request.ts +36 -1
  123. package/src/meeting/request.type.ts +7 -0
  124. package/src/meeting/util.ts +11 -2
  125. package/src/meeting-info/meeting-info-v2.ts +247 -6
  126. package/src/meetings/index.ts +128 -1
  127. package/src/meetings/util.ts +18 -0
  128. package/src/member/index.ts +13 -2
  129. package/src/member/util.ts +351 -348
  130. package/src/members/index.ts +25 -0
  131. package/src/members/request.ts +26 -0
  132. package/src/members/util.ts +16 -0
  133. package/src/metrics/constants.ts +9 -0
  134. package/src/reachability/clusterReachability.ts +73 -26
  135. package/src/reachability/index.ts +70 -1
  136. package/src/reachability/reachability.types.ts +6 -0
  137. package/src/reachability/request.ts +7 -0
  138. package/src/reconnection-manager/index.ts +2 -2
  139. package/src/recording-controller/util.ts +17 -13
  140. package/src/roap/index.ts +3 -7
  141. package/src/roap/turnDiscovery.ts +34 -39
  142. package/src/roap/types.ts +23 -0
  143. package/test/unit/spec/controls-options-manager/util.js +120 -0
  144. package/test/unit/spec/locus-info/controlsUtils.js +103 -9
  145. package/test/unit/spec/locus-info/index.js +141 -73
  146. package/test/unit/spec/locus-info/selfUtils.js +98 -24
  147. package/test/unit/spec/media/index.ts +98 -16
  148. package/test/unit/spec/media/properties.ts +130 -0
  149. package/test/unit/spec/meeting/brbState.ts +19 -0
  150. package/test/unit/spec/meeting/in-meeting-actions.ts +19 -4
  151. package/test/unit/spec/meeting/index.js +524 -35
  152. package/test/unit/spec/meeting/locusMediaRequest.ts +0 -30
  153. package/test/unit/spec/meeting/muteState.js +0 -2
  154. package/test/unit/spec/meeting/request.js +32 -1
  155. package/test/unit/spec/meeting/utils.js +119 -18
  156. package/test/unit/spec/meeting-info/meetinginfov2.js +443 -114
  157. package/test/unit/spec/meetings/index.js +133 -2
  158. package/test/unit/spec/member/index.js +7 -0
  159. package/test/unit/spec/member/util.js +24 -0
  160. package/test/unit/spec/members/index.js +103 -26
  161. package/test/unit/spec/members/request.js +45 -22
  162. package/test/unit/spec/members/utils.js +33 -0
  163. package/test/unit/spec/reachability/clusterReachability.ts +88 -56
  164. package/test/unit/spec/reachability/index.ts +101 -0
  165. package/test/unit/spec/reachability/request.js +47 -2
  166. package/test/unit/spec/reconnection-manager/index.js +4 -4
  167. 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: {
@@ -808,7 +836,7 @@ describe('plugin-meetings', () => {
808
836
  selfWithBrbChanged.controls.brb = enabled;
809
837
 
810
838
  locusInfo.emitScoped = sinon.stub();
811
- locusInfo.updateSelf(selfWithBrbChanged, []);
839
+ locusInfo.updateSelf(selfWithBrbChanged);
812
840
 
813
841
  assert.calledWith(
814
842
  locusInfo.emitScoped,
@@ -828,14 +856,15 @@ describe('plugin-meetings', () => {
828
856
 
829
857
  const selfWithBrbChanged = cloneDeep(self);
830
858
  selfWithBrbChanged.controls.brb = value;
831
- locusInfo.self = selfWithBrbChanged;
859
+
860
+ locusInfo.updateSelf(selfWithBrbChanged);
832
861
 
833
862
  locusInfo.emitScoped = sinon.stub();
834
863
 
835
864
  const newSelf = cloneDeep(self);
836
865
  newSelf.controls.brb = value;
837
866
 
838
- locusInfo.updateSelf(newSelf, []);
867
+ locusInfo.updateSelf(newSelf);
839
868
 
840
869
  assert.neverCalledWith(
841
870
  locusInfo.emitScoped,
@@ -852,14 +881,14 @@ describe('plugin-meetings', () => {
852
881
  it('should not trigger SELF_MEETING_BRB_CHANGED when brb state is undefined', () => {
853
882
  const selfWithBrbChanged = cloneDeep(self);
854
883
  selfWithBrbChanged.controls.brb = false;
855
- locusInfo.self = selfWithBrbChanged;
884
+ locusInfo.updateSelf(selfWithBrbChanged);
856
885
 
857
886
  locusInfo.emitScoped = sinon.stub();
858
887
 
859
888
  const newSelf = cloneDeep(self);
860
889
  newSelf.controls.brb = undefined;
861
890
 
862
- locusInfo.updateSelf(newSelf, []);
891
+ locusInfo.updateSelf(newSelf);
863
892
 
864
893
  assert.neverCalledWith(
865
894
  locusInfo.emitScoped,
@@ -882,7 +911,7 @@ describe('plugin-meetings', () => {
882
911
  ];
883
912
 
884
913
  locusInfo.emitScoped = sinon.stub();
885
- locusInfo.updateSelf(selfWithLayoutChanged, []);
914
+ locusInfo.updateSelf(selfWithLayoutChanged);
886
915
 
887
916
  assert.calledWith(
888
917
  locusInfo.emitScoped,
@@ -908,11 +937,11 @@ describe('plugin-meetings', () => {
908
937
  ];
909
938
 
910
939
  // Set the layout prior to stubbing to validate it does not change.
911
- locusInfo.updateSelf(selfWithLayoutChanged, []);
940
+ locusInfo.updateSelf(selfWithLayoutChanged);
912
941
 
913
942
  locusInfo.emitScoped = sinon.stub();
914
943
 
915
- locusInfo.updateSelf(selfWithLayoutChanged, []);
944
+ locusInfo.updateSelf(selfWithLayoutChanged);
916
945
 
917
946
  assert.neverCalledWith(
918
947
  locusInfo.emitScoped,
@@ -926,11 +955,11 @@ describe('plugin-meetings', () => {
926
955
  });
927
956
 
928
957
  it('should trigger MEDIA_INACTIVITY on server media inactivity', () => {
929
- locusInfo.self = self;
930
-
931
958
  locusInfo.webex.internal.device.url = selfWithInactivity.deviceUrl;
959
+ locusInfo.updateSelf(self);
960
+
932
961
  locusInfo.emitScoped = sinon.stub();
933
- locusInfo.updateSelf(selfWithInactivity, []);
962
+ locusInfo.updateSelf(selfWithInactivity);
934
963
 
935
964
  assert.calledWith(
936
965
  locusInfo.emitScoped,
@@ -952,7 +981,7 @@ describe('plugin-meetings', () => {
952
981
 
953
982
  locusInfo.webex.internal.device.url = self.deviceUrl;
954
983
  locusInfo.emitScoped = sinon.stub();
955
- locusInfo.updateSelf(selfWithMutedByOthers, []);
984
+ locusInfo.updateSelf(selfWithMutedByOthers);
956
985
 
957
986
  assert.calledWith(
958
987
  locusInfo.emitScoped,
@@ -965,10 +994,10 @@ describe('plugin-meetings', () => {
965
994
  );
966
995
 
967
996
  // but sometimes "previous self" is defined, but without controls.audio.muted, so we test this here:
968
- locusInfo.self = cloneDeep(self);
997
+ locusInfo.updateSelf(self);
969
998
  locusInfo.self.controls.audio = {};
970
999
 
971
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1000
+ locusInfo.updateSelf(selfWithMutedByOthers);
972
1001
  assert.calledWith(
973
1002
  locusInfo.emitScoped,
974
1003
  {
@@ -988,7 +1017,7 @@ describe('plugin-meetings', () => {
988
1017
 
989
1018
  locusInfo.webex.internal.device.url = self.deviceUrl;
990
1019
  locusInfo.emitScoped = sinon.stub();
991
- locusInfo.updateSelf(selfWithMutedByOthersFalse, []);
1020
+ locusInfo.updateSelf(selfWithMutedByOthersFalse);
992
1021
 
993
1022
  // we might get some calls to emitScoped, but we need to check that none of them are for SELF_REMOTE_MUTE_STATUS_UPDATED
994
1023
  locusInfo.emitScoped.getCalls().forEach((x) => {
@@ -997,20 +1026,20 @@ describe('plugin-meetings', () => {
997
1026
  });
998
1027
 
999
1028
  it('should not trigger SELF_REMOTE_MUTE_STATUS_UPDATED when being removed from meeting', () => {
1029
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1000
1030
  const selfWithMutedByOthers = cloneDeep(self);
1001
1031
 
1002
1032
  selfWithMutedByOthers.controls.audio.muted = true;
1003
1033
 
1004
- locusInfo.self = selfWithMutedByOthers;
1034
+ locusInfo.updateSelf(selfWithMutedByOthers);
1005
1035
 
1006
1036
  // when user gets removed from meeting we receive a Locus DTO without any self.controls
1007
1037
  const selfWithoutControls = cloneDeep(self);
1008
1038
 
1009
1039
  selfWithoutControls.controls = undefined;
1010
1040
 
1011
- locusInfo.webex.internal.device.url = self.deviceUrl;
1012
1041
  locusInfo.emitScoped = sinon.stub();
1013
- locusInfo.updateSelf(selfWithoutControls, []);
1042
+ locusInfo.updateSelf(selfWithoutControls);
1014
1043
 
1015
1044
  // we might get some calls to emitScoped, but we need to check that none of them are for SELF_REMOTE_MUTE_STATUS_UPDATED
1016
1045
  locusInfo.emitScoped.getCalls().forEach((x) => {
@@ -1019,14 +1048,14 @@ describe('plugin-meetings', () => {
1019
1048
  });
1020
1049
 
1021
1050
  it('should trigger SELF_REMOTE_MUTE_STATUS_UPDATED on othersMuted', () => {
1022
- locusInfo.self = self;
1051
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1052
+ locusInfo.updateSelf(self);
1023
1053
  const selfWithMutedByOthers = cloneDeep(self);
1024
1054
 
1025
1055
  selfWithMutedByOthers.controls.audio.muted = true;
1026
1056
 
1027
- locusInfo.webex.internal.device.url = self.deviceUrl;
1028
1057
  locusInfo.emitScoped = sinon.stub();
1029
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1058
+ locusInfo.updateSelf(selfWithMutedByOthers);
1030
1059
 
1031
1060
  assert.calledWith(
1032
1061
  locusInfo.emitScoped,
@@ -1050,7 +1079,7 @@ describe('plugin-meetings', () => {
1050
1079
 
1051
1080
  locusInfo.webex.internal.device.url = self.deviceUrl;
1052
1081
  locusInfo.emitScoped = sinon.stub();
1053
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1082
+ locusInfo.updateSelf(selfWithMutedByOthers);
1054
1083
 
1055
1084
  assert.calledWith(
1056
1085
  locusInfo.emitScoped,
@@ -1063,10 +1092,10 @@ describe('plugin-meetings', () => {
1063
1092
  );
1064
1093
 
1065
1094
  // but sometimes "previous self" is defined, but without controls.audio.muted, so we test this here:
1066
- locusInfo.self = cloneDeep(self);
1095
+ locusInfo.updateSelf(self);
1067
1096
  locusInfo.self.controls.video = {};
1068
1097
 
1069
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1098
+ locusInfo.updateSelf(selfWithMutedByOthers);
1070
1099
  assert.calledWith(
1071
1100
  locusInfo.emitScoped,
1072
1101
  {
@@ -1086,7 +1115,7 @@ describe('plugin-meetings', () => {
1086
1115
 
1087
1116
  locusInfo.webex.internal.device.url = self.deviceUrl;
1088
1117
  locusInfo.emitScoped = sinon.stub();
1089
- locusInfo.updateSelf(selfWithMutedByOthersFalse, []);
1118
+ locusInfo.updateSelf(selfWithMutedByOthersFalse);
1090
1119
 
1091
1120
  // 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
1121
  locusInfo.emitScoped.getCalls().forEach((x) => {
@@ -1095,14 +1124,14 @@ describe('plugin-meetings', () => {
1095
1124
  });
1096
1125
 
1097
1126
  it('should emit event when remoteVideoMuted changed', () => {
1098
- locusInfo.self = self;
1127
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1128
+ locusInfo.updateSelf(self);
1099
1129
  const selfWithMutedByOthers = cloneDeep(self);
1100
1130
 
1101
1131
  selfWithMutedByOthers.controls.video.muted = true;
1102
1132
 
1103
- locusInfo.webex.internal.device.url = self.deviceUrl;
1104
1133
  locusInfo.emitScoped = sinon.stub();
1105
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1134
+ locusInfo.updateSelf(selfWithMutedByOthers);
1106
1135
 
1107
1136
  assert.calledWith(
1108
1137
  locusInfo.emitScoped,
@@ -1117,13 +1146,13 @@ describe('plugin-meetings', () => {
1117
1146
  });
1118
1147
 
1119
1148
  it('should trigger SELF_MEETING_BREAKOUTS_CHANGED when breakouts changed', () => {
1120
- locusInfo.self = self;
1149
+ locusInfo.updateSelf(self);
1121
1150
  const selfWithBreakoutsChanged = cloneDeep(self);
1122
1151
 
1123
1152
  selfWithBreakoutsChanged.controls.breakout.sessions.active[0].name = 'new name';
1124
1153
 
1125
1154
  locusInfo.emitScoped = sinon.stub();
1126
- locusInfo.updateSelf(selfWithBreakoutsChanged, []);
1155
+ locusInfo.updateSelf(selfWithBreakoutsChanged);
1127
1156
 
1128
1157
  assert.calledWith(
1129
1158
  locusInfo.emitScoped,
@@ -1156,16 +1185,16 @@ describe('plugin-meetings', () => {
1156
1185
  });
1157
1186
 
1158
1187
  it('should trigger SELF_REMOTE_MUTE_STATUS_UPDATED if muted and disallowUnmute changed', () => {
1159
- locusInfo.self = self;
1188
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1189
+ locusInfo.updateSelf(self);
1160
1190
  const selfWithMutedByOthersAndDissalowUnmute = cloneDeep(self);
1161
1191
 
1162
1192
  // first simulate remote mute
1163
1193
  selfWithMutedByOthersAndDissalowUnmute.controls.audio.muted = true;
1164
1194
  selfWithMutedByOthersAndDissalowUnmute.controls.audio.disallowUnmute = true;
1165
1195
 
1166
- locusInfo.webex.internal.device.url = self.deviceUrl;
1167
1196
  locusInfo.emitScoped = sinon.stub();
1168
- locusInfo.updateSelf(selfWithMutedByOthersAndDissalowUnmute, []);
1197
+ locusInfo.updateSelf(selfWithMutedByOthersAndDissalowUnmute);
1169
1198
 
1170
1199
  assert.calledWith(
1171
1200
  locusInfo.emitScoped,
@@ -1183,7 +1212,7 @@ describe('plugin-meetings', () => {
1183
1212
  selfWithMutedByOthers.controls.audio.muted = true;
1184
1213
  selfWithMutedByOthers.controls.audio.disallowUnmute = false;
1185
1214
 
1186
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1215
+ locusInfo.updateSelf(selfWithMutedByOthers);
1187
1216
 
1188
1217
  assert.calledWith(
1189
1218
  locusInfo.emitScoped,
@@ -1197,15 +1226,15 @@ describe('plugin-meetings', () => {
1197
1226
  });
1198
1227
 
1199
1228
  it('should trigger LOCAL_UNMUTE_REQUIRED on localAudioUnmuteRequired', () => {
1200
- locusInfo.self = self;
1229
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1230
+ locusInfo.updateSelf(self);
1201
1231
  const selfWithLocalUnmuteRequired = cloneDeep(self);
1202
1232
 
1203
1233
  selfWithLocalUnmuteRequired.controls.audio.muted = false;
1204
1234
  selfWithLocalUnmuteRequired.controls.audio.localAudioUnmuteRequired = true;
1205
1235
 
1206
- locusInfo.webex.internal.device.url = self.deviceUrl;
1207
1236
  locusInfo.emitScoped = sinon.stub();
1208
- locusInfo.updateSelf(selfWithLocalUnmuteRequired, []);
1237
+ locusInfo.updateSelf(selfWithLocalUnmuteRequired);
1209
1238
 
1210
1239
  assert.calledWith(
1211
1240
  locusInfo.emitScoped,
@@ -1222,16 +1251,16 @@ describe('plugin-meetings', () => {
1222
1251
  });
1223
1252
 
1224
1253
  it('should trigger LOCAL_UNMUTE_REQUESTED when receiving requestedToUnmute=true', () => {
1225
- locusInfo.self = self;
1254
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1255
+ locusInfo.updateSelf(self);
1226
1256
  const selfWithRequestedToUnmute = cloneDeep(self);
1227
1257
 
1228
1258
  selfWithRequestedToUnmute.controls.audio.requestedToUnmute = true;
1229
1259
  selfWithRequestedToUnmute.controls.audio.lastModifiedRequestedToUnmute =
1230
1260
  '2023-06-16T19:25:04.369Z';
1231
1261
 
1232
- locusInfo.webex.internal.device.url = self.deviceUrl;
1233
1262
  locusInfo.emitScoped = sinon.stub();
1234
- locusInfo.updateSelf(selfWithRequestedToUnmute, []);
1263
+ locusInfo.updateSelf(selfWithRequestedToUnmute);
1235
1264
 
1236
1265
  assert.calledWith(
1237
1266
  locusInfo.emitScoped,
@@ -1249,7 +1278,7 @@ describe('plugin-meetings', () => {
1249
1278
  selfWithoutRequestedToUnmute.controls.audio.requestedToUnmute = false;
1250
1279
 
1251
1280
  locusInfo.emitScoped.resetHistory();
1252
- locusInfo.updateSelf(selfWithoutRequestedToUnmute, []);
1281
+ locusInfo.updateSelf(selfWithoutRequestedToUnmute);
1253
1282
 
1254
1283
  assert.neverCalledWith(
1255
1284
  locusInfo.emitScoped,
@@ -1263,15 +1292,14 @@ describe('plugin-meetings', () => {
1263
1292
  });
1264
1293
 
1265
1294
  it('should trigger SELF_OBSERVING when moving meeting to DX', () => {
1266
- locusInfo.self = self;
1295
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1296
+ locusInfo.updateSelf(self);
1267
1297
  const selfInitiatedMove = cloneDeep(self);
1268
1298
 
1269
1299
  // Inital move meeting is iniated
1270
1300
  selfInitiatedMove.devices[0].intent.type = 'MOVE_MEDIA';
1271
1301
 
1272
- locusInfo.webex.internal.device.url = self.deviceUrl;
1273
-
1274
- locusInfo.updateSelf(selfInitiatedMove, []);
1302
+ locusInfo.updateSelf(selfInitiatedMove);
1275
1303
 
1276
1304
  locusInfo.emitScoped = sinon.stub();
1277
1305
  // When dx joined the meeting after move
@@ -1279,7 +1307,7 @@ describe('plugin-meetings', () => {
1279
1307
 
1280
1308
  selfAfterDxJoins.devices[0].intent.type = 'OBSERVE';
1281
1309
 
1282
- locusInfo.updateSelf(selfAfterDxJoins, []);
1310
+ locusInfo.updateSelf(selfAfterDxJoins);
1283
1311
 
1284
1312
  assert.calledWith(
1285
1313
  locusInfo.emitScoped,
@@ -1297,11 +1325,11 @@ describe('plugin-meetings', () => {
1297
1325
  selfClone.canNotViewTheParticipantList = false; // same
1298
1326
 
1299
1327
  // Set the layout prior to stubbing to validate it does not change.
1300
- locusInfo.updateSelf(self, []);
1328
+ locusInfo.updateSelf(self);
1301
1329
 
1302
1330
  locusInfo.emitScoped = sinon.stub();
1303
1331
 
1304
- locusInfo.updateSelf(selfClone, []);
1332
+ locusInfo.updateSelf(selfClone);
1305
1333
 
1306
1334
  assert.neverCalledWith(
1307
1335
  locusInfo.emitScoped,
@@ -1320,11 +1348,11 @@ describe('plugin-meetings', () => {
1320
1348
  selfClone.canNotViewTheParticipantList = true; // different
1321
1349
 
1322
1350
  // Set the layout prior to stubbing to validate it does not change.
1323
- locusInfo.updateSelf(self, []);
1351
+ locusInfo.updateSelf(self);
1324
1352
 
1325
1353
  locusInfo.emitScoped = sinon.stub();
1326
1354
 
1327
- locusInfo.updateSelf(selfClone, []);
1355
+ locusInfo.updateSelf(selfClone);
1328
1356
 
1329
1357
  assert.calledWith(
1330
1358
  locusInfo.emitScoped,
@@ -1343,11 +1371,11 @@ describe('plugin-meetings', () => {
1343
1371
  selfClone.isSharingBlocked = false; // same
1344
1372
 
1345
1373
  // Set the layout prior to stubbing to validate it does not change.
1346
- locusInfo.updateSelf(self, []);
1374
+ locusInfo.updateSelf(self);
1347
1375
 
1348
1376
  locusInfo.emitScoped = sinon.stub();
1349
1377
 
1350
- locusInfo.updateSelf(selfClone, []);
1378
+ locusInfo.updateSelf(selfClone);
1351
1379
 
1352
1380
  assert.neverCalledWith(
1353
1381
  locusInfo.emitScoped,
@@ -1366,11 +1394,11 @@ describe('plugin-meetings', () => {
1366
1394
  selfClone.isSharingBlocked = true; // different
1367
1395
 
1368
1396
  // Set the layout prior to stubbing to validate it does not change.
1369
- locusInfo.updateSelf(self, []);
1397
+ locusInfo.updateSelf(self);
1370
1398
 
1371
1399
  locusInfo.emitScoped = sinon.stub();
1372
1400
 
1373
- locusInfo.updateSelf(selfClone, []);
1401
+ locusInfo.updateSelf(selfClone);
1374
1402
 
1375
1403
  assert.calledWith(
1376
1404
  locusInfo.emitScoped,
@@ -1384,12 +1412,12 @@ describe('plugin-meetings', () => {
1384
1412
  });
1385
1413
 
1386
1414
  it('should trigger SELF_ROLES_CHANGED if self roles changed', () => {
1387
- locusInfo.self = self;
1415
+ locusInfo.updateSelf(self);
1388
1416
  locusInfo.emitScoped = sinon.stub();
1389
1417
  const sampleNewSelf = cloneDeep(self);
1390
1418
  sampleNewSelf.controls.role.roles = [{type: 'COHOST', hasRole: true}];
1391
1419
 
1392
- locusInfo.updateSelf(sampleNewSelf, []);
1420
+ locusInfo.updateSelf(sampleNewSelf);
1393
1421
 
1394
1422
  assert.calledWith(
1395
1423
  locusInfo.emitScoped,
@@ -1403,12 +1431,12 @@ describe('plugin-meetings', () => {
1403
1431
  });
1404
1432
 
1405
1433
  it('should not trigger SELF_ROLES_CHANGED if self roles not changed', () => {
1406
- locusInfo.self = self;
1434
+ locusInfo.updateSelf(self);
1407
1435
  locusInfo.emitScoped = sinon.stub();
1408
1436
  const sampleNewSelf = cloneDeep(self);
1409
1437
  sampleNewSelf.controls.role.roles = [{type: 'PRESENTER', hasRole: true}];
1410
1438
 
1411
- locusInfo.updateSelf(sampleNewSelf, []);
1439
+ locusInfo.updateSelf(sampleNewSelf);
1412
1440
 
1413
1441
  assert.neverCalledWith(
1414
1442
  locusInfo.emitScoped,
@@ -1422,12 +1450,12 @@ describe('plugin-meetings', () => {
1422
1450
  });
1423
1451
 
1424
1452
  it('should trigger SELF_MEETING_INTERPRETATION_CHANGED if self interpretation info changed', () => {
1425
- locusInfo.self = self;
1453
+ locusInfo.updateSelf(self);
1426
1454
  locusInfo.emitScoped = sinon.stub();
1427
1455
  const sampleNewSelf = cloneDeep(self);
1428
1456
  sampleNewSelf.controls.interpretation.targetLanguage = 'it';
1429
1457
 
1430
- locusInfo.updateSelf(sampleNewSelf, []);
1458
+ locusInfo.updateSelf(sampleNewSelf);
1431
1459
 
1432
1460
  assert.calledWith(
1433
1461
  locusInfo.emitScoped,
@@ -1444,12 +1472,12 @@ describe('plugin-meetings', () => {
1444
1472
  });
1445
1473
 
1446
1474
  it('should not trigger SELF_MEETING_INTERPRETATION_CHANGED if self interpretation info not changed', () => {
1447
- locusInfo.self = self;
1475
+ locusInfo.updateSelf(self);
1448
1476
  locusInfo.emitScoped = sinon.stub();
1449
1477
  const sampleNewSelf = cloneDeep(self);
1450
1478
  sampleNewSelf.controls.interpretation.targetLanguage = 'cn'; // same with previous one
1451
1479
 
1452
- locusInfo.updateSelf(sampleNewSelf, []);
1480
+ locusInfo.updateSelf(sampleNewSelf);
1453
1481
 
1454
1482
  assert.neverCalledWith(
1455
1483
  locusInfo.emitScoped,
@@ -1466,12 +1494,12 @@ describe('plugin-meetings', () => {
1466
1494
  });
1467
1495
 
1468
1496
  it('should not trigger any events if controls is undefined', () => {
1469
- locusInfo.self = self;
1497
+ locusInfo.updateSelf(self);
1470
1498
  locusInfo.emitScoped = sinon.stub();
1471
1499
  const newSelf = cloneDeep(self);
1472
1500
  newSelf.controls = undefined;
1473
1501
 
1474
- locusInfo.updateSelf(newSelf, []);
1502
+ locusInfo.updateSelf(newSelf);
1475
1503
 
1476
1504
  const eventsSet = new Set([
1477
1505
  LOCUSINFO.EVENTS.CONTROLS_MEETING_LAYOUT_UPDATED,
@@ -1488,6 +1516,31 @@ describe('plugin-meetings', () => {
1488
1516
  assert.isFalse(eventsSet.has(eventName));
1489
1517
  });
1490
1518
  });
1519
+
1520
+ it('calls getSelves with correct parameters', () => {
1521
+ const getSelvesStub = sinon.stub(SelfUtils, 'getSelves').returns({
1522
+ current: {},
1523
+ previous: {},
1524
+ updates: {},
1525
+ });
1526
+
1527
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1528
+ locusInfo.participants = [{id: '1'}, {id: '2'}];
1529
+ locusInfo.parsedLocus.self = {id: 'fake parsed locus self id'};
1530
+
1531
+ const parsedLocusSelf = locusInfo.parsedLocus.self; // need to store it before it's updated in updateSelf
1532
+ locusInfo.updateSelf(self);
1533
+
1534
+ assert.calledWith(
1535
+ getSelvesStub,
1536
+ parsedLocusSelf,
1537
+ self,
1538
+ locusInfo.webex.internal.device.url,
1539
+ locusInfo.participants
1540
+ );
1541
+
1542
+ getSelvesStub.restore();
1543
+ });
1491
1544
  });
1492
1545
 
1493
1546
  describe('#updateMeetingInfo', () => {
@@ -1754,11 +1807,11 @@ describe('plugin-meetings', () => {
1754
1807
  });
1755
1808
 
1756
1809
  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 };
1810
+ const initialMediaShares = {audio: true, video: false};
1811
+ const newMediaShares = {audio: false, video: true};
1759
1812
 
1760
1813
  locusInfo.mediaShares = initialMediaShares;
1761
- locusInfo.parsedLocus = { mediaShares: null };
1814
+ locusInfo.parsedLocus = {mediaShares: null};
1762
1815
 
1763
1816
  const parsedMediaShares = {
1764
1817
  current: newMediaShares,
@@ -1795,9 +1848,9 @@ describe('plugin-meetings', () => {
1795
1848
  });
1796
1849
 
1797
1850
  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 };
1851
+ const initialMediaShares = {audio: true, video: false};
1799
1852
  locusInfo.mediaShares = initialMediaShares;
1800
- locusInfo.parsedLocus = { mediaShares: null };
1853
+ locusInfo.parsedLocus = {mediaShares: null};
1801
1854
 
1802
1855
  const parsedMediaShares = {
1803
1856
  current: initialMediaShares,
@@ -1829,7 +1882,7 @@ describe('plugin-meetings', () => {
1829
1882
  });
1830
1883
 
1831
1884
  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 };
1885
+ const initialMediaShares = {audio: true, video: false};
1833
1886
  locusInfo.mediaShares = initialMediaShares;
1834
1887
 
1835
1888
  // Call the function with the same mediaShares and forceUpdate = false
@@ -1843,11 +1896,11 @@ describe('plugin-meetings', () => {
1843
1896
  });
1844
1897
 
1845
1898
  it('should update internal state correctly when mediaShares are updated', () => {
1846
- const initialMediaShares = { audio: true, video: false };
1847
- const newMediaShares = { audio: false, video: true };
1899
+ const initialMediaShares = {audio: true, video: false};
1900
+ const newMediaShares = {audio: false, video: true};
1848
1901
 
1849
1902
  locusInfo.mediaShares = initialMediaShares;
1850
- locusInfo.parsedLocus = { mediaShares: null };
1903
+ locusInfo.parsedLocus = {mediaShares: null};
1851
1904
 
1852
1905
  const parsedMediaShares = {
1853
1906
  current: newMediaShares,
@@ -2386,6 +2439,21 @@ describe('plugin-meetings', () => {
2386
2439
  locusInfo.onDeltaLocus(fakeLocus);
2387
2440
  assert.calledWith(locusInfo.updateParticipants, {}, true);
2388
2441
  });
2442
+
2443
+ it('onDeltaLocus merges delta participants with existing participants', () => {
2444
+ const FAKE_DELTA_PARTICIPANTS = [
2445
+ {id: '1111'}, {id: '2222'}
2446
+ ]
2447
+ fakeLocus.participants = FAKE_DELTA_PARTICIPANTS;
2448
+
2449
+ sinon.spy(locusInfo, 'mergeParticipants');
2450
+ locusInfo.updateParticipants = sinon.stub();
2451
+ const existingParticipants = locusInfo.participants;
2452
+
2453
+ locusInfo.onDeltaLocus(fakeLocus);
2454
+ assert.calledOnceWithExactly(locusInfo.mergeParticipants, existingParticipants, FAKE_DELTA_PARTICIPANTS);
2455
+ assert.calledWith(locusInfo.updateParticipants, FAKE_DELTA_PARTICIPANTS, false);
2456
+ });
2389
2457
  });
2390
2458
 
2391
2459
  describe('#updateLocusCache', () => {