@webex/plugin-meetings 3.8.0-web-workers-keepalive.1 → 3.8.1-next.1

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 (168) 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 +4 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/constants.js +22 -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 +30 -10
  18. package/dist/locus-info/controlsUtils.js.map +1 -1
  19. package/dist/locus-info/index.js +83 -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 +9 -2
  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 +568 -328
  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 +4 -4
  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 +9 -1
  41. package/dist/meeting/util.js.map +1 -1
  42. package/dist/meeting-info/meeting-info-v2.js +19 -13
  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 +76 -0
  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 +45 -9
  51. package/dist/member/index.js.map +1 -1
  52. package/dist/member/types.js +3 -0
  53. package/dist/member/types.js.map +1 -1
  54. package/dist/member/util.js +335 -356
  55. package/dist/member/util.js.map +1 -1
  56. package/dist/members/collection.js.map +1 -1
  57. package/dist/members/index.js +137 -29
  58. package/dist/members/index.js.map +1 -1
  59. package/dist/members/request.js +38 -0
  60. package/dist/members/request.js.map +1 -1
  61. package/dist/members/util.js +36 -1
  62. package/dist/members/util.js.map +1 -1
  63. package/dist/metrics/constants.js +1 -0
  64. package/dist/metrics/constants.js.map +1 -1
  65. package/dist/reachability/clusterReachability.js +23 -31
  66. package/dist/reachability/clusterReachability.js.map +1 -1
  67. package/dist/reachability/index.js +42 -2
  68. package/dist/reachability/index.js.map +1 -1
  69. package/dist/reconnection-manager/index.js +2 -2
  70. package/dist/reconnection-manager/index.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 +15 -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 +35 -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 +2 -1
  91. package/dist/types/meetings/index.d.ts +28 -0
  92. package/dist/types/member/index.d.ts +20 -6
  93. package/dist/types/member/types.d.ts +73 -14
  94. package/dist/types/member/util.d.ts +156 -1
  95. package/dist/types/members/collection.d.ts +6 -5
  96. package/dist/types/members/index.d.ts +32 -43
  97. package/dist/types/members/request.d.ts +26 -0
  98. package/dist/types/members/util.d.ts +27 -0
  99. package/dist/types/metrics/constants.d.ts +1 -0
  100. package/dist/types/reachability/clusterReachability.d.ts +2 -6
  101. package/dist/types/reachability/index.d.ts +8 -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 +2 -0
  110. package/src/constants.ts +23 -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 +48 -12
  115. package/src/locus-info/index.ts +88 -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 +11 -2
  120. package/src/meeting/in-meeting-actions.ts +32 -0
  121. package/src/meeting/index.ts +356 -87
  122. package/src/meeting/locusMediaRequest.ts +0 -18
  123. package/src/meeting/muteState.ts +4 -4
  124. package/src/meeting/request.ts +36 -1
  125. package/src/meeting/request.type.ts +7 -0
  126. package/src/meeting/util.ts +9 -1
  127. package/src/meeting-info/meeting-info-v2.ts +7 -2
  128. package/src/meeting-info/utilv2.ts +5 -0
  129. package/src/meetings/index.ts +76 -0
  130. package/src/meetings/util.ts +18 -0
  131. package/src/member/index.ts +57 -22
  132. package/src/member/types.ts +82 -16
  133. package/src/member/util.ts +357 -353
  134. package/src/members/collection.ts +4 -3
  135. package/src/members/index.ts +137 -18
  136. package/src/members/request.ts +44 -0
  137. package/src/members/util.ts +43 -1
  138. package/src/metrics/constants.ts +1 -0
  139. package/src/reachability/clusterReachability.ts +26 -25
  140. package/src/reachability/index.ts +55 -1
  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 +131 -9
  148. package/test/unit/spec/locus-info/index.js +195 -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 +40 -2
  153. package/test/unit/spec/meeting/in-meeting-actions.ts +19 -4
  154. package/test/unit/spec/meeting/index.js +553 -36
  155. package/test/unit/spec/meeting/locusMediaRequest.ts +0 -30
  156. package/test/unit/spec/meeting/muteState.js +73 -2
  157. package/test/unit/spec/meeting/request.js +32 -1
  158. package/test/unit/spec/meeting/utils.js +79 -33
  159. package/test/unit/spec/meeting-info/meetinginfov2.js +41 -0
  160. package/test/unit/spec/meeting-info/utilv2.js +19 -0
  161. package/test/unit/spec/meetings/index.js +68 -1
  162. package/test/unit/spec/members/index.js +304 -78
  163. package/test/unit/spec/members/request.js +68 -22
  164. package/test/unit/spec/members/utils.js +75 -0
  165. package/test/unit/spec/reachability/clusterReachability.ts +41 -55
  166. package/test/unit/spec/reachability/index.ts +89 -0
  167. package/test/unit/spec/reconnection-manager/index.js +4 -4
  168. 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: {
@@ -529,6 +557,34 @@ describe('plugin-meetings', () => {
529
557
  );
530
558
  });
