@webex/plugin-meetings 3.8.1 → 3.9.0-next.2

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 (290) hide show
  1. package/README.md +26 -13
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/constants.js +32 -3
  5. package/dist/constants.js.map +1 -1
  6. package/dist/controls-options-manager/enums.js +1 -0
  7. package/dist/controls-options-manager/enums.js.map +1 -1
  8. package/dist/controls-options-manager/types.js.map +1 -1
  9. package/dist/controls-options-manager/util.js +26 -0
  10. package/dist/controls-options-manager/util.js.map +1 -1
  11. package/dist/interpretation/index.js +1 -1
  12. package/dist/interpretation/siLanguage.js +1 -1
  13. package/dist/locus-info/controlsUtils.js +11 -3
  14. package/dist/locus-info/controlsUtils.js.map +1 -1
  15. package/dist/locus-info/index.js +69 -85
  16. package/dist/locus-info/index.js.map +1 -1
  17. package/dist/media/index.js +2 -2
  18. package/dist/media/index.js.map +1 -1
  19. package/dist/meeting/brbState.js +17 -14
  20. package/dist/meeting/brbState.js.map +1 -1
  21. package/dist/meeting/in-meeting-actions.js +11 -1
  22. package/dist/meeting/in-meeting-actions.js.map +1 -1
  23. package/dist/meeting/index.js +476 -284
  24. package/dist/meeting/index.js.map +1 -1
  25. package/dist/meeting/request.js +19 -0
  26. package/dist/meeting/request.js.map +1 -1
  27. package/dist/meeting/request.type.js.map +1 -1
  28. package/dist/{rtcMetrics/constants.js → meeting/type.js} +1 -5
  29. package/dist/meeting/type.js.map +1 -0
  30. package/dist/meeting/util.js +68 -2
  31. package/dist/meeting/util.js.map +1 -1
  32. package/dist/meetings/index.js +35 -33
  33. package/dist/meetings/index.js.map +1 -1
  34. package/dist/members/index.js +11 -9
  35. package/dist/members/index.js.map +1 -1
  36. package/dist/members/request.js +3 -3
  37. package/dist/members/request.js.map +1 -1
  38. package/dist/members/util.js +18 -6
  39. package/dist/members/util.js.map +1 -1
  40. package/dist/metrics/constants.js +1 -0
  41. package/dist/metrics/constants.js.map +1 -1
  42. package/dist/multistream/mediaRequestManager.js +1 -1
  43. package/dist/multistream/mediaRequestManager.js.map +1 -1
  44. package/dist/multistream/remoteMedia.js +34 -5
  45. package/dist/multistream/remoteMedia.js.map +1 -1
  46. package/dist/multistream/remoteMediaGroup.js +42 -2
  47. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  48. package/dist/multistream/sendSlotManager.js +32 -2
  49. package/dist/multistream/sendSlotManager.js.map +1 -1
  50. package/dist/reachability/index.js +5 -10
  51. package/dist/reachability/index.js.map +1 -1
  52. package/dist/types/constants.d.ts +28 -0
  53. package/dist/types/controls-options-manager/enums.d.ts +2 -1
  54. package/dist/types/controls-options-manager/types.d.ts +4 -1
  55. package/dist/types/locus-info/index.d.ts +0 -9
  56. package/dist/types/meeting/brbState.d.ts +0 -1
  57. package/dist/types/meeting/in-meeting-actions.d.ts +10 -0
  58. package/dist/types/meeting/index.d.ts +47 -19
  59. package/dist/types/meeting/request.d.ts +9 -1
  60. package/dist/types/meeting/request.type.d.ts +74 -0
  61. package/dist/types/meeting/type.d.ts +9 -0
  62. package/dist/types/meeting/util.d.ts +3 -0
  63. package/dist/types/members/index.d.ts +10 -7
  64. package/dist/types/members/request.d.ts +1 -1
  65. package/dist/types/members/util.d.ts +7 -3
  66. package/dist/types/metrics/constants.d.ts +1 -0
  67. package/dist/types/multistream/remoteMedia.d.ts +20 -1
  68. package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
  69. package/dist/types/multistream/sendSlotManager.d.ts +16 -0
  70. package/dist/types/reachability/index.d.ts +2 -2
  71. package/dist/webinar/index.js +1 -1
  72. package/package.json +24 -25
  73. package/src/constants.ts +32 -2
  74. package/src/controls-options-manager/enums.ts +1 -0
  75. package/src/controls-options-manager/types.ts +6 -1
  76. package/src/controls-options-manager/util.ts +31 -0
  77. package/src/locus-info/controlsUtils.ts +15 -0
  78. package/src/locus-info/index.ts +89 -86
  79. package/src/media/index.ts +2 -2
  80. package/src/meeting/brbState.ts +13 -9
  81. package/src/meeting/in-meeting-actions.ts +21 -0
  82. package/src/meeting/index.ts +271 -71
  83. package/src/meeting/request.ts +16 -0
  84. package/src/meeting/request.type.ts +64 -0
  85. package/src/meeting/type.ts +9 -0
  86. package/src/meeting/util.ts +73 -2
  87. package/src/meetings/index.ts +3 -2
  88. package/src/members/index.ts +13 -10
  89. package/src/members/request.ts +2 -2
  90. package/src/members/util.ts +16 -4
  91. package/src/metrics/constants.ts +1 -0
  92. package/src/multistream/mediaRequestManager.ts +7 -7
  93. package/src/multistream/remoteMedia.ts +34 -4
  94. package/src/multistream/remoteMediaGroup.ts +37 -2
  95. package/src/multistream/sendSlotManager.ts +34 -2
  96. package/src/reachability/index.ts +5 -13
  97. package/test/unit/spec/controls-options-manager/util.js +58 -0
  98. package/test/unit/spec/locus-info/controlsUtils.js +52 -0
  99. package/test/unit/spec/locus-info/index.js +240 -82
  100. package/test/unit/spec/media/index.ts +107 -0
  101. package/test/unit/spec/meeting/brbState.ts +23 -4
  102. package/test/unit/spec/meeting/in-meeting-actions.ts +10 -0
  103. package/test/unit/spec/meeting/index.js +954 -85
  104. package/test/unit/spec/meeting/request.js +71 -0
  105. package/test/unit/spec/meeting/utils.js +122 -1
  106. package/test/unit/spec/meetings/index.js +2 -0
  107. package/test/unit/spec/members/index.js +68 -9
  108. package/test/unit/spec/members/request.js +2 -2
  109. package/test/unit/spec/members/utils.js +27 -7
  110. package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
  111. package/test/unit/spec/multistream/remoteMedia.ts +66 -2
  112. package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
  113. package/test/unit/spec/reachability/index.ts +2 -6
  114. package/dist/annotation/annotation.types.d.ts +0 -42
  115. package/dist/annotation/constants.d.ts +0 -31
  116. package/dist/annotation/index.d.ts +0 -117
  117. package/dist/breakouts/breakout.d.ts +0 -8
  118. package/dist/breakouts/collection.d.ts +0 -5
  119. package/dist/breakouts/edit-lock-error.d.ts +0 -15
  120. package/dist/breakouts/events.d.ts +0 -8
  121. package/dist/breakouts/index.d.ts +0 -5
  122. package/dist/breakouts/request.d.ts +0 -22
  123. package/dist/breakouts/utils.d.ts +0 -15
  124. package/dist/common/browser-detection.d.ts +0 -9
  125. package/dist/common/collection.d.ts +0 -48
  126. package/dist/common/config.d.ts +0 -2
  127. package/dist/common/errors/captcha-error.d.ts +0 -15
  128. package/dist/common/errors/intent-to-join.d.ts +0 -16
  129. package/dist/common/errors/join-meeting.d.ts +0 -17
  130. package/dist/common/errors/media.d.ts +0 -15
  131. package/dist/common/errors/no-meeting-info.d.ts +0 -14
  132. package/dist/common/errors/parameter.d.ts +0 -15
  133. package/dist/common/errors/password-error.d.ts +0 -15
  134. package/dist/common/errors/permission.d.ts +0 -14
  135. package/dist/common/errors/reclaim-host-role-error.d.ts +0 -60
  136. package/dist/common/errors/reclaim-host-role-error.js +0 -158
  137. package/dist/common/errors/reclaim-host-role-error.js.map +0 -1
  138. package/dist/common/errors/reclaim-host-role-errors.d.ts +0 -60
  139. package/dist/common/errors/reconnection-in-progress.d.ts +0 -9
  140. package/dist/common/errors/reconnection-in-progress.js +0 -35
  141. package/dist/common/errors/reconnection-in-progress.js.map +0 -1
  142. package/dist/common/errors/reconnection.d.ts +0 -15
  143. package/dist/common/errors/stats.d.ts +0 -15
  144. package/dist/common/errors/webex-errors.d.ts +0 -81
  145. package/dist/common/errors/webex-meetings-error.d.ts +0 -20
  146. package/dist/common/events/events-scope.d.ts +0 -17
  147. package/dist/common/events/events.d.ts +0 -12
  148. package/dist/common/events/trigger-proxy.d.ts +0 -2
  149. package/dist/common/events/util.d.ts +0 -2
  150. package/dist/common/logs/logger-config.d.ts +0 -2
  151. package/dist/common/logs/logger-proxy.d.ts +0 -2
  152. package/dist/common/logs/request.d.ts +0 -34
  153. package/dist/common/queue.d.ts +0 -32
  154. package/dist/config.d.ts +0 -73
  155. package/dist/constants.d.ts +0 -952
  156. package/dist/controls-options-manager/constants.d.ts +0 -4
  157. package/dist/controls-options-manager/enums.d.ts +0 -5
  158. package/dist/controls-options-manager/index.d.ts +0 -120
  159. package/dist/controls-options-manager/types.d.ts +0 -43
  160. package/dist/controls-options-manager/util.d.ts +0 -7
  161. package/dist/index.d.ts +0 -4
  162. package/dist/interceptors/index.d.ts +0 -2
  163. package/dist/interceptors/locusRetry.d.ts +0 -27
  164. package/dist/interpretation/collection.d.ts +0 -5
  165. package/dist/interpretation/index.d.ts +0 -5
  166. package/dist/interpretation/siLanguage.d.ts +0 -5
  167. package/dist/locus-info/controlsUtils.d.ts +0 -2
  168. package/dist/locus-info/embeddedAppsUtils.d.ts +0 -2
  169. package/dist/locus-info/fullState.d.ts +0 -2
  170. package/dist/locus-info/hostUtils.d.ts +0 -2
  171. package/dist/locus-info/index.d.ts +0 -269
  172. package/dist/locus-info/infoUtils.d.ts +0 -2
  173. package/dist/locus-info/mediaSharesUtils.d.ts +0 -2
  174. package/dist/locus-info/parser.d.ts +0 -212
  175. package/dist/locus-info/selfUtils.d.ts +0 -2
  176. package/dist/media/index.d.ts +0 -32
  177. package/dist/media/properties.d.ts +0 -108
  178. package/dist/media/util.d.ts +0 -2
  179. package/dist/mediaQualityMetrics/config.d.ts +0 -233
  180. package/dist/mediaQualityMetrics/config.js +0 -513
  181. package/dist/mediaQualityMetrics/config.js.map +0 -1
  182. package/dist/meeting/effectsState.d.ts +0 -42
  183. package/dist/meeting/effectsState.js +0 -260
  184. package/dist/meeting/effectsState.js.map +0 -1
  185. package/dist/meeting/in-meeting-actions.d.ts +0 -79
  186. package/dist/meeting/index.d.ts +0 -1622
  187. package/dist/meeting/locusMediaRequest.d.ts +0 -74
  188. package/dist/meeting/muteState.d.ts +0 -116
  189. package/dist/meeting/request.d.ts +0 -257
  190. package/dist/meeting/request.type.d.ts +0 -11
  191. package/dist/meeting/state.d.ts +0 -9
  192. package/dist/meeting/util.d.ts +0 -2
  193. package/dist/meeting/voicea-meeting.d.ts +0 -16
  194. package/dist/meeting-info/collection.d.ts +0 -20
  195. package/dist/meeting-info/index.d.ts +0 -57
  196. package/dist/meeting-info/meeting-info-v2.d.ts +0 -93
  197. package/dist/meeting-info/request.d.ts +0 -22
  198. package/dist/meeting-info/util.d.ts +0 -2
  199. package/dist/meeting-info/utilv2.d.ts +0 -2
  200. package/dist/meetings/collection.d.ts +0 -23
  201. package/dist/meetings/index.d.ts +0 -296
  202. package/dist/meetings/meetings.types.d.ts +0 -4
  203. package/dist/meetings/request.d.ts +0 -27
  204. package/dist/meetings/util.d.ts +0 -18
  205. package/dist/member/index.d.ts +0 -148
  206. package/dist/member/member.types.d.ts +0 -11
  207. package/dist/member/member.types.js +0 -18
  208. package/dist/member/member.types.js.map +0 -1
  209. package/dist/member/types.d.ts +0 -32
  210. package/dist/member/util.d.ts +0 -2
  211. package/dist/members/collection.d.ts +0 -24
  212. package/dist/members/index.d.ts +0 -308
  213. package/dist/members/request.d.ts +0 -58
  214. package/dist/members/types.d.ts +0 -25
  215. package/dist/members/util.d.ts +0 -2
  216. package/dist/metrics/config.d.ts +0 -169
  217. package/dist/metrics/config.js +0 -289
  218. package/dist/metrics/config.js.map +0 -1
  219. package/dist/metrics/constants.d.ts +0 -59
  220. package/dist/metrics/index.d.ts +0 -152
  221. package/dist/multistream/mediaRequestManager.d.ts +0 -119
  222. package/dist/multistream/receiveSlot.d.ts +0 -68
  223. package/dist/multistream/receiveSlotManager.d.ts +0 -56
  224. package/dist/multistream/remoteMedia.d.ts +0 -72
  225. package/dist/multistream/remoteMediaGroup.d.ts +0 -49
  226. package/dist/multistream/remoteMediaManager.d.ts +0 -300
  227. package/dist/multistream/sendSlotManager.d.ts +0 -69
  228. package/dist/networkQualityMonitor/index.d.ts +0 -70
  229. package/dist/networkQualityMonitor/index.js +0 -226
  230. package/dist/networkQualityMonitor/index.js.map +0 -1
  231. package/dist/peer-connection-manager/index.d.ts +0 -6
  232. package/dist/peer-connection-manager/index.js +0 -671
  233. package/dist/peer-connection-manager/index.js.map +0 -1
  234. package/dist/peer-connection-manager/util.d.ts +0 -6
  235. package/dist/peer-connection-manager/util.js +0 -110
  236. package/dist/peer-connection-manager/util.js.map +0 -1
  237. package/dist/personal-meeting-room/index.d.ts +0 -47
  238. package/dist/personal-meeting-room/request.d.ts +0 -14
  239. package/dist/personal-meeting-room/util.d.ts +0 -2
  240. package/dist/reachability/clusterReachability.d.ts +0 -109
  241. package/dist/reachability/index.d.ts +0 -139
  242. package/dist/reachability/request.d.ts +0 -35
  243. package/dist/reachability/util.d.ts +0 -8
  244. package/dist/reactions/constants.d.ts +0 -3
  245. package/dist/reactions/reactions.d.ts +0 -4
  246. package/dist/reactions/reactions.type.d.ts +0 -32
  247. package/dist/reconnection-manager/index.d.ts +0 -112
  248. package/dist/recording-controller/enums.d.ts +0 -7
  249. package/dist/recording-controller/index.d.ts +0 -193
  250. package/dist/recording-controller/util.d.ts +0 -13
  251. package/dist/roap/collection.d.ts +0 -10
  252. package/dist/roap/collection.js +0 -63
  253. package/dist/roap/collection.js.map +0 -1
  254. package/dist/roap/handler.d.ts +0 -47
  255. package/dist/roap/handler.js +0 -279
  256. package/dist/roap/handler.js.map +0 -1
  257. package/dist/roap/index.d.ts +0 -116
  258. package/dist/roap/request.d.ts +0 -35
  259. package/dist/roap/state.d.ts +0 -9
  260. package/dist/roap/state.js +0 -127
  261. package/dist/roap/state.js.map +0 -1
  262. package/dist/roap/turnDiscovery.d.ts +0 -81
  263. package/dist/roap/util.d.ts +0 -2
  264. package/dist/roap/util.js +0 -76
  265. package/dist/roap/util.js.map +0 -1
  266. package/dist/rtcMetrics/constants.d.ts +0 -4
  267. package/dist/rtcMetrics/constants.js.map +0 -1
  268. package/dist/rtcMetrics/index.d.ts +0 -61
  269. package/dist/rtcMetrics/index.js +0 -197
  270. package/dist/rtcMetrics/index.js.map +0 -1
  271. package/dist/statsAnalyzer/global.d.ts +0 -118
  272. package/dist/statsAnalyzer/global.js +0 -127
  273. package/dist/statsAnalyzer/global.js.map +0 -1
  274. package/dist/statsAnalyzer/index.d.ts +0 -193
  275. package/dist/statsAnalyzer/index.js +0 -1019
  276. package/dist/statsAnalyzer/index.js.map +0 -1
  277. package/dist/statsAnalyzer/mqaUtil.d.ts +0 -22
  278. package/dist/statsAnalyzer/mqaUtil.js +0 -181
  279. package/dist/statsAnalyzer/mqaUtil.js.map +0 -1
  280. package/dist/transcription/index.d.ts +0 -64
  281. package/dist/types/common/errors/reconnection-in-progress.d.ts +0 -9
  282. package/dist/types/mediaQualityMetrics/config.d.ts +0 -241
  283. package/dist/types/networkQualityMonitor/index.d.ts +0 -70
  284. package/dist/types/rtcMetrics/constants.d.ts +0 -4
  285. package/dist/types/rtcMetrics/index.d.ts +0 -71
  286. package/dist/types/statsAnalyzer/global.d.ts +0 -36
  287. package/dist/types/statsAnalyzer/index.d.ts +0 -217
  288. package/dist/types/statsAnalyzer/mqaUtil.d.ts +0 -48
  289. package/dist/webinar/collection.d.ts +0 -16
  290. package/dist/webinar/index.d.ts +0 -5
