@webex/plugin-meetings 3.6.0-next.9 → 3.7.0-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 (118) hide show
  1. package/README.md +2 -1
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/config.js +2 -1
  5. package/dist/config.js.map +1 -1
  6. package/dist/constants.js +24 -2
  7. package/dist/constants.js.map +1 -1
  8. package/dist/controls-options-manager/enums.js +1 -0
  9. package/dist/controls-options-manager/enums.js.map +1 -1
  10. package/dist/controls-options-manager/index.js +10 -3
  11. package/dist/controls-options-manager/index.js.map +1 -1
  12. package/dist/controls-options-manager/types.js.map +1 -1
  13. package/dist/controls-options-manager/util.js +12 -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 -4
  18. package/dist/locus-info/controlsUtils.js.map +1 -1
  19. package/dist/locus-info/fullState.js +2 -1
  20. package/dist/locus-info/fullState.js.map +1 -1
  21. package/dist/locus-info/index.js +61 -3
  22. package/dist/locus-info/index.js.map +1 -1
  23. package/dist/meeting/in-meeting-actions.js +19 -1
  24. package/dist/meeting/in-meeting-actions.js.map +1 -1
  25. package/dist/meeting/index.js +564 -441
  26. package/dist/meeting/index.js.map +1 -1
  27. package/dist/meeting/locusMediaRequest.js +2 -6
  28. package/dist/meeting/locusMediaRequest.js.map +1 -1
  29. package/dist/meeting/request.js +21 -29
  30. package/dist/meeting/request.js.map +1 -1
  31. package/dist/meeting/util.js +94 -59
  32. package/dist/meeting/util.js.map +1 -1
  33. package/dist/meetings/index.js +2 -0
  34. package/dist/meetings/index.js.map +1 -1
  35. package/dist/members/index.js +3 -2
  36. package/dist/members/index.js.map +1 -1
  37. package/dist/members/util.js +9 -5
  38. package/dist/members/util.js.map +1 -1
  39. package/dist/reachability/clusterReachability.js +0 -4
  40. package/dist/reachability/clusterReachability.js.map +1 -1
  41. package/dist/reachability/index.js +433 -136
  42. package/dist/reachability/index.js.map +1 -1
  43. package/dist/reachability/reachability.types.js +7 -0
  44. package/dist/reachability/reachability.types.js.map +1 -0
  45. package/dist/reachability/request.js +23 -9
  46. package/dist/reachability/request.js.map +1 -1
  47. package/dist/roap/index.js +5 -7
  48. package/dist/roap/index.js.map +1 -1
  49. package/dist/roap/request.js +45 -79
  50. package/dist/roap/request.js.map +1 -1
  51. package/dist/roap/turnDiscovery.js +3 -6
  52. package/dist/roap/turnDiscovery.js.map +1 -1
  53. package/dist/types/config.d.ts +1 -0
  54. package/dist/types/constants.d.ts +19 -0
  55. package/dist/types/controls-options-manager/enums.d.ts +2 -1
  56. package/dist/types/controls-options-manager/index.d.ts +2 -1
  57. package/dist/types/controls-options-manager/types.d.ts +2 -0
  58. package/dist/types/locus-info/index.d.ts +9 -0
  59. package/dist/types/meeting/in-meeting-actions.d.ts +18 -0
  60. package/dist/types/meeting/index.d.ts +14 -3
  61. package/dist/types/meeting/locusMediaRequest.d.ts +2 -3
  62. package/dist/types/meeting/request.d.ts +2 -2
  63. package/dist/types/meeting/util.d.ts +2 -2
  64. package/dist/types/meetings/index.d.ts +1 -1
  65. package/dist/types/members/index.d.ts +2 -1
  66. package/dist/types/members/util.d.ts +3 -1
  67. package/dist/types/reachability/clusterReachability.d.ts +1 -10
  68. package/dist/types/reachability/index.d.ts +74 -35
  69. package/dist/types/reachability/reachability.types.d.ts +64 -0
  70. package/dist/types/reachability/request.d.ts +5 -1
  71. package/dist/types/roap/request.d.ts +1 -13
  72. package/dist/webinar/index.js +32 -19
  73. package/dist/webinar/index.js.map +1 -1
  74. package/package.json +22 -22
  75. package/src/config.ts +1 -0
  76. package/src/constants.ts +25 -0
  77. package/src/controls-options-manager/enums.ts +1 -0
  78. package/src/controls-options-manager/index.ts +19 -2
  79. package/src/controls-options-manager/types.ts +2 -0
  80. package/src/controls-options-manager/util.ts +12 -0
  81. package/src/locus-info/controlsUtils.ts +46 -2
  82. package/src/locus-info/fullState.ts +1 -0
  83. package/src/locus-info/index.ts +60 -0
  84. package/src/meeting/in-meeting-actions.ts +37 -0
  85. package/src/meeting/index.ts +114 -11
  86. package/src/meeting/locusMediaRequest.ts +4 -8
  87. package/src/meeting/request.ts +4 -11
  88. package/src/meeting/util.ts +24 -4
  89. package/src/meetings/index.ts +46 -39
  90. package/src/members/index.ts +4 -2
  91. package/src/members/util.ts +3 -1
  92. package/src/reachability/clusterReachability.ts +1 -14
  93. package/src/reachability/index.ts +285 -77
  94. package/src/reachability/reachability.types.ts +85 -0
  95. package/src/reachability/request.ts +55 -30
  96. package/src/roap/index.ts +4 -5
  97. package/src/roap/request.ts +30 -44
  98. package/src/roap/turnDiscovery.ts +2 -4
  99. package/src/webinar/index.ts +31 -17
  100. package/test/unit/spec/controls-options-manager/index.js +56 -32
  101. package/test/unit/spec/controls-options-manager/util.js +44 -0
  102. package/test/unit/spec/locus-info/controlsUtils.js +80 -4
  103. package/test/unit/spec/locus-info/index.js +59 -2
  104. package/test/unit/spec/meeting/in-meeting-actions.ts +18 -0
  105. package/test/unit/spec/meeting/index.js +231 -100
  106. package/test/unit/spec/meeting/locusMediaRequest.ts +18 -11
  107. package/test/unit/spec/meeting/request.js +3 -26
  108. package/test/unit/spec/meeting/utils.js +53 -13
  109. package/test/unit/spec/meetings/index.js +16 -1
  110. package/test/unit/spec/members/index.js +25 -2
  111. package/test/unit/spec/members/request.js +37 -3
  112. package/test/unit/spec/members/utils.js +15 -1
  113. package/test/unit/spec/reachability/index.ts +265 -1
  114. package/test/unit/spec/reachability/request.js +56 -15
  115. package/test/unit/spec/roap/index.ts +1 -1
  116. package/test/unit/spec/roap/request.ts +51 -109
  117. package/test/unit/spec/roap/turnDiscovery.ts +202 -147
  118. package/test/unit/spec/webinar/index.ts +82 -16