531
559
 
560
+ it('should update the transcribe spoken language', () => {
561
+ locusInfo.emitScoped = sinon.stub();
562
+ locusInfo.controls = {
563
+ transcribe: {
564
+ transcribing: false,
565
+ caption: true,
566
+ spokenLanguage: 'en-US',
567
+ },
568
+ };
569
+ newControls.transcribe.transcribing = false;
570
+ newControls.transcribe.caption = true;
571
+ newControls.transcribe.spokenLanguage = 'fr';
572
+
573
+ locusInfo.updateControls(newControls);
574
+
575
+ assert.calledWith(
576
+ locusInfo.emitScoped,
577
+ {
578
+ file: 'locus-info',
579
+ function: 'updateControls',
580
+ },
581
+ LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
582
+ {
583
+ spokenLanguage: 'fr',
584
+ }
585
+ );
586
+ });
587
+
532
588
  it('should update the manual caption state', () => {
533
589
  locusInfo.emitScoped = sinon.stub();
534
590
  locusInfo.controls = {
@@ -797,6 +853,32 @@ describe('plugin-meetings', () => {
797
853
 
798
854
  assert.isTrue(locusInfo.deltaParticipants.length === 0);
799
855
  });
856
+
857
+ it('should call with participant display name', () => {
858
+ const failureParticipant = [
859
+ {
860
+ person: {
861
+ id: 5678,
862
+ primaryDisplayString: 'Test User',
863
+ },
864
+ reason: 'FAILURE',
865
+ },
866
+ ];
867
+
868
+ locusInfo.emitScoped = sinon.stub();
869
+ locusInfo.updateParticipants(failureParticipant);
870
+ assert.calledWith(
871
+ locusInfo.emitScoped,
872
+ {
873
+ file: 'locus-info',
874
+ function: 'updateParticipants',
875
+ },
876
+ LOCUSINFO.EVENTS.PARTICIPANT_REASON_CHANGED,
877
+ {
878
+ displayName: 'Test User',
879
+ }
880
+ );
881
+ })
800
882
  });
801
883
 
802
884
  describe('#updateSelf', () => {
@@ -808,7 +890,7 @@ describe('plugin-meetings', () => {
808
890
  selfWithBrbChanged.controls.brb = enabled;
809
891
 
810
892
  locusInfo.emitScoped = sinon.stub();
811
- locusInfo.updateSelf(selfWithBrbChanged, []);
893
+ locusInfo.updateSelf(selfWithBrbChanged);
812
894
 
813
895
  assert.calledWith(
814
896
  locusInfo.emitScoped,
@@ -828,14 +910,15 @@ describe('plugin-meetings', () => {
828
910
 
829
911
  const selfWithBrbChanged = cloneDeep(self);
830
912
  selfWithBrbChanged.controls.brb = value;
831
- locusInfo.self = selfWithBrbChanged;
913
+
914
+ locusInfo.updateSelf(selfWithBrbChanged);
832
915
 
833
916
  locusInfo.emitScoped = sinon.stub();
834
917
 
835
918
  const newSelf = cloneDeep(self);
836
919
  newSelf.controls.brb = value;
837
920
 
838
- locusInfo.updateSelf(newSelf, []);
921
+ locusInfo.updateSelf(newSelf);
839
922
 
840
923
  assert.neverCalledWith(
841
924
  locusInfo.emitScoped,
@@ -852,14 +935,14 @@ describe('plugin-meetings', () => {
852
935
  it('should not trigger SELF_MEETING_BRB_CHANGED when brb state is undefined', () => {
853
936
  const selfWithBrbChanged = cloneDeep(self);
854
937
  selfWithBrbChanged.controls.brb = false;
855
- locusInfo.self = selfWithBrbChanged;
938
+ locusInfo.updateSelf(selfWithBrbChanged);
856
939
 
857
940
  locusInfo.emitScoped = sinon.stub();
858
941
 
859
942
  const newSelf = cloneDeep(self);
860
943
  newSelf.controls.brb = undefined;
861
944
 
862
- locusInfo.updateSelf(newSelf, []);
945
+ locusInfo.updateSelf(newSelf);
863
946
 
864
947
  assert.neverCalledWith(
865
948
  locusInfo.emitScoped,
@@ -882,7 +965,7 @@ describe('plugin-meetings', () => {
882
965
  ];
883
966
 
884
967
  locusInfo.emitScoped = sinon.stub();
885
- locusInfo.updateSelf(selfWithLayoutChanged, []);
968
+ locusInfo.updateSelf(selfWithLayoutChanged);
886
969
 
887
970
  assert.calledWith(
888
971
  locusInfo.emitScoped,
@@ -908,11 +991,11 @@ describe('plugin-meetings', () => {
908
991
  ];
909
992
 
910
993
  // Set the layout prior to stubbing to validate it does not change.
911
- locusInfo.updateSelf(selfWithLayoutChanged, []);
994
+ locusInfo.updateSelf(selfWithLayoutChanged);
912
995
 
913
996
  locusInfo.emitScoped = sinon.stub();
914
997
 
915
- locusInfo.updateSelf(selfWithLayoutChanged, []);
998
+ locusInfo.updateSelf(selfWithLayoutChanged);
916
999
 
917
1000
  assert.neverCalledWith(
918
1001
  locusInfo.emitScoped,
@@ -926,11 +1009,11 @@ describe('plugin-meetings', () => {
926
1009
  });
927
1010
 
928
1011
  it('should trigger MEDIA_INACTIVITY on server media inactivity', () => {
929
- locusInfo.self = self;
930
-
931
1012
  locusInfo.webex.internal.device.url = selfWithInactivity.deviceUrl;
1013
+ locusInfo.updateSelf(self);
1014
+
932
1015
  locusInfo.emitScoped = sinon.stub();
933
- locusInfo.updateSelf(selfWithInactivity, []);
1016
+ locusInfo.updateSelf(selfWithInactivity);
934
1017
 
935
1018
  assert.calledWith(
936
1019
  locusInfo.emitScoped,
@@ -952,7 +1035,7 @@ describe('plugin-meetings', () => {
952
1035
 
953
1036
  locusInfo.webex.internal.device.url = self.deviceUrl;
954
1037
  locusInfo.emitScoped = sinon.stub();
955
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1038
+ locusInfo.updateSelf(selfWithMutedByOthers);
956
1039
 
957
1040
  assert.calledWith(
958
1041
  locusInfo.emitScoped,
@@ -965,10 +1048,10 @@ describe('plugin-meetings', () => {
965
1048
  );
966
1049
 
967
1050
  // but sometimes "previous self" is defined, but without controls.audio.muted, so we test this here:
968
- locusInfo.self = cloneDeep(self);
1051
+ locusInfo.updateSelf(self);
969
1052
  locusInfo.self.controls.audio = {};
970
1053
 
971
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1054
+ locusInfo.updateSelf(selfWithMutedByOthers);
972
1055
  assert.calledWith(
973
1056
  locusInfo.emitScoped,
974
1057
  {
@@ -988,7 +1071,7 @@ describe('plugin-meetings', () => {
988
1071
 
989
1072
  locusInfo.webex.internal.device.url = self.deviceUrl;
990
1073
  locusInfo.emitScoped = sinon.stub();
991
- locusInfo.updateSelf(selfWithMutedByOthersFalse, []);
1074
+ locusInfo.updateSelf(selfWithMutedByOthersFalse);
992
1075
 
993
1076
  // we might get some calls to emitScoped, but we need to check that none of them are for SELF_REMOTE_MUTE_STATUS_UPDATED
994
1077
  locusInfo.emitScoped.getCalls().forEach((x) => {
@@ -997,20 +1080,20 @@ describe('plugin-meetings', () => {
997
1080
  });
998
1081
 
999
1082
  it('should not trigger SELF_REMOTE_MUTE_STATUS_UPDATED when being removed from meeting', () => {
1083
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1000
1084
  const selfWithMutedByOthers = cloneDeep(self);
1001
1085
 
1002
1086
  selfWithMutedByOthers.controls.audio.muted = true;
1003
1087
 
1004
- locusInfo.self = selfWithMutedByOthers;
1088
+ locusInfo.updateSelf(selfWithMutedByOthers);
1005
1089
 
1006
1090
  // when user gets removed from meeting we receive a Locus DTO without any self.controls
1007
1091
  const selfWithoutControls = cloneDeep(self);
1008
1092
 
1009
1093
  selfWithoutControls.controls = undefined;
1010
1094
 
1011
- locusInfo.webex.internal.device.url = self.deviceUrl;
1012
1095
  locusInfo.emitScoped = sinon.stub();
1013
- locusInfo.updateSelf(selfWithoutControls, []);
1096
+ locusInfo.updateSelf(selfWithoutControls);
1014
1097
 
1015
1098
  // we might get some calls to emitScoped, but we need to check that none of them are for SELF_REMOTE_MUTE_STATUS_UPDATED
1016
1099
  locusInfo.emitScoped.getCalls().forEach((x) => {
@@ -1019,14 +1102,14 @@ describe('plugin-meetings', () => {
1019
1102
  });
1020
1103
 
1021
1104
  it('should trigger SELF_REMOTE_MUTE_STATUS_UPDATED on othersMuted', () => {
1022
- locusInfo.self = self;
1105
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1106
+ locusInfo.updateSelf(self);
1023
1107
  const selfWithMutedByOthers = cloneDeep(self);
1024
1108
 
1025
1109
  selfWithMutedByOthers.controls.audio.muted = true;
1026
1110
 
1027
- locusInfo.webex.internal.device.url = self.deviceUrl;
1028
1111
  locusInfo.emitScoped = sinon.stub();
1029
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1112
+ locusInfo.updateSelf(selfWithMutedByOthers);
1030
1113
 
1031
1114
  assert.calledWith(
1032
1115
  locusInfo.emitScoped,
@@ -1050,7 +1133,7 @@ describe('plugin-meetings', () => {
1050
1133
 
1051
1134
  locusInfo.webex.internal.device.url = self.deviceUrl;
1052
1135
  locusInfo.emitScoped = sinon.stub();
1053
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1136
+ locusInfo.updateSelf(selfWithMutedByOthers);
1054
1137
 
1055
1138
  assert.calledWith(
1056
1139
  locusInfo.emitScoped,
@@ -1063,10 +1146,10 @@ describe('plugin-meetings', () => {
1063
1146
  );
1064
1147
 
1065
1148
  // but sometimes "previous self" is defined, but without controls.audio.muted, so we test this here:
1066
- locusInfo.self = cloneDeep(self);
1149
+ locusInfo.updateSelf(self);
1067
1150
  locusInfo.self.controls.video = {};
1068
1151
 
1069
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1152
+ locusInfo.updateSelf(selfWithMutedByOthers);
1070
1153
  assert.calledWith(
1071
1154
  locusInfo.emitScoped,
1072
1155
  {
@@ -1086,7 +1169,7 @@ describe('plugin-meetings', () => {
1086
1169
 
1087
1170
  locusInfo.webex.internal.device.url = self.deviceUrl;
1088
1171
  locusInfo.emitScoped = sinon.stub();
1089
- locusInfo.updateSelf(selfWithMutedByOthersFalse, []);
1172
+ locusInfo.updateSelf(selfWithMutedByOthersFalse);
1090
1173
 
1091
1174
  // 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
1175
  locusInfo.emitScoped.getCalls().forEach((x) => {
@@ -1095,14 +1178,14 @@ describe('plugin-meetings', () => {
1095
1178
  });
1096
1179
 
1097
1180
  it('should emit event when remoteVideoMuted changed', () => {
1098
- locusInfo.self = self;
1181
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1182
+ locusInfo.updateSelf(self);
1099
1183
  const selfWithMutedByOthers = cloneDeep(self);
1100
1184
 
1101
1185
  selfWithMutedByOthers.controls.video.muted = true;
1102
1186
 
1103
- locusInfo.webex.internal.device.url = self.deviceUrl;
1104
1187
  locusInfo.emitScoped = sinon.stub();
1105
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1188
+ locusInfo.updateSelf(selfWithMutedByOthers);
1106
1189
 
1107
1190
  assert.calledWith(
1108
1191
  locusInfo.emitScoped,
@@ -1117,13 +1200,13 @@ describe('plugin-meetings', () => {
1117
1200
  });
1118
1201
 
1119
1202
  it('should trigger SELF_MEETING_BREAKOUTS_CHANGED when breakouts changed', () => {
1120
- locusInfo.self = self;
1203
+ locusInfo.updateSelf(self);
1121
1204
  const selfWithBreakoutsChanged = cloneDeep(self);
1122
1205
 
1123
1206
  selfWithBreakoutsChanged.controls.breakout.sessions.active[0].name = 'new name';
1124
1207
 
1125
1208
  locusInfo.emitScoped = sinon.stub();
1126
- locusInfo.updateSelf(selfWithBreakoutsChanged, []);
1209
+ locusInfo.updateSelf(selfWithBreakoutsChanged);
1127
1210
 
1128
1211
  assert.calledWith(
1129
1212
  locusInfo.emitScoped,
@@ -1156,16 +1239,16 @@ describe('plugin-meetings', () => {
1156
1239
  });
1157
1240
 
1158
1241
  it('should trigger SELF_REMOTE_MUTE_STATUS_UPDATED if muted and disallowUnmute changed', () => {
1159
- locusInfo.self = self;
1242
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1243
+ locusInfo.updateSelf(self);
1160
1244
  const selfWithMutedByOthersAndDissalowUnmute = cloneDeep(self);
1161
1245
 
1162
1246
  // first simulate remote mute
1163
1247
  selfWithMutedByOthersAndDissalowUnmute.controls.audio.muted = true;
1164
1248
  selfWithMutedByOthersAndDissalowUnmute.controls.audio.disallowUnmute = true;
1165
1249
 
1166
- locusInfo.webex.internal.device.url = self.deviceUrl;
1167
1250
  locusInfo.emitScoped = sinon.stub();
1168
- locusInfo.updateSelf(selfWithMutedByOthersAndDissalowUnmute, []);
1251
+ locusInfo.updateSelf(selfWithMutedByOthersAndDissalowUnmute);
1169
1252
 
1170
1253
  assert.calledWith(
1171
1254
  locusInfo.emitScoped,
@@ -1183,7 +1266,7 @@ describe('plugin-meetings', () => {
1183
1266
  selfWithMutedByOthers.controls.audio.muted = true;
1184
1267
  selfWithMutedByOthers.controls.audio.disallowUnmute = false;
1185
1268
 
1186
- locusInfo.updateSelf(selfWithMutedByOthers, []);
1269
+ locusInfo.updateSelf(selfWithMutedByOthers);
1187
1270
 
1188
1271
  assert.calledWith(
1189
1272
  locusInfo.emitScoped,
@@ -1197,15 +1280,15 @@ describe('plugin-meetings', () => {
1197
1280
  });
1198
1281
 
1199
1282
  it('should trigger LOCAL_UNMUTE_REQUIRED on localAudioUnmuteRequired', () => {
1200
- locusInfo.self = self;
1283
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1284
+ locusInfo.updateSelf(self);
1201
1285
  const selfWithLocalUnmuteRequired = cloneDeep(self);
1202
1286
 
1203
1287
  selfWithLocalUnmuteRequired.controls.audio.muted = false;
1204
1288
  selfWithLocalUnmuteRequired.controls.audio.localAudioUnmuteRequired = true;
1205
1289
 
1206
- locusInfo.webex.internal.device.url = self.deviceUrl;
1207
1290
  locusInfo.emitScoped = sinon.stub();
1208
- locusInfo.updateSelf(selfWithLocalUnmuteRequired, []);
1291
+ locusInfo.updateSelf(selfWithLocalUnmuteRequired);
1209
1292
 
1210
1293
  assert.calledWith(
1211
1294
  locusInfo.emitScoped,
@@ -1222,16 +1305,16 @@ describe('plugin-meetings', () => {
1222
1305
  });
1223
1306
 
1224
1307
  it('should trigger LOCAL_UNMUTE_REQUESTED when receiving requestedToUnmute=true', () => {
1225
- locusInfo.self = self;
1308
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1309
+ locusInfo.updateSelf(self);
1226
1310
  const selfWithRequestedToUnmute = cloneDeep(self);
1227
1311
 
1228
1312
  selfWithRequestedToUnmute.controls.audio.requestedToUnmute = true;
1229
1313
  selfWithRequestedToUnmute.controls.audio.lastModifiedRequestedToUnmute =
1230
1314
  '2023-06-16T19:25:04.369Z';
1231
1315
 
1232
- locusInfo.webex.internal.device.url = self.deviceUrl;
1233
1316
  locusInfo.emitScoped = sinon.stub();
1234
- locusInfo.updateSelf(selfWithRequestedToUnmute, []);
1317
+ locusInfo.updateSelf(selfWithRequestedToUnmute);
1235
1318
 
1236
1319
  assert.calledWith(
1237
1320
  locusInfo.emitScoped,
@@ -1249,7 +1332,7 @@ describe('plugin-meetings', () => {
1249
1332
  selfWithoutRequestedToUnmute.controls.audio.requestedToUnmute = false;
1250
1333
 
1251
1334
  locusInfo.emitScoped.resetHistory();
1252
- locusInfo.updateSelf(selfWithoutRequestedToUnmute, []);
1335
+ locusInfo.updateSelf(selfWithoutRequestedToUnmute);
1253
1336
 
1254
1337
  assert.neverCalledWith(
1255
1338
  locusInfo.emitScoped,
@@ -1263,15 +1346,14 @@ describe('plugin-meetings', () => {
1263
1346
  });
1264
1347
 
1265
1348
  it('should trigger SELF_OBSERVING when moving meeting to DX', () => {
1266
- locusInfo.self = self;
1349
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1350
+ locusInfo.updateSelf(self);
1267
1351
  const selfInitiatedMove = cloneDeep(self);
1268
1352
 
1269
1353
  // Inital move meeting is iniated
1270
1354
  selfInitiatedMove.devices[0].intent.type = 'MOVE_MEDIA';
1271
1355
 
1272
- locusInfo.webex.internal.device.url = self.deviceUrl;
1273
-
1274
- locusInfo.updateSelf(selfInitiatedMove, []);
1356
+ locusInfo.updateSelf(selfInitiatedMove);
1275
1357
 
1276
1358
  locusInfo.emitScoped = sinon.stub();
1277
1359
  // When dx joined the meeting after move
@@ -1279,7 +1361,7 @@ describe('plugin-meetings', () => {
1279
1361
 
1280
1362
  selfAfterDxJoins.devices[0].intent.type = 'OBSERVE';
1281
1363
 
1282
- locusInfo.updateSelf(selfAfterDxJoins, []);
1364
+ locusInfo.updateSelf(selfAfterDxJoins);
1283
1365
 
1284
1366
  assert.calledWith(
1285
1367
  locusInfo.emitScoped,
@@ -1297,11 +1379,11 @@ describe('plugin-meetings', () => {
1297
1379
  selfClone.canNotViewTheParticipantList = false; // same
1298
1380
 
1299
1381
  // Set the layout prior to stubbing to validate it does not change.
1300
- locusInfo.updateSelf(self, []);
1382
+ locusInfo.updateSelf(self);
1301
1383
 
1302
1384
  locusInfo.emitScoped = sinon.stub();
1303
1385
 
1304
- locusInfo.updateSelf(selfClone, []);
1386
+ locusInfo.updateSelf(selfClone);
1305
1387
 
1306
1388
  assert.neverCalledWith(
1307
1389
  locusInfo.emitScoped,
@@ -1320,11 +1402,11 @@ describe('plugin-meetings', () => {
1320
1402
  selfClone.canNotViewTheParticipantList = true; // different
1321
1403
 
1322
1404
  // Set the layout prior to stubbing to validate it does not change.
1323
- locusInfo.updateSelf(self, []);
1405
+ locusInfo.updateSelf(self);
1324
1406
 
1325
1407
  locusInfo.emitScoped = sinon.stub();
1326
1408
 
1327
- locusInfo.updateSelf(selfClone, []);
1409
+ locusInfo.updateSelf(selfClone);
1328
1410
 
1329
1411
  assert.calledWith(
1330
1412
  locusInfo.emitScoped,
@@ -1343,11 +1425,11 @@ describe('plugin-meetings', () => {
1343
1425
  selfClone.isSharingBlocked = false; // same
1344
1426
 
1345
1427
  // Set the layout prior to stubbing to validate it does not change.
1346
- locusInfo.updateSelf(self, []);
1428
+ locusInfo.updateSelf(self);
1347
1429
 
1348
1430
  locusInfo.emitScoped = sinon.stub();
1349
1431
 
1350
- locusInfo.updateSelf(selfClone, []);
1432
+ locusInfo.updateSelf(selfClone);
1351
1433
 
1352
1434
  assert.neverCalledWith(
1353
1435
  locusInfo.emitScoped,
@@ -1366,11 +1448,11 @@ describe('plugin-meetings', () => {
1366
1448
  selfClone.isSharingBlocked = true; // different
1367
1449
 
1368
1450
  // Set the layout prior to stubbing to validate it does not change.
1369
- locusInfo.updateSelf(self, []);
1451
+ locusInfo.updateSelf(self);
1370
1452
 
1371
1453
  locusInfo.emitScoped = sinon.stub();
1372
1454
 
1373
- locusInfo.updateSelf(selfClone, []);
1455
+ locusInfo.updateSelf(selfClone);
1374
1456
 
1375
1457
  assert.calledWith(
1376
1458
  locusInfo.emitScoped,
@@ -1384,12 +1466,12 @@ describe('plugin-meetings', () => {
1384
1466
  });
1385
1467
 
1386
1468
  it('should trigger SELF_ROLES_CHANGED if self roles changed', () => {
1387
- locusInfo.self = self;
1469
+ locusInfo.updateSelf(self);
1388
1470
  locusInfo.emitScoped = sinon.stub();
1389
1471
  const sampleNewSelf = cloneDeep(self);
1390
1472
  sampleNewSelf.controls.role.roles = [{type: 'COHOST', hasRole: true}];
1391
1473
 
1392
- locusInfo.updateSelf(sampleNewSelf, []);
1474
+ locusInfo.updateSelf(sampleNewSelf);
1393
1475
 
1394
1476
  assert.calledWith(
1395
1477
  locusInfo.emitScoped,
@@ -1403,12 +1485,12 @@ describe('plugin-meetings', () => {
1403
1485
  });
1404
1486
 
1405
1487
  it('should not trigger SELF_ROLES_CHANGED if self roles not changed', () => {
1406
- locusInfo.self = self;
1488
+ locusInfo.updateSelf(self);
1407
1489
  locusInfo.emitScoped = sinon.stub();
1408
1490
  const sampleNewSelf = cloneDeep(self);
1409
1491
  sampleNewSelf.controls.role.roles = [{type: 'PRESENTER', hasRole: true}];
1410
1492
 
1411
- locusInfo.updateSelf(sampleNewSelf, []);
1493
+ locusInfo.updateSelf(sampleNewSelf);
1412
1494
 
1413
1495
  assert.neverCalledWith(
1414
1496
  locusInfo.emitScoped,
@@ -1422,12 +1504,12 @@ describe('plugin-meetings', () => {
1422
1504
  });
1423
1505
 
1424
1506
  it('should trigger SELF_MEETING_INTERPRETATION_CHANGED if self interpretation info changed', () => {
1425
- locusInfo.self = self;
1507
+ locusInfo.updateSelf(self);
1426
1508
  locusInfo.emitScoped = sinon.stub();
1427
1509
  const sampleNewSelf = cloneDeep(self);
1428
1510
  sampleNewSelf.controls.interpretation.targetLanguage = 'it';
1429
1511
 
1430
- locusInfo.updateSelf(sampleNewSelf, []);
1512
+ locusInfo.updateSelf(sampleNewSelf);
1431
1513
 
1432
1514
  assert.calledWith(
1433
1515
  locusInfo.emitScoped,
@@ -1444,12 +1526,12 @@ describe('plugin-meetings', () => {
1444
1526
  });
1445
1527
 
1446
1528
  it('should not trigger SELF_MEETING_INTERPRETATION_CHANGED if self interpretation info not changed', () => {
1447
- locusInfo.self = self;
1529
+ locusInfo.updateSelf(self);
1448
1530
  locusInfo.emitScoped = sinon.stub();
1449
1531
  const sampleNewSelf = cloneDeep(self);
1450
1532
  sampleNewSelf.controls.interpretation.targetLanguage = 'cn'; // same with previous one
1451
1533
 
1452
- locusInfo.updateSelf(sampleNewSelf, []);
1534
+ locusInfo.updateSelf(sampleNewSelf);
1453
1535
 
1454
1536
  assert.neverCalledWith(
1455
1537
  locusInfo.emitScoped,
@@ -1466,12 +1548,12 @@ describe('plugin-meetings', () => {
1466
1548
  });
1467
1549
 
1468
1550
  it('should not trigger any events if controls is undefined', () => {
1469
- locusInfo.self = self;
1551
+ locusInfo.updateSelf(self);
1470
1552
  locusInfo.emitScoped = sinon.stub();
1471
1553
  const newSelf = cloneDeep(self);
1472
1554
  newSelf.controls = undefined;
1473
1555
 
1474
- locusInfo.updateSelf(newSelf, []);
1556
+ locusInfo.updateSelf(newSelf);
1475
1557
 
1476
1558
  const eventsSet = new Set([
1477
1559
  LOCUSINFO.EVENTS.CONTROLS_MEETING_LAYOUT_UPDATED,
@@ -1488,6 +1570,31 @@ describe('plugin-meetings', () => {
1488
1570
  assert.isFalse(eventsSet.has(eventName));
1489
1571
  });
1490
1572
  });
1573
+
1574
+ it('calls getSelves with correct parameters', () => {
1575
+ const getSelvesStub = sinon.stub(SelfUtils, 'getSelves').returns({
1576
+ current: {},
1577
+ previous: {},
1578
+ updates: {},
1579
+ });
1580
+
1581
+ locusInfo.webex.internal.device.url = self.deviceUrl;
1582
+ locusInfo.participants = [{id: '1'}, {id: '2'}];
1583
+ locusInfo.parsedLocus.self = {id: 'fake parsed locus self id'};
1584
+
1585
+ const parsedLocusSelf = locusInfo.parsedLocus.self; // need to store it before it's updated in updateSelf
1586
+ locusInfo.updateSelf(self);
1587
+
1588
+ assert.calledWith(
1589
+ getSelvesStub,
1590
+ parsedLocusSelf,
1591
+ self,
1592
+ locusInfo.webex.internal.device.url,
1593
+ locusInfo.participants
1594
+ );
1595
+
1596
+ getSelvesStub.restore();
1597
+ });
1491
1598
  });
1492
1599
 
1493
1600
  describe('#updateMeetingInfo', () => {
@@ -1754,11 +1861,11 @@ describe('plugin-meetings', () => {
1754
1861
  });
1755
1862
 
1756
1863
  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 };
1864
+ const initialMediaShares = {audio: true, video: false};
1865
+ const newMediaShares = {audio: false, video: true};
1759
1866
 
1760
1867
  locusInfo.mediaShares = initialMediaShares;
1761
- locusInfo.parsedLocus = { mediaShares: null };
1868
+ locusInfo.parsedLocus = {mediaShares: null};
1762
1869
 
1763
1870
  const parsedMediaShares = {
1764
1871
  current: newMediaShares,
@@ -1795,9 +1902,9 @@ describe('plugin-meetings', () => {
1795
1902
  });
1796
1903
 
1797
1904
  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 };
1905
+ const initialMediaShares = {audio: true, video: false};
1799
1906
  locusInfo.mediaShares = initialMediaShares;
1800
- locusInfo.parsedLocus = { mediaShares: null };
1907
+ locusInfo.parsedLocus = {mediaShares: null};
1801
1908
 
1802
1909
  const parsedMediaShares = {
1803
1910
  current: initialMediaShares,
@@ -1829,7 +1936,7 @@ describe('plugin-meetings', () => {
1829
1936
  });
1830
1937
 
1831
1938
  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 };
1939
+ const initialMediaShares = {audio: true, video: false};
1833
1940
  locusInfo.mediaShares = initialMediaShares;
1834
1941
 
1835
1942
  // Call the function with the same mediaShares and forceUpdate = false
@@ -1843,11 +1950,11 @@ describe('plugin-meetings', () => {
1843
1950
  });
1844
1951
 
1845
1952
  it('should update internal state correctly when mediaShares are updated', () => {
1846
- const initialMediaShares = { audio: true, video: false };
1847
- const newMediaShares = { audio: false, video: true };
1953
+ const initialMediaShares = {audio: true, video: false};
1954
+ const newMediaShares = {audio: false, video: true};
1848
1955
 
1849
1956
  locusInfo.mediaShares = initialMediaShares;
1850
- locusInfo.parsedLocus = { mediaShares: null };
1957
+ locusInfo.parsedLocus = {mediaShares: null};
1851
1958
 
1852
1959
  const parsedMediaShares = {
1853
1960
  current: newMediaShares,
@@ -2386,6 +2493,21 @@ describe('plugin-meetings', () => {
2386
2493
  locusInfo.onDeltaLocus(fakeLocus);
2387
2494
  assert.calledWith(locusInfo.updateParticipants, {}, true);
2388
2495
  });
2496
+
2497
+ it('onDeltaLocus merges delta participants with existing participants', () => {
2498
+ const FAKE_DELTA_PARTICIPANTS = [
2499
+ {id: '1111'}, {id: '2222'}
2500
+ ]
2501
+ fakeLocus.participants = FAKE_DELTA_PARTICIPANTS;
2502
+
2503
+ sinon.spy(locusInfo, 'mergeParticipants');
2504
+ locusInfo.updateParticipants = sinon.stub();
2505
+ const existingParticipants = locusInfo.participants;
2506
+
2507
+ locusInfo.onDeltaLocus(fakeLocus);
2508
+ assert.calledOnceWithExactly(locusInfo.mergeParticipants, existingParticipants, FAKE_DELTA_PARTICIPANTS);
2509
+ assert.calledWith(locusInfo.updateParticipants, FAKE_DELTA_PARTICIPANTS, false);
2510
+ });
2389
2511
  });
2390
2512
 
2391
2513
  describe('#updateLocusCache', () => {