@@ -121,6 +121,7 @@ import {
121
121
  WEBINAR_ERROR_REGISTRATION_ID,
122
122
  JOIN_BEFORE_HOST,
123
123
  REGISTRATION_ID_STATUS,
124
+ STAGE_MANAGER_TYPE,
124
125
  } from '../constants';
125
126
  import BEHAVIORAL_METRICS from '../metrics/constants';
126
127
  import ParameterError from '../common/errors/parameter';
@@ -164,6 +165,8 @@ import {BrbState, createBrbState} from './brbState';
164
165
  import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error';
165
166
  import JoinForbiddenError from '../common/errors/join-forbidden-error';
166
167
  import {ReachabilityMetrics} from '../reachability/reachability.types';
168
+ import {SetStageOptions, SetStageVideoLayout, UnsetStageVideoLayout} from './request.type';
169
+ import {Invitee} from './type';
167
170
 
168
171
  // default callback so we don't call an undefined function, but in practice it should never be used
169
172
  const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
@@ -231,6 +234,14 @@ export type AddMediaOptions = {
231
234
  remoteMediaManagerConfig?: RemoteMediaManagerConfiguration; // applies only to multistream meetings
232
235
  bundlePolicy?: BundlePolicy; // applies only to multistream meetings
233
236
  allowMediaInLobby?: boolean; // allows adding media when in the lobby
237
+ additionalMediaOptions?: AdditionalMediaOptions; // allows adding additional options like send/receive audio/video
238
+ };
239
+
240
+ export type AdditionalMediaOptions = {
241
+ sendVideo?: boolean; // if not specified, default value of videoEnabled is used
242
+ receiveVideo?: boolean; // if not specified, default value of videoEnabled is used
243
+ sendAudio?: boolean; // if not specified, default value of audioEnabled true is used
244
+ receiveAudio?: boolean; // if not specified, default value of audioEnabled true is used
234
245
  };