package/src/constants.ts CHANGED
@@ -356,6 +356,11 @@ export const EVENT_TRIGGERS = {
356
356
  'meeting:controls:view-the-participants-list:updated',
357
357
  MEETING_CONTROLS_RAISE_HAND_UPDATED: 'meeting:controls:raise-hand:updated',
358
358
  MEETING_CONTROLS_VIDEO_UPDATED: 'meeting:controls:video:updated',
359
+ MEETING_CONTROLS_STAGE_VIEW_UPDATED: 'meeting:controls:stage-view:updated',
360
+ MEETING_CONTROLS_WEBCAST_UPDATED: 'meeting:controls:webcast:updated',
361
+ MEETING_CONTROLS_MEETING_FULL_UPDATED: 'meeting:controls:meeting-full:updated',
362
+ MEETING_CONTROLS_PRACTICE_SESSION_STATUS_UPDATED:
363
+ 'meeting:controls:practice-session-status:updated',
359
364
  // Locus URL changed
360
365
  MEETING_LOCUS_URL_UPDATE: 'meeting:locus:locusUrl:update',
361
366
  MEETING_STREAM_PUBLISH_STATE_CHANGED: 'meeting:streamPublishStateChanged',
@@ -676,7 +681,11 @@ export const LOCUSINFO = {
676
681
  CONTROLS_REACTIONS_CHANGED: 'CONTROLS_REACTIONS_CHANGED',
677
682
  CONTROLS_VIEW_THE_PARTICIPANTS_LIST_CHANGED: 'CONTROLS_VIEW_THE_PARTICIPANTS_LIST_CHANGED',
678
683
  CONTROLS_RAISE_HAND_CHANGED: 'CONTROLS_RAISE_HAND_CHANGED',
684
+ CONTROLS_WEBCAST_CHANGED: 'CONTROLS_WEBCAST_CHANGED',
685
+ CONTROLS_MEETING_FULL_CHANGED: 'CONTROLS_MEETING_FULL_CHANGED',
686
+ CONTROLS_PRACTICE_SESSION_STATUS_UPDATED: 'CONTROLS_PRACTICE_SESSION_STATUS_UPDATED',
679
687
  CONTROLS_VIDEO_CHANGED: 'CONTROLS_VIDEO_CHANGED',
688
+ CONTROLS_STAGE_VIEW_UPDATED: 'CONTROLS_STAGE_VIEW_UPDATED',
680
689
  SELF_UNADMITTED_GUEST: 'SELF_UNADMITTED_GUEST',
681
690
  SELF_ADMITTED_GUEST: 'SELF_ADMITTED_GUEST',
682
691
  SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED: 'SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED',
@@ -702,6 +711,7 @@ export const LOCUSINFO = {
702
711
  SELF_MEETING_INTERPRETATION_CHANGED: 'SELF_MEETING_INTERPRETATION_CHANGED',
703
712
  MEDIA_INACTIVITY: 'MEDIA_INACTIVITY',
704
713
  LINKS_SERVICES: 'LINKS_SERVICES',
714
+ LINKS_RESOURCES: 'LINKS_RESOURCES',
705
715
  },
706
716
  };
707
717
 
@@ -944,6 +954,11 @@ export const DISPLAY_HINTS = {
944
954
  // participants list
945
955
  DISABLE_VIEW_THE_PARTICIPANT_LIST: 'DISABLE_VIEW_THE_PARTICIPANT_LIST',
946
956
  ENABLE_VIEW_THE_PARTICIPANT_LIST: 'ENABLE_VIEW_THE_PARTICIPANT_LIST',
957
+ // for webinar participants list
958
+ DISABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST: 'DISABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST',
959
+ ENABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST: 'ENABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST',
960
+ DISABLE_SHOW_ATTENDEE_COUNT: 'DISABLE_SHOW_ATTENDEE_COUNT',
961
+ ENABLE_SHOW_ATTENDEE_COUNT: 'ENABLE_SHOW_ATTENDEE_COUNT',
947
962
 
948
963
  // raise hand
949
964
  DISABLE_RAISE_HAND: 'DISABLE_RAISE_HAND',
@@ -963,6 +978,16 @@ export const DISPLAY_HINTS = {
963
978
 
964
979
  // Voip (audio/video)
965
980
  VOIP_IS_ENABLED: 'VOIP_IS_ENABLED',
981
+
982
+ // Webcast
983
+ WEBCAST_CONTROL_START: 'WEBCAST_CONTROL_START',
984
+ WEBCAST_CONTROL_STOP: 'WEBCAST_CONTROL_STOP',
985
+
986
+ // Stage View
987
+ STAGE_VIEW_ACTIVE: 'STAGE_VIEW_ACTIVE',
988
+ STAGE_VIEW_INACTIVE: 'STAGE_VIEW_INACTIVE',
989
+ ENABLE_STAGE_VIEW: 'ENABLE_STAGE_VIEW',
990
+ DISABLE_STAGE_VIEW: 'DISABLE_STAGE_VIEW',
966
991
  };
967
992
 
968
993
  export const INTERSTITIAL_DISPLAY_HINTS = [DISPLAY_HINTS.VOIP_IS_ENABLED];
@@ -2,6 +2,7 @@ enum Setting {
2
2
  disallowUnmute = 'DisallowUnmute',
3
3
  muteOnEntry = 'MuteOnEntry',
4
4
  muted = 'Muted',
5
+ roles = 'Roles',
5
6
  }
6
7
 
7
8
  enum Control {
@@ -177,7 +177,12 @@ export default class ControlsOptionsManager {
177
177
  * @memberof ControlsOptionsManager
178
178
  * @returns {Promise}
179
179
  */
180
- private setControls(setting: {[key in Setting]?: boolean}): Promise<any> {
180
+ private setControls(setting: {
181
+ [Setting.muted]?: boolean;
182
+ [Setting.disallowUnmute]?: boolean;
183
+ [Setting.muteOnEntry]?: boolean;
184
+ [Setting.roles]?: Array<string>;
185
+ }): Promise<any> {
181
186
  LoggerProxy.logger.log(
182
187
  `ControlsOptionsManager:index#setControls --> ${JSON.stringify(setting)}`
183
188
  );
@@ -190,6 +195,7 @@ export default class ControlsOptionsManager {
190
195
  Object.entries(setting).forEach(([key, value]) => {
191
196
  if (
192
197
  !shouldSkipCheckToMergeBody &&
198
+ value !== undefined &&
193
199
  !Util?.[`${value ? CAN_SET : CAN_UNSET}${key}`](this.displayHints)
194
200
  ) {
195
201
  error = new PermissionError(`${key} [${value}] not allowed, due to moderator property.`);
@@ -219,6 +225,14 @@ export default class ControlsOptionsManager {
219
225
  }
220
226
  break;
221
227
 
228
+ case Setting.roles:
229
+ if (Array.isArray(value)) {
230
+ body.audio = body.audio
231
+ ? {...body.audio, [camelCase(key)]: value}
232
+ : {[camelCase(key)]: value};
233
+ }
234
+ break;
235
+
222
236
  default:
223
237
  error = new PermissionError(`${key} [${value}] not allowed, due to moderator property.`);
224
238
  }
@@ -261,18 +275,21 @@ export default class ControlsOptionsManager {
261
275
  * @param {boolean} mutedEnabled
262
276
  * @param {boolean} disallowUnmuteEnabled
263
277
  * @param {boolean} muteOnEntryEnabled
278
+ * @param {array} roles which should be muted
264
279
  * @memberof ControlsOptionsManager
265
280
  * @returns {Promise}
266
281
  */
267
282
  public setMuteAll(
268
283
  mutedEnabled: boolean,
269
284
  disallowUnmuteEnabled: boolean,
270
- muteOnEntryEnabled: boolean
285
+ muteOnEntryEnabled: boolean,
286
+ roles: Array<string>
271
287
  ): Promise<any> {
272
288
  return this.setControls({
273
289
  [Setting.muted]: mutedEnabled,
274
290
  [Setting.disallowUnmute]: disallowUnmuteEnabled,
275
291
  [Setting.muteOnEntry]: muteOnEntryEnabled,
292
+ [Setting.roles]: roles,
276
293
  });
277
294
  }
278
295
  }
@@ -36,6 +36,8 @@ export interface VideoProperties {
36
36
 
37
37
  export interface ViewTheParticipantListProperties {
38
38
  enabled?: boolean;
39
+ panelistEnabled?: boolean;
40
+ attendeeCount?: boolean;
39
41
  }
40
42
 
41
43
  export type Properties =
@@ -217,6 +217,18 @@ class Utils {
217
217
  if (control.properties.enabled === false) {
218
218
  requiredHints.push(DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST);
219
219
  }
220
+ if (control.properties.panelistEnabled === true) {
221
+ requiredHints.push(DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST);
222
+ }
223
+ if (control.properties.panelistEnabled === false) {
224
+ requiredHints.push(DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST);
225
+ }
226
+ if (control.properties.attendeeCount === true) {
227
+ requiredHints.push(DISPLAY_HINTS.ENABLE_SHOW_ATTENDEE_COUNT);
228
+ }
229
+ if (control.properties.attendeeCount === false) {
230
+ requiredHints.push(DISPLAY_HINTS.DISABLE_SHOW_ATTENDEE_COUNT);
231
+ }
220
232
 
221
233
  return Utils.hasHints({requiredHints, displayHints});
222
234
  }
@@ -79,7 +79,11 @@ ControlsUtils.parse = (controls: any) => {
79
79
  }
80
80
 
81
81
  if (controls?.viewTheParticipantList) {
82
- parsedControls.viewTheParticipantList = {enabled: controls.viewTheParticipantList.enabled};
82
+ parsedControls.viewTheParticipantList = {
83
+ enabled: controls.viewTheParticipantList?.enabled ?? false,
84
+ panelistEnabled: controls.viewTheParticipantList?.panelistEnabled ?? false,
85
+ attendeeCount: controls.viewTheParticipantList?.attendeeCount ?? 0,
86
+ };
83
87
  }
84
88
 
85
89
  if (controls?.raiseHand) {
@@ -90,6 +94,23 @@ ControlsUtils.parse = (controls: any) => {
90
94
  parsedControls.video = {enabled: controls.video.enabled};
91
95
  }
92
96
 
97
+ if (controls?.webcastControl) {
98
+ parsedControls.webcastControl = {streaming: controls.webcastControl.streaming};
99
+ }
100
+
101
+ if (controls?.meetingFull) {
102
+ parsedControls.meetingFull = {
103
+ meetingFull: controls.meetingFull?.meetingFull ?? false,
104
+ meetingPanelistFull: controls.meetingFull?.meetingPanelistFull ?? false,
105
+ };
106
+ }
107
+
108
+ if (controls?.practiceSession) {
109
+ parsedControls.practiceSession = {
110
+ enabled: controls.practiceSession.enabled,
111
+ };
112
+ }
113
+
93
114
  return parsedControls;
94
115
  };
95
116
 
@@ -121,7 +142,11 @@ ControlsUtils.getControls = (oldControls: any, newControls: any) => {
121
142
  previous?.reactions?.showDisplayNameWithReactions,
122
143
 
123
144
  hasViewTheParticipantListChanged:
124
- current?.viewTheParticipantList?.enabled !== previous?.viewTheParticipantList?.enabled,
145
+ current?.viewTheParticipantList?.enabled !== previous?.viewTheParticipantList?.enabled ||
146
+ current?.viewTheParticipantList?.panelistEnabled !==
147
+ previous?.viewTheParticipantList?.panelistEnabled ||
148
+ current?.viewTheParticipantList?.attendeeCount !==
149
+ previous?.viewTheParticipantList?.attendeeCount,
125
150
 
126
151
  hasRaiseHandChanged: current?.raiseHand?.enabled !== previous?.raiseHand?.enabled,
127
152
 
@@ -167,6 +192,25 @@ ControlsUtils.getControls = (oldControls: any, newControls: any) => {
167
192
  hasVideoEnabledChanged:
168
193
  newControls.video?.enabled !== undefined &&
169
194
  !isEqual(previous?.videoEnabled, current?.videoEnabled),
195
+
196
+ hasWebcastChanged: !isEqual(
197
+ previous?.webcastControl?.streaming,
198
+ current?.webcastControl?.streaming
199
+ ),
200
+
201
+ hasMeetingFullChanged:
202
+ !isEqual(previous?.meetingFull?.meetingFull, current?.meetingFull?.meetingFull) ||
203
+ !isEqual(
204
+ previous?.meetingFull?.meetingPanelistFull,
205
+ current?.meetingFull?.meetingPanelistFull
206
+ ),
207
+
208
+ hasPracticeSessionEnabledChanged: !isEqual(
209
+ previous?.practiceSession?.enabled,
210
+ current?.practiceSession?.enabled
211
+ ),
212
+
213
+ hasStageViewChanged: !isEqual(previous?.videoLayout, current?.videoLayout),
170
214
  },
171
215
  };
172
216
  };
@@ -6,6 +6,7 @@ FullState.parse = (fullState) => ({
6
6
  type: fullState.type || FULL_STATE.UNKNOWN,
7
7
  meetingState: fullState.state,
8
8
  locked: fullState.locked,
9
+ attendeeCount: typeof fullState.attendeeCount === 'number' ? fullState.attendeeCount : 0,
9
10
  });
10
11
 
11
12
  FullState.getFullState = (oldFullState, newFullState) => {
@@ -64,6 +64,7 @@ export default class LocusInfo extends EventsScope {
64
64
  replace: any;
65
65
  url: any;
66
66
  services: any;
67
+ resources: any;
67
68
  mainSessionLocusCache: any;
68
69
  /**
69
70
  * Constructor
@@ -263,6 +264,7 @@ export default class LocusInfo extends EventsScope {
263
264
  this.updateHostInfo(locus.host);
264
265
  this.updateMediaShares(locus.mediaShares);
265
266
  this.updateServices(locus.links?.services);
267
+ this.updateResources(locus.links?.resources);
266
268
  }
267
269
 
268
270
  /**
@@ -452,6 +454,7 @@ export default class LocusInfo extends EventsScope {
452
454
  this.updateIdentifiers(locus.identities);
453
455
  this.updateEmbeddedApps(locus.embeddedApps);
454
456
  this.updateServices(locus.links?.services);
457
+ this.updateResources(locus.links?.resources);
455
458
  this.compareAndUpdate();
456
459
  // update which required to compare different objects from locus
457
460
  }
@@ -805,6 +808,10 @@ export default class LocusInfo extends EventsScope {
805
808
  hasRaiseHandChanged,
806
809
  hasVideoChanged,
807
810
  hasInterpretationChanged,
811
+ hasWebcastChanged,
812
+ hasMeetingFullChanged,
813
+ hasPracticeSessionEnabledChanged,
814
+ hasStageViewChanged,
808
815
  },
809
816
  current,
810
817
  } = ControlsUtils.getControls(this.controls, controls);
@@ -1008,6 +1015,38 @@ export default class LocusInfo extends EventsScope {
1008
1015
  );
1009
1016
  }
1010
1017
 
1018
+ if (hasWebcastChanged) {
1019
+ this.emitScoped(
1020
+ {file: 'locus-info', function: 'updateControls'},
1021
+ LOCUSINFO.EVENTS.CONTROLS_WEBCAST_CHANGED,
1022
+ {state: current.webcastControl}
1023
+ );
1024
+ }
1025
+
1026
+ if (hasMeetingFullChanged) {
1027
+ this.emitScoped(
1028
+ {file: 'locus-info', function: 'updateControls'},
1029
+ LOCUSINFO.EVENTS.CONTROLS_MEETING_FULL_CHANGED,
1030
+ {state: current.meetingFull}
1031
+ );
1032
+ }
1033
+
1034
+ if (hasPracticeSessionEnabledChanged) {
1035
+ this.emitScoped(
1036
+ {file: 'locus-info', function: 'updateControls'},
1037
+ LOCUSINFO.EVENTS.CONTROLS_PRACTICE_SESSION_STATUS_UPDATED,
1038
+ {state: current.practiceSession}
1039
+ );
1040
+ }
1041
+
1042
+ if (hasStageViewChanged) {
1043
+ this.emitScoped(
1044
+ {file: 'locus-info', function: 'updateControls'},
1045
+ LOCUSINFO.EVENTS.CONTROLS_STAGE_VIEW_UPDATED,
1046
+ {state: current.videoLayout}
1047
+ );
1048
+ }
1049
+
1011
1050
  this.controls = controls;
1012
1051
  }
1013
1052
  }
@@ -1064,6 +1103,27 @@ export default class LocusInfo extends EventsScope {
1064
1103
  }
1065
1104
  }
1066
1105
 
1106
+ /**
1107
+ * @param {Object} resources
1108
+ * @returns {undefined}
1109
+ * @memberof LocusInfo
1110
+ */
1111
+ updateResources(resources: Record<'webcastInstance', {url: string}>) {
1112
+ if (resources && !isEqual(this.resources, resources)) {
1113
+ this.resources = resources;
1114
+ this.emitScoped(
1115
+ {
1116
+ file: 'locus-info',
1117
+ function: 'updateResources',
1118
+ },
1119
+ LOCUSINFO.EVENTS.LINKS_RESOURCES,
1120
+ {
1121
+ resources,
1122
+ }
1123
+ );
1124
+ }
1125
+ }
1126
+
1067
1127
  /**
1068
1128
  * @param {Object} fullState
1069
1129
  * @returns {undefined}
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import {MEETINGS} from '../constants';
6
+ import ControlsOptionsUtil from '../controls-options-manager/util';
6
7
 
7
8
  /**
8
9
  * IInMeetingActions
@@ -64,6 +65,10 @@ interface IInMeetingActions {
64
65
  canUpdateShareControl?: boolean;
65
66
  canEnableViewTheParticipantsList?: boolean;
66
67
  canDisableViewTheParticipantsList?: boolean;
68
+ canEnableViewTheParticipantsListPanelist?: boolean;
69
+ canDisableViewTheParticipantsListPanelist?: boolean;
70
+ canEnableShowAttendeeCount?: boolean;
71
+ canDisableShowAttendeeCount?: boolean;
67
72
  canEnableRaiseHand?: boolean;
68
73
  canDisableRaiseHand?: boolean;
69
74
  canEnableVideo?: boolean;
@@ -83,6 +88,11 @@ interface IInMeetingActions {
83
88
  canShareWhiteBoard?: boolean;
84
89
  enforceVirtualBackground?: boolean;
85
90
  canPollingAndQA?: boolean;
91
+ canStartWebcast?: boolean;
92
+ canStopWebcast?: boolean;
93
+ canShowStageView?: boolean;
94
+ canEnableStageView?: boolean;
95
+ canDisableStageView?: boolean;
86
96
  }
87
97
 
88
98
  /**
@@ -201,6 +211,14 @@ export default class InMeetingActions implements IInMeetingActions {
201
211
 
202
212
  canDisableViewTheParticipantsList = null;
203
213
 
214
+ canEnableViewTheParticipantsListPanelist = null;
215
+
216
+ canDisableViewTheParticipantsListPanelist = null;
217
+
218
+ canEnableShowAttendeeCount = null;
219
+
220
+ canDisableShowAttendeeCount = null;
221
+
204
222
  canEnableRaiseHand = null;
205
223
 
206
224
  canDisableRaiseHand = null;
@@ -238,6 +256,16 @@ export default class InMeetingActions implements IInMeetingActions {
238
256
  canShareWhiteBoard = null;
239
257
 
240
258
  canPollingAndQA = null;
259
+
260
+ canStartWebcast = null;
261
+
262
+ canStopWebcast = null;
263
+
264
+ canShowStageView = null;
265
+
266
+ canEnableStageView = null;
267
+
268
+ canDisableStageView = null;
241
269
  /**
242
270
  * Returns all meeting action options
243
271
  * @returns {Object}
@@ -298,6 +326,10 @@ export default class InMeetingActions implements IInMeetingActions {
298
326
  canUpdateShareControl: this.canUpdateShareControl,
299
327
  canEnableViewTheParticipantsList: this.canEnableViewTheParticipantsList,
300
328
  canDisableViewTheParticipantsList: this.canDisableViewTheParticipantsList,
329
+ canEnableViewTheParticipantsListPanelist: this.canEnableViewTheParticipantsListPanelist,
330
+ canDisableViewTheParticipantsListPanelist: this.canDisableViewTheParticipantsListPanelist,
331
+ canEnableShowAttendeeCount: this.canEnableShowAttendeeCount,
332
+ canDisableShowAttendeeCount: this.canDisableShowAttendeeCount,
301
333
  canEnableRaiseHand: this.canEnableRaiseHand,
302
334
  canDisableRaiseHand: this.canDisableRaiseHand,
303
335
  canEnableVideo: this.canEnableVideo,
@@ -317,6 +349,11 @@ export default class InMeetingActions implements IInMeetingActions {
317
349
  supportHDV: this.supportHDV,
318
350
  canShareWhiteBoard: this.canShareWhiteBoard,
319
351
  canPollingAndQA: this.canPollingAndQA,
352
+ canStartWebcast: this.canStartWebcast,
353
+ canStopWebcast: this.canStopWebcast,
354
+ canShowStageView: this.canShowStageView,
355
+ canEnableStageView: this.canEnableStageView,
356
+ canDisableStageView: this.canDisableStageView,
320
357
  });
321
358
 
322
359
  /**
@@ -2014,6 +2014,7 @@ export default class Meeting extends StatelessWebexPlugin {
2014
2014
  this.setUpLocusInfoSelfListener();
2015
2015
  this.setUpLocusInfoMeetingListener();
2016
2016
  this.setUpLocusServicesListener();
2017
+ this.setUpLocusResourcesListener();
2017
2018
  // members update listeners
2018
2019
  this.setUpLocusFullStateListener();
2019
2020
  this.setUpLocusUrlListener();
@@ -2635,6 +2636,42 @@ export default class Meeting extends StatelessWebexPlugin {
2635
2636
  );
2636
2637
  });
2637
2638
 
2639
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_WEBCAST_CHANGED, ({state}) => {
2640
+ Trigger.trigger(
2641
+ this,
2642
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2643
+ EVENT_TRIGGERS.MEETING_CONTROLS_WEBCAST_UPDATED,
2644
+ {state}
2645
+ );
2646
+ });
2647
+
2648
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_FULL_CHANGED, ({state}) => {
2649
+ Trigger.trigger(
2650
+ this,
2651
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2652
+ EVENT_TRIGGERS.MEETING_CONTROLS_MEETING_FULL_UPDATED,
2653
+ {state}
2654
+ );
2655
+ });
2656
+
2657
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_PRACTICE_SESSION_STATUS_UPDATED, ({state}) => {
2658
+ Trigger.trigger(
2659
+ this,
2660
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2661
+ EVENT_TRIGGERS.MEETING_CONTROLS_PRACTICE_SESSION_STATUS_UPDATED,
2662
+ {state}
2663
+ );
2664
+ });
2665
+
2666
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_STAGE_VIEW_UPDATED, ({state}) => {
2667
+ Trigger.trigger(
2668
+ this,
2669
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2670
+ EVENT_TRIGGERS.MEETING_CONTROLS_STAGE_VIEW_UPDATED,
2671
+ {state}
2672
+ );
2673
+ });
2674
+
2638
2675
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_VIDEO_CHANGED, ({state}) => {
2639
2676
  Trigger.trigger(
2640
2677
  this,
@@ -2996,10 +3033,20 @@ export default class Meeting extends StatelessWebexPlugin {
2996
3033
  this.breakouts.breakoutServiceUrlUpdate(payload?.services?.breakout?.url);
2997
3034
  this.annotation.approvalUrlUpdate(payload?.services?.approval?.url);
2998
3035
  this.simultaneousInterpretation.approvalUrlUpdate(payload?.services?.approval?.url);
2999
- this.webinar.webcastUrlUpdate(payload?.services?.webcast?.url);
3000
- this.webinar.webinarAttendeesSearchingUrlUpdate(
3001
- payload?.services?.webinarAttendeesSearching?.url
3002
- );
3036
+ });
3037
+ }
3038
+
3039
+ /**
3040
+ * Set up the locus info resources link listener
3041
+ * update the locusInfo for webcast instance url
3042
+ * @param {Object} payload - The event payload
3043
+ * @returns {undefined}
3044
+ * @private
3045
+ * @memberof Meeting
3046
+ */
3047
+ private setUpLocusResourcesListener() {
3048
+ this.locusInfo.on(LOCUSINFO.EVENTS.LINKS_RESOURCES, (payload) => {
3049
+ this.webinar.updateWebcastUrl(payload);
3003
3050
  });
3004
3051
  }
3005
3052
 
@@ -3311,7 +3358,7 @@ export default class Meeting extends StatelessWebexPlugin {
3311
3358
  this.simultaneousInterpretation.updateCanManageInterpreters(
3312
3359
  payload.newRoles?.includes(SELF_ROLES.MODERATOR)
3313
3360
  );
3314
- this.webinar.updateCanManageWebcast(payload.newRoles?.includes(SELF_ROLES.MODERATOR));
3361
+ this.webinar.updateRoleChanged(payload);
3315
3362
  Trigger.trigger(
3316
3363
  this,
3317
3364
  {
@@ -3805,6 +3852,22 @@ export default class Meeting extends StatelessWebexPlugin {
3805
3852
  requiredHints: [DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST],
3806
3853
  displayHints: this.userDisplayHints,
3807
3854
  }),
3855
+ canEnableViewTheParticipantsListPanelist: ControlsOptionsUtil.hasHints({
3856
+ requiredHints: [DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST],
3857
+ displayHints: this.userDisplayHints,
3858
+ }),
3859
+ canDisableViewTheParticipantsListPanelist: ControlsOptionsUtil.hasHints({
3860
+ requiredHints: [DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST],
3861
+ displayHints: this.userDisplayHints,
3862
+ }),
3863
+ canEnableShowAttendeeCount: ControlsOptionsUtil.hasHints({
3864
+ requiredHints: [DISPLAY_HINTS.ENABLE_SHOW_ATTENDEE_COUNT],
3865
+ displayHints: this.userDisplayHints,
3866
+ }),
3867
+ canDisableShowAttendeeCount: ControlsOptionsUtil.hasHints({
3868
+ requiredHints: [DISPLAY_HINTS.DISABLE_SHOW_ATTENDEE_COUNT],
3869
+ displayHints: this.userDisplayHints,
3870
+ }),
3808
3871
  canEnableRaiseHand: ControlsOptionsUtil.hasHints({
3809
3872
  requiredHints: [DISPLAY_HINTS.ENABLE_RAISE_HAND],
3810
3873
  displayHints: this.userDisplayHints,
@@ -3821,6 +3884,26 @@ export default class Meeting extends StatelessWebexPlugin {
3821
3884
  requiredHints: [DISPLAY_HINTS.DISABLE_VIDEO],
3822
3885
  displayHints: this.userDisplayHints,
3823
3886
  }),
3887
+ canStartWebcast: ControlsOptionsUtil.hasHints({
3888
+ requiredHints: [DISPLAY_HINTS.WEBCAST_CONTROL_START],
3889
+ displayHints: this.userDisplayHints,
3890
+ }),
3891
+ canStopWebcast: ControlsOptionsUtil.hasHints({
3892
+ requiredHints: [DISPLAY_HINTS.WEBCAST_CONTROL_STOP],
3893
+ displayHints: this.userDisplayHints,
3894
+ }),
3895
+ canShowStageView: ControlsOptionsUtil.hasHints({
3896
+ requiredHints: [DISPLAY_HINTS.STAGE_VIEW_ACTIVE],
3897
+ displayHints: this.userDisplayHints,
3898
+ }),
3899
+ canEnableStageView: ControlsOptionsUtil.hasHints({
3900
+ requiredHints: [DISPLAY_HINTS.ENABLE_STAGE_VIEW],
3901
+ displayHints: this.userDisplayHints,
3902
+ }),
3903
+ canDisableStageView: ControlsOptionsUtil.hasHints({
3904
+ requiredHints: [DISPLAY_HINTS.DISABLE_STAGE_VIEW],
3905
+ displayHints: this.userDisplayHints,
3906
+ }),
3824
3907
  canShareFile:
3825
3908
  (ControlsOptionsUtil.hasHints({
3826
3909
  requiredHints: [DISPLAY_HINTS.SHARE_FILE],
@@ -4688,8 +4771,6 @@ export default class Meeting extends StatelessWebexPlugin {
4688
4771
  if (!joinResponse) {
4689
4772
  // This is the 1st attempt or a retry after join request failed -> we need to do a join with TURN discovery
4690
4773
 
4691
- // @ts-ignore
4692
- joinOptions.reachability = await this.webex.meetings.reachability.getReachabilityResults();
4693
4774
  const turnDiscoveryRequest = await this.roap.generateTurnDiscoveryRequestMessage(
4694
4775
  this,
4695
4776
  true
@@ -4821,6 +4902,8 @@ export default class Meeting extends StatelessWebexPlugin {
4821
4902
  );
4822
4903
  }
4823
4904
 
4905
+ this.cleanUpBeforeReconnection();
4906
+
4824
4907
  return this.reconnectionManager
4825
4908
  .reconnect(options, async () => {
4826
4909
  await this.waitForRemoteSDPAnswer();
@@ -6238,7 +6321,7 @@ export default class Meeting extends StatelessWebexPlugin {
6238
6321
  this.mediaProperties.webrtcMediaConnection.on(
6239
6322
  MediaConnectionEventNames.ICE_CANDIDATE,
6240
6323
  (event) => {
6241
- if (event.candidate) {
6324
+ if (event.candidate && event.candidate.candidate && event.candidate.candidate.length > 0) {
6242
6325
  this.iceCandidatesCount += 1;
6243
6326
  }
6244
6327
  }
@@ -6949,6 +7032,23 @@ export default class Meeting extends StatelessWebexPlugin {
6949
7032
  }
6950
7033
  }
6951
7034
 
7035
+ private async cleanUpBeforeReconnection(): Promise<void> {
7036
+ try {
7037
+ // when media fails, we want to upload a webrtc dump to see whats going on
7038
+ // this function is async, but returns once the stats have been gathered
7039
+ await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});
7040
+
7041
+ if (this.statsAnalyzer) {
7042
+ await this.statsAnalyzer.stopAnalyzer();
7043
+ }
7044
+ } catch (error) {
7045
+ LoggerProxy.logger.error(
7046
+ 'Meeting:index#cleanUpBeforeReconnection --> Error during cleanup: ',
7047
+ error
7048
+ );
7049
+ }
7050
+ }
7051
+
6952
7052
  /**
6953
7053
  * Creates an instance of LocusMediaRequest for this meeting - it is needed for doing any calls
6954
7054
  * to Locus /media API (these are used for sending Roap messages and updating audio/video mute status).
@@ -7040,7 +7140,7 @@ export default class Meeting extends StatelessWebexPlugin {
7040
7140
  shareAudioEnabled = true,
7041
7141
  shareVideoEnabled = true,
7042
7142
  remoteMediaManagerConfig,
7043
- bundlePolicy,
7143
+ bundlePolicy = 'max-bundle',
7044
7144
  } = options;
7045
7145
 
7046
7146
  this.allowMediaInLobby = options?.allowMediaInLobby;
@@ -7927,18 +8027,21 @@ export default class Meeting extends StatelessWebexPlugin {
7927
8027
  * @param {boolean} mutedEnabled
7928
8028
  * @param {boolean} disallowUnmuteEnabled
7929
8029
  * @param {boolean} muteOnEntryEnabled
8030
+ * @param {array} roles
7930
8031
  * @public
7931
8032
  * @memberof Meeting
7932
8033
  */
7933
8034
  public setMuteAll(
7934
8035
  mutedEnabled: boolean,
7935
8036
  disallowUnmuteEnabled: boolean,
7936
- muteOnEntryEnabled: boolean
8037
+ muteOnEntryEnabled: boolean,
8038
+ roles: Array<string>
7937
8039
  ) {
7938
8040
  return this.controlsOptionsManager.setMuteAll(
7939
8041
  mutedEnabled,
7940
8042
  disallowUnmuteEnabled,
7941
- muteOnEntryEnabled
8043
+ muteOnEntryEnabled,
8044
+ roles
7942
8045
  );
7943
8046
  }
7944
8047
 
@@ -2,8 +2,9 @@
2
2
  import {defer} from 'lodash';
3
3
  import {Defer} from '@webex/common';
4
4
  import {WebexPlugin} from '@webex/webex-core';
5
- import {MEDIA, HTTP_VERBS, ROAP, IP_VERSION} from '../constants';
5
+ import {MEDIA, HTTP_VERBS, ROAP} from '../constants';
6
6
  import LoggerProxy from '../common/logs/logger-proxy';
7
+ import {ClientMediaPreferences} from '../reachability/reachability.types';
7
8
 
8
9
  export type MediaRequestType = 'RoapMessage' | 'LocalMute';
9
10
  export type RequestResult = any;
@@ -14,9 +15,8 @@ export type RoapRequest = {
14
15
  mediaId: string;
15
16
  roapMessage: any;
16
17
  reachability: any;
18
+ clientMediaPreferences: ClientMediaPreferences;
17
19
  sequence?: any;
18
- joinCookie: any; // any, because this is opaque to the client, we pass whatever object we got from one backend component (Orpheus) to the other (Locus)
19
- ipVersion?: IP_VERSION;
20
20
  };
21
21
 
22
22
  export type LocalMuteRequest = {
@@ -202,10 +202,6 @@ export class LocusMediaRequest extends WebexPlugin {
202
202
  const body: any = {
203
203
  device: this.config.device,
204
204
  correlationId: this.config.correlationId,
205
- clientMediaPreferences: {
206
- preferTranscoding: this.config.preferTranscoding,
207
- ipver: request.type === 'RoapMessage' ? request.ipVersion : undefined,
208
- },
209
205
  };
210
206
 
211
207
  const localMedias: any = {
@@ -223,7 +219,7 @@ export class LocusMediaRequest extends WebexPlugin {
223
219
  case 'RoapMessage':
224
220
  localMedias.roapMessage = request.roapMessage;
225
221
  localMedias.reachability = request.reachability;
226
- body.clientMediaPreferences.joinCookie = request.joinCookie;
222
+ body.clientMediaPreferences = request.clientMediaPreferences;
227
223
 
228
224
  // @ts-ignore
229
225
  this.webex.internal.newMetrics.submitClientEvent({