235
246
 
236
247
  export type CallStateForMetrics = {
@@ -240,6 +251,7 @@ export type CallStateForMetrics = {
240
251
  loginType?: string;
241
252
  userNameInput?: string;
242
253
  emailInput?: string;
254
+ pstnCorrelationId?: string;
243
255
  };
244
256
 
245
257
  export const MEDIA_UPDATE_TYPE = {
@@ -263,8 +275,9 @@ type FetchMeetingInfoParams = {
263
275
  };
264
276
 
265
277
  type MediaReachabilityMetrics = ReachabilityMetrics & {
266
- isSubnetReachable: boolean;
267
- selectedCluster: string | null;
278
+ subnet_reachable: boolean;
279
+ selected_cluster: string | null;
280
+ selected_subnet: string | null;
268
281
  };
269
282
 
270
283
  /**
@@ -732,10 +745,11 @@ export default class Meeting extends StatelessWebexPlugin {
732
745
  /**
733
746
  * @param {Object} attrs
734
747
  * @param {Object} options
748
+ * @param {Function} callback - if provided, it will be called with the newly created meeting object as soon as the meeting.id is set
735
749
  * @constructor
736
750
  * @memberof Meeting
737
751
  */
738
- constructor(attrs: any, options: object) {
752
+ constructor(attrs: any, options: object, callback: (meeting: Meeting) => void) {
739
753
  super({}, options);
740
754
  /**
741
755
  * @instance
@@ -761,6 +775,11 @@ export default class Meeting extends StatelessWebexPlugin {
761
775
  * @memberof Meeting
762
776
  */
763
777
  this.id = uuid.v4();
778
+
779
+ if (callback) {
780
+ callback(this);
781
+ }
782
+
764
783
  /**
765
784
  * Call state used for metrics
766
785
  * @instance
@@ -1344,7 +1363,7 @@ export default class Meeting extends StatelessWebexPlugin {
1344
1363
  captions: [],
1345
1364
  isListening: false,
1346
1365
  commandText: '',
1347
- languageOptions: {},
1366
+ languageOptions: {currentSpokenLanguage: 'en'},
1348
1367
  showCaptionBox: false,
1349
1368
  transcribingRequestStatus: 'INACTIVE',
1350
1369
  isCaptioning: false,
@@ -1665,6 +1684,22 @@ export default class Meeting extends StatelessWebexPlugin {
1665
1684
  this.callStateForMetrics.correlationId = correlationId;
1666
1685
  }
1667
1686
 
1687
+ /**
1688
+ * Getter - Returns callStateForMetrics.pstnCorrelationId
1689
+ * @returns {string | undefined}
1690
+ */
1691
+ get pstnCorrelationId(): string | undefined {
1692
+ return this.callStateForMetrics.pstnCorrelationId;
1693
+ }
1694
+
1695
+ /**
1696
+ * Setter - sets callStateForMetrics.pstnCorrelationId
1697
+ * @param {string | undefined} correlationId
1698
+ */
1699
+ set pstnCorrelationId(correlationId: string | undefined) {
1700
+ this.callStateForMetrics.pstnCorrelationId = correlationId;
1701
+ }
1702
+
1668
1703
  /**
1669
1704
  * Getter - Returns callStateForMetrics.userNameInput
1670
1705
  * @returns {string}
@@ -2753,6 +2788,29 @@ export default class Meeting extends StatelessWebexPlugin {
2753
2788
  }
2754
2789
  );
2755
2790
 
2791
+ this.locusInfo.on(
2792
+ LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
2793
+ ({spokenLanguage}) => {
2794
+ if (spokenLanguage) {
2795
+ if (this.transcription?.languageOptions) {
2796
+ this.transcription.languageOptions.currentSpokenLanguage = spokenLanguage;
2797
+ }
2798
+ // @ts-ignore
2799
+ this.webex.internal.voicea.onSpokenLanguageUpdate(spokenLanguage, this.id);
2800
+
2801
+ Trigger.trigger(
2802
+ this,
2803
+ {
2804
+ file: 'meeting/index',
2805
+ function: 'setupLocusControlsListener',
2806
+ },
2807
+ EVENT_TRIGGERS.MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
2808
+ {spokenLanguage, meetingId: this.id}
2809
+ );
2810
+ }
2811
+ }
2812
+ );
2813
+
2756
2814
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_MANUAL_CAPTION_UPDATED, ({enable}) => {
2757
2815
  Trigger.trigger(
2758
2816
  this,
@@ -2921,6 +2979,15 @@ export default class Meeting extends StatelessWebexPlugin {
2921
2979
  {state}
2922
2980
  );
2923
2981
  });
2982
+
2983
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_POLLING_QA_CHANGED, ({state}) => {
2984
+ Trigger.trigger(
2985
+ this,
2986
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2987
+ EVENT_TRIGGERS.MEETING_CONTROLS_POLLING_QA_UPDATED,
2988
+ {state}
2989
+ );
2990
+ });
2924
2991
  }
2925
2992
 
2926
2993
  /**
@@ -3015,12 +3082,16 @@ export default class Meeting extends StatelessWebexPlugin {
3015
3082
  // There is no concept of local/remote share for whiteboard
3016
3083
  // It does not matter who requested to share the whiteboard, everyone gets the same view
3017
3084
  else if (whiteboardShare.disposition === FLOOR_ACTION.GRANTED) {
3018
- // WHITEBOARD - sharing whiteboard
3019
- // Webinar attendee should receive whiteboard as remote share
3020
- newShareStatus =
3021
- this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee
3022
- ? SHARE_STATUS.REMOTE_SHARE_ACTIVE
3023
- : SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
3085
+ if (this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee) {
3086
+ // WHITEBOARD - sharing whiteboard
3087
+ // Webinar attendee should receive whiteboard as remote share
3088
+ newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
3089
+ } else if (this.guest) {
3090
+ // If user is a guest to a meeting, they should receive whiteboard as remote share
3091
+ newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
3092
+ } else {
3093
+ newShareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
3094
+ }
3024
3095
  }
3025
3096
  // or if content share is either released or null and whiteboard share is either released or null, no one is sharing
3026
3097
  else if (
@@ -3078,6 +3149,23 @@ export default class Meeting extends StatelessWebexPlugin {
3078
3149
  },
3079
3150
  EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD
3080
3151
  );
3152
+ // @ts-ignore
3153
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
3154
+ key: 'internal.client.share.stopped',
3155
+ });
3156
+ // @ts-ignore
3157
+ this.webex.internal.newMetrics.submitClientEvent({
3158
+ name: 'client.share.stopped',
3159
+ payload: {
3160
+ mediaType: 'whiteboard',
3161
+ shareDuration:
3162
+ // @ts-ignore
3163
+ this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
3164
+ },
3165
+ options: {
3166
+ meetingId: this.id,
3167
+ },
3168
+ });
3081
3169
  break;
3082
3170
 
3083
3171
  case SHARE_STATUS.NO_SHARE:
@@ -3786,49 +3874,44 @@ export default class Meeting extends StatelessWebexPlugin {
3786
3874
 
3787
3875
  /**
3788
3876
  * Invite a guest to the call that isn't normally part of this call
3789
- * @param {Object} invitee
3877
+ * @param {Invitee} invitee
3790
3878
  * @param {String} invitee.emailAddress
3791
3879
  * @param {String} invitee.email
3792
3880
  * @param {String} invitee.phoneNumber
3793
3881
  * @param {Boolean} [alertIfActive]
3882
+ * @param {Boolean} [invitee.skipEmailValidation]
3883
+ * @param {Boolean} [invitee.isInternalNumber]
3794
3884
  * @returns {Promise} see #members.addMember
3795
3885
  * @public
3796
3886
  * @memberof Meeting
3797
3887
  */
3798
- public invite(
3799
- invitee: {
3800
- emailAddress: string;
3801
- email: string;
3802
- phoneNumber: string;
3803
- roles: Array<string>;
3804
- },
3805
- alertIfActive = true
3806
- ) {
3888
+ public invite(invitee: Invitee, alertIfActive = true) {
3807
3889
  return this.members.addMember(invitee, alertIfActive);
3808
3890
  }
3809
3891
 
3810
3892
  /**
3811
3893
  * Cancel an outgoing phone call invitation made during a meeting
3812
- * @param {Object} invitee
3894
+ * @param {Invitee} invitee
3813
3895
  * @param {String} invitee.phoneNumber
3814
3896
  * @returns {Promise} see #members.cancelPhoneInvite
3815
3897
  * @public
3816
3898
  * @memberof Meeting
3817
3899
  */
3818
- public cancelPhoneInvite(invitee: {phoneNumber: string}) {
3900
+ public cancelPhoneInvite(invitee: Invitee) {
3819
3901
  return this.members.cancelPhoneInvite(invitee);
3820
3902
  }
3821
3903
 
3822
3904
  /**
3823
- * Cancel an SIP call invitation made during a meeting
3824
- * @param {Object} invitee
3905
+ * Cancel an SIP/phone call invitation made during a meeting
3906
+ * @param {Invitee} invitee
3825
3907
  * @param {String} invitee.memberId
3826
- * @returns {Promise} see #members.cancelSIPInvite
3908
+ * @param {Boolean} [invitee.isInternalNumber] - When cancel phone invitation, if the number is internal
3909
+ * @returns {Promise} see #members.cancelInviteByMemberId
3827
3910
  * @public
3828
3911
  * @memberof Meeting
3829
3912
  */
3830
- public cancelSIPInvite(invitee: {memberId: string}) {
3831
- return this.members.cancelSIPInvite(invitee);
3913
+ public cancelInviteByMemberId(invitee: Invitee) {
3914
+ return this.members.cancelInviteByMemberId(invitee);
3832
3915
  }
3833
3916
 
3834
3917
  /**
@@ -3886,13 +3969,16 @@ export default class Meeting extends StatelessWebexPlugin {
3886
3969
  return Promise.reject(error);
3887
3970
  }
3888
3971
 
3889
- return this.brbState.enable(enabled, this.sendSlotManager).then(() => {
3890
- if (this.audio && enabled) {
3891
- // locus mutes the participant with brb enabled request,
3892
- // so we need to explicitly update remote mute for correct logic flow
3893
- this.audio.handleServerRemoteMuteUpdate(this, enabled);
3894
- }
3895
- });
3972
+ return this.brbState
3973
+ .enable(enabled, this.sendSlotManager)
3974
+ .then(() => {
3975
+ if (this.audio && enabled) {
3976
+ // locus mutes the participant with brb enabled request,
3977
+ // so we need to explicitly update remote mute for correct logic flow
3978
+ this.audio.handleServerRemoteMuteUpdate(this, enabled);
3979
+ }
3980
+ })
3981
+ .catch((error) => Promise.reject(error));
3896
3982
  }
3897
3983
 
3898
3984
  /**
@@ -4123,6 +4209,9 @@ export default class Meeting extends StatelessWebexPlugin {
4123
4209
  isClosedCaptionActive: MeetingUtil.isClosedCaptionActive(this.userDisplayHints),
4124
4210
  canStartManualCaption: MeetingUtil.canStartManualCaption(this.userDisplayHints),
4125
4211
  canStopManualCaption: MeetingUtil.canStopManualCaption(this.userDisplayHints),
4212
+ isLocalRecordingStarted: MeetingUtil.isLocalRecordingStarted(this.userDisplayHints),
4213
+ isLocalRecordingStopped: MeetingUtil.isLocalRecordingStopped(this.userDisplayHints),
4214
+ isLocalRecordingPaused: MeetingUtil.isLocalRecordingPaused(this.userDisplayHints),
4126
4215
  isManualCaptionActive: MeetingUtil.isManualCaptionActive(this.userDisplayHints),
4127
4216
  isSaveTranscriptsEnabled: MeetingUtil.isSaveTranscriptsEnabled(this.userDisplayHints),
4128
4217
  isWebexAssistantActive: MeetingUtil.isWebexAssistantActive(this.userDisplayHints),
@@ -4359,6 +4448,14 @@ export default class Meeting extends StatelessWebexPlugin {
4359
4448
  requiredHints: [DISPLAY_HINTS.DISABLE_RDC_MEETING_OPTION],
4360
4449
  displayHints: this.userDisplayHints,
4361
4450
  }),
4451
+ canEnablePollingQA: ControlsOptionsUtil.hasHints({
4452
+ requiredHints: [DISPLAY_HINTS.ENABLE_ATTENDEE_START_POLLING_QA],
4453
+ displayHints: this.userDisplayHints,
4454
+ }),
4455
+ canDisablePollingQA: ControlsOptionsUtil.hasHints({
4456
+ requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
4457
+ displayHints: this.userDisplayHints,
4458
+ }),
4362
4459
  }) || changed;
4363
4460
  }
4364
4461
  if (changed) {
@@ -4874,11 +4971,6 @@ export default class Meeting extends StatelessWebexPlugin {
4874
4971
 
4875
4972
  // Only send restore event when it was disconnected before and for connected later
4876
4973
  if (!this.hasWebsocketConnected) {
4877
- // @ts-ignore
4878
- this.webex.internal.newMetrics.submitClientEvent({
4879
- name: 'client.mercury.connection.restored',
4880
- options: {meetingId: this.id},
4881
- });
4882
4974
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_RESTORED, {
4883
4975
  correlation_id: this.correlationId,
4884
4976
  });
@@ -4889,11 +4981,6 @@ export default class Meeting extends StatelessWebexPlugin {
4889
4981
  // @ts-ignore
4890
4982
  this.webex.internal.mercury.on(OFFLINE, () => {
4891
4983
  LoggerProxy.logger.error('Meeting:index#setMercuryListener --> Web socket offline');
4892
- // @ts-ignore
4893
- this.webex.internal.newMetrics.submitClientEvent({
4894
- name: 'client.mercury.connection.lost',
4895
- options: {meetingId: this.id},
4896
- });
4897
4984
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_FAILURE, {
4898
4985
  correlation_id: this.correlationId,
4899
4986
  });
@@ -5882,15 +5969,6 @@ export default class Meeting extends StatelessWebexPlugin {
5882
5969
  this.meetingFiniteStateMachine.fail(error);
5883
5970
  LoggerProxy.logger.error('Meeting:index#join --> Failed', error);
5884
5971
 
5885
- // @ts-ignore
5886
- this.webex.internal.newMetrics.submitClientEvent({
5887
- name: 'client.locus.join.response',
5888
- payload: {
5889
- identifiers: {meetingLookupUrl: this.meetingInfo?.meetingLookupUrl},
5890
- },
5891
- options: {meetingId: this.id, rawError: error},
5892
- });
5893
-
5894
5972
  // TODO: change this to error codes and pre defined dictionary
5895
5973
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_FAILURE, {
5896
5974
  correlation_id: this.correlationId,
@@ -6040,8 +6118,9 @@ export default class Meeting extends StatelessWebexPlugin {
6040
6118
  */
6041
6119
  private dialInPstn() {
6042
6120
  if (this.isPhoneProvisioned(this.dialInDeviceStatus)) return Promise.resolve(); // prevent multiple dial in devices from being provisioned
6121
+ this.pstnCorrelationId = uuid.v4();
6043
6122
 
6044
- const {correlationId, locusUrl} = this;
6123
+ const {pstnCorrelationId, locusUrl} = this;
6045
6124
 
6046
6125
  if (!this.dialInUrl) this.dialInUrl = `dialin:///${uuid.v4()}`;
6047
6126
 
@@ -6049,7 +6128,7 @@ export default class Meeting extends StatelessWebexPlugin {
6049
6128
  this.meetingRequest
6050
6129
  // @ts-ignore
6051
6130
  .dialIn({
6052
- correlationId,
6131
+ correlationId: pstnCorrelationId,
6053
6132
  dialInUrl: this.dialInUrl,
6054
6133
  locusUrl,
6055
6134
  clientUrl: this.deviceUrl,
@@ -6058,12 +6137,17 @@ export default class Meeting extends StatelessWebexPlugin {
6058
6137
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
6059
6138
  correlation_id: this.correlationId,
6060
6139
  dial_in_url: this.dialInUrl,
6140
+ dial_in_correlation_id: pstnCorrelationId,
6061
6141
  locus_id: locusUrl.split('/').pop(),
6062
6142
  client_url: this.deviceUrl,
6063
6143
  reason: error.error?.message,
6064
6144
  stack: error.stack,
6065
6145
  });
6066
6146
 
6147
+ if (this.pstnCorrelationId === pstnCorrelationId) {
6148
+ this.pstnCorrelationId = undefined;
6149
+ }
6150
+
6067
6151
  return Promise.reject(error);
6068
6152
  })
6069
6153
  );
@@ -6078,8 +6162,9 @@ export default class Meeting extends StatelessWebexPlugin {
6078
6162
  */
6079
6163
  private dialOutPstn(phoneNumber: string) {
6080
6164
  if (this.isPhoneProvisioned(this.dialOutDeviceStatus)) return Promise.resolve(); // prevent multiple dial out devices from being provisioned
6165
+ this.pstnCorrelationId = uuid.v4();
6081
6166
 
6082
- const {correlationId, locusUrl} = this;
6167
+ const {locusUrl, pstnCorrelationId} = this;
6083
6168
 
6084
6169
  if (!this.dialOutUrl) this.dialOutUrl = `dialout:///${uuid.v4()}`;
6085
6170
 
@@ -6087,7 +6172,7 @@ export default class Meeting extends StatelessWebexPlugin {
6087
6172
  this.meetingRequest
6088
6173
  // @ts-ignore
6089
6174
  .dialOut({
6090
- correlationId,
6175
+ correlationId: pstnCorrelationId,
6091
6176
  dialOutUrl: this.dialOutUrl,
6092
6177
  phoneNumber,
6093
6178
  locusUrl,
@@ -6097,12 +6182,17 @@ export default class Meeting extends StatelessWebexPlugin {
6097
6182
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
6098
6183
  correlation_id: this.correlationId,
6099
6184
  dial_out_url: this.dialOutUrl,
6185
+ dial_out_correlation_id: pstnCorrelationId,
6100
6186
  locus_id: locusUrl.split('/').pop(),
6101
6187
  client_url: this.deviceUrl,
6102
6188
  reason: error.error?.message,
6103
6189
  stack: error.stack,
6104
6190
  });
6105
6191
 
6192
+ if (this.pstnCorrelationId === pstnCorrelationId) {
6193
+ this.pstnCorrelationId = undefined;
6194
+ }
6195
+
6106
6196
  return Promise.reject(error);
6107
6197
  })
6108
6198
  );
@@ -6116,6 +6206,8 @@ export default class Meeting extends StatelessWebexPlugin {
6116
6206
  * @returns {Promise}
6117
6207
  */
6118
6208
  public disconnectPhoneAudio() {
6209
+ const correlationToClear = this.pstnCorrelationId;
6210
+
6119
6211
  return Promise.all([
6120
6212
  this.isPhoneProvisioned(this.dialInDeviceStatus)
6121
6213
  ? MeetingUtil.disconnectPhoneAudio(this, this.dialInUrl)
@@ -6123,7 +6215,11 @@ export default class Meeting extends StatelessWebexPlugin {
6123
6215
  this.isPhoneProvisioned(this.dialOutDeviceStatus)
6124
6216
  ? MeetingUtil.disconnectPhoneAudio(this, this.dialOutUrl)
6125
6217
  : Promise.resolve(),
6126
- ]);
6218
+ ]).then(() => {
6219
+ if (this.pstnCorrelationId === correlationToClear) {
6220
+ this.pstnCorrelationId = undefined;
6221
+ }
6222
+ });
6127
6223
  }
6128
6224
 
6129
6225
  /**
@@ -7723,8 +7819,21 @@ export default class Meeting extends StatelessWebexPlugin {
7723
7819
  shareVideoEnabled = true,
7724
7820
  remoteMediaManagerConfig,
7725
7821
  bundlePolicy = 'max-bundle',
7822
+ additionalMediaOptions = {},
7726
7823
  } = options;
7727
7824
 
7825
+ const {
7826
+ sendVideo: rawSendVideo,
7827
+ receiveVideo: rawReceiveVideo,
7828
+ sendAudio: rawSendAudio,
7829
+ receiveAudio: rawReceiveAudio,
7830
+ } = additionalMediaOptions;
7831
+
7832
+ const sendVideo = videoEnabled && (rawSendVideo ?? true);
7833
+ const receiveVideo = videoEnabled && (rawReceiveVideo ?? true);
7834
+ const sendAudio = audioEnabled && (rawSendAudio ?? true);
7835
+ const receiveAudio = audioEnabled && (rawReceiveAudio ?? true);
7836
+
7728
7837
  this.allowMediaInLobby = options?.allowMediaInLobby;
7729
7838
 
7730
7839
  // If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
@@ -7760,11 +7869,11 @@ export default class Meeting extends StatelessWebexPlugin {
7760
7869
  // when audioEnabled/videoEnabled is true, we set sendAudio/sendVideo to true even before any streams are published
7761
7870
  // to avoid doing an extra SDP exchange when they are published for the first time
7762
7871
  this.mediaProperties.setMediaDirection({
7763
- sendAudio: audioEnabled,
7764
- sendVideo: videoEnabled,
7872
+ sendAudio,
7873
+ sendVideo,
7765
7874
  sendShare: false,
7766
- receiveAudio: audioEnabled,
7767
- receiveVideo: videoEnabled,
7875
+ receiveAudio,
7876
+ receiveVideo,
7768
7877
  receiveShare: shareAudioEnabled || shareVideoEnabled,
7769
7878
  });
7770
7879
 
@@ -8332,6 +8441,10 @@ export default class Meeting extends StatelessWebexPlugin {
8332
8441
  }
8333
8442
 
8334
8443
  if (whiteboard) {
8444
+ // @ts-ignore
8445
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
8446
+ key: 'internal.client.share.initiated',
8447
+ });
8335
8448
  // @ts-ignore
8336
8449
  this.webex.internal.newMetrics.submitClientEvent({
8337
8450
  name: 'client.share.initiated',
@@ -8391,11 +8504,17 @@ export default class Meeting extends StatelessWebexPlugin {
8391
8504
  const whiteboard = this.locusInfo.mediaShares.find((element) => element.name === 'whiteboard');
8392
8505
 
8393
8506
  if (whiteboard) {
8507
+ // @ts-ignore
8508
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
8509
+ key: 'internal.client.share.stopped',
8510
+ });
8394
8511
  // @ts-ignore
8395
8512
  this.webex.internal.newMetrics.submitClientEvent({
8396
8513
  name: 'client.share.stopped',
8397
8514
  payload: {
8398
8515
  mediaType: 'whiteboard',
8516
+ // @ts-ignore
8517
+ shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
8399
8518
  },
8400
8519
  options: {
8401
8520
  meetingId: this.id,
@@ -8553,12 +8672,18 @@ export default class Meeting extends StatelessWebexPlugin {
8553
8672
  }
8554
8673
  this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
8555
8674
  if (content) {
8675
+ // @ts-ignore
8676
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
8677
+ key: 'internal.client.share.stopped',
8678
+ });
8556
8679
  // @ts-ignore
8557
8680
  this.webex.internal.newMetrics.submitClientEvent({
8558
8681
  name: 'client.share.stopped',
8559
8682
  payload: {
8560
8683
  mediaType: 'share',
8561
8684
  shareInstanceId: this.localShareInstanceId,
8685
+ // @ts-ignore
8686
+ shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
8562
8687
  },
8563
8688
  options: {meetingId: this.id},
8564
8689
  });
@@ -9535,6 +9660,11 @@ export default class Meeting extends StatelessWebexPlugin {
9535
9660
  this.shareCAEventSentStatus.transmitStart = false;
9536
9661
  this.shareCAEventSentStatus.transmitStop = false;
9537
9662
 
9663
+ // @ts-ignore
9664
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
9665
+ key: 'internal.client.share.initiated',
9666
+ });
9667
+
9538
9668
  // @ts-ignore
9539
9669
  this.webex.internal.newMetrics.submitClientEvent({
9540
9670
  name: 'client.share.initiated',
@@ -9690,21 +9820,91 @@ export default class Meeting extends StatelessWebexPlugin {
9690
9820
  return total;
9691
9821
  }, 0);
9692
9822
 
9823
+ const selectedSubnetFirstOctet = this.mediaServerIp?.split('.')[0];
9824
+
9693
9825
  let isSubnetReachable = null;
9694
- if (totalSuccessCases > 0) {
9695
- // @ts-ignore
9696
- isSubnetReachable = this.webex.meetings.reachability.isSubnetReachable(this.mediaServerIp);
9826
+ if (totalSuccessCases > 0 && selectedSubnetFirstOctet) {
9827
+ isSubnetReachable =
9828
+ // @ts-ignore
9829
+ this.webex.meetings.reachability.isSubnetReachable(selectedSubnetFirstOctet);
9697
9830
  }
9698
9831
 
9699
- let selectedCluster = null;
9700
- if (this.mediaConnections && this.mediaConnections.length > 0) {
9701
- selectedCluster = this.mediaConnections[0].mediaAgentCluster;
9702
- }
9832
+ const selectedCluster = this.mediaConnections?.[0]?.mediaAgentCluster ?? null;
9703
9833
 
9704
9834
  return {
9705
9835
  ...reachabilityMetrics,
9706
- isSubnetReachable,
9707
- selectedCluster,
9836
+ subnet_reachable: isSubnetReachable,
9837
+ selected_cluster: selectedCluster,
9838
+ selected_subnet: selectedSubnetFirstOctet ? `${selectedSubnetFirstOctet}.X.X.X` : null,
9708
9839
  };
9709
9840
  }
9841
+
9842
+ /**
9843
+ * Set the stage for the meeting
9844
+ *
9845
+ * @param {SetStageOptions} options Options to use when setting the stage
9846
+ * @returns {Promise} The locus request
9847
+ */
9848
+ setStage({
9849
+ activeSpeakerProportion = 0.5,
9850
+ customBackground,
9851
+ customLogo,
9852
+ customNameLabel,
9853
+ importantParticipants,
9854
+ lockAttendeeViewOnStage = false,
9855
+ showActiveSpeaker = false,
9856
+ }: SetStageOptions = {}) {
9857
+ const videoLayout: SetStageVideoLayout = {
9858
+ overrideDefault: true,
9859
+ lockAttendeeViewOnStageOnly: lockAttendeeViewOnStage,
9860
+ stageParameters: {
9861
+ activeSpeakerProportion,
9862
+ showActiveSpeaker: {show: showActiveSpeaker, order: 0},
9863
+ stageManagerType: 0,
9864
+ },
9865
+ };
9866
+
9867
+ if (importantParticipants?.length) {
9868
+ videoLayout.stageParameters.importantParticipants = importantParticipants.map(
9869
+ (importantParticipant, index) => ({...importantParticipant, order: index + 1})
9870
+ );
9871
+ }
9872
+
9873
+ if (customLogo) {
9874
+ if (!videoLayout.customLayouts) {
9875
+ videoLayout.customLayouts = {};
9876
+ }
9877
+ videoLayout.customLayouts.logo = customLogo;
9878
+ // eslint-disable-next-line no-bitwise
9879
+ videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.LOGO;
9880
+ }
9881
+
9882
+ if (customBackground) {
9883
+ if (!videoLayout.customLayouts) {
9884
+ videoLayout.customLayouts = {};
9885
+ }
9886
+ videoLayout.customLayouts.background = customBackground;
9887
+ // eslint-disable-next-line no-bitwise
9888
+ videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.BACKGROUND;
9889
+ }
9890
+
9891
+ if (customNameLabel) {
9892
+ videoLayout.nameLabelStyle = customNameLabel;
9893
+ // eslint-disable-next-line no-bitwise
9894
+ videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.NAME_LABEL;
9895
+ }
9896
+
9897
+ return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
9898
+ }
9899
+
9900
+ /**
9901
+ * Unset the stage for the meeting
9902
+ *
9903
+ * @returns {Promise} The locus request
9904
+ */
9905
+ unsetStage() {
9906
+ const videoLayout: UnsetStageVideoLayout = {overrideDefault: false};
9907
+
9908
+ return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
9909
+ }
9710
9910
  }
@@ -32,6 +32,7 @@ import {
32
32
  BrbOptions,
33
33
  ToggleReactionsOptions,
34
34
  PostMeetingDataConsentOptions,
35
+ SynchronizeVideoLayout,
35
36
  } from './request.type';
36
37
  import MeetingUtil from './util';
37
38
  import {AnnotationInfo} from '../annotation/annotation.types';
@@ -969,4 +970,19 @@ export default class MeetingRequest extends StatelessWebexPlugin {
969
970
  },
970
971
  });
971
972
  }
973
+
974
+ /**
975
+ * Synchronize the stage for a meeting
976
+ *
977
+ * @param {LocusUrl} locusUrl The locus URL
978
+ * @param {SetStageVideoLayout} videoLayout The video layout to synchronize
979
+ * @returns {Promise} The locus request
980
+ */
981
+ synchronizeStage(locusUrl: string, videoLayout: SynchronizeVideoLayout) {
982
+ return this.locusDeltaRequest({
983
+ method: HTTP_VERBS.PATCH,
984
+ uri: `${locusUrl}/${CONTROLS}`,
985
+ body: {videoLayout},
986
+ });
987
+ }
972
988
  }