@webex/plugin-meetings 3.8.1 → 3.9.0

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 +68 -84
  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 +428 -253
  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 +88 -82
  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 +254 -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 +218 -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 +901 -84
  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 (
@@ -3786,49 +3857,44 @@ export default class Meeting extends StatelessWebexPlugin {
3786
3857
 
3787
3858
  /**
3788
3859
  * Invite a guest to the call that isn't normally part of this call
3789
- * @param {Object} invitee
3860
+ * @param {Invitee} invitee
3790
3861
  * @param {String} invitee.emailAddress
3791
3862
  * @param {String} invitee.email
3792
3863
  * @param {String} invitee.phoneNumber
3793
3864
  * @param {Boolean} [alertIfActive]
3865
+ * @param {Boolean} [invitee.skipEmailValidation]
3866
+ * @param {Boolean} [invitee.isInternalNumber]
3794
3867
  * @returns {Promise} see #members.addMember
3795
3868
  * @public
3796
3869
  * @memberof Meeting
3797
3870
  */
3798
- public invite(
3799
- invitee: {
3800
- emailAddress: string;
3801
- email: string;
3802
- phoneNumber: string;
3803
- roles: Array<string>;
3804
- },
3805
- alertIfActive = true
3806
- ) {
3871
+ public invite(invitee: Invitee, alertIfActive = true) {
3807
3872
  return this.members.addMember(invitee, alertIfActive);
3808
3873
  }
3809
3874
 
3810
3875
  /**
3811
3876
  * Cancel an outgoing phone call invitation made during a meeting
3812
- * @param {Object} invitee
3877
+ * @param {Invitee} invitee
3813
3878
  * @param {String} invitee.phoneNumber
3814
3879
  * @returns {Promise} see #members.cancelPhoneInvite
3815
3880
  * @public
3816
3881
  * @memberof Meeting
3817
3882
  */
3818
- public cancelPhoneInvite(invitee: {phoneNumber: string}) {
3883
+ public cancelPhoneInvite(invitee: Invitee) {
3819
3884
  return this.members.cancelPhoneInvite(invitee);
3820
3885
  }
3821
3886
 
3822
3887
  /**
3823
- * Cancel an SIP call invitation made during a meeting
3824
- * @param {Object} invitee
3888
+ * Cancel an SIP/phone call invitation made during a meeting
3889
+ * @param {Invitee} invitee
3825
3890
  * @param {String} invitee.memberId
3826
- * @returns {Promise} see #members.cancelSIPInvite
3891
+ * @param {Boolean} [invitee.isInternalNumber] - When cancel phone invitation, if the number is internal
3892
+ * @returns {Promise} see #members.cancelInviteByMemberId
3827
3893
  * @public
3828
3894
  * @memberof Meeting
3829
3895
  */
3830
- public cancelSIPInvite(invitee: {memberId: string}) {
3831
- return this.members.cancelSIPInvite(invitee);
3896
+ public cancelInviteByMemberId(invitee: Invitee) {
3897
+ return this.members.cancelInviteByMemberId(invitee);
3832
3898
  }
3833
3899
 
3834
3900
  /**
@@ -3886,13 +3952,16 @@ export default class Meeting extends StatelessWebexPlugin {
3886
3952
  return Promise.reject(error);
3887
3953
  }
3888
3954
 
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
- });
3955
+ return this.brbState
3956
+ .enable(enabled, this.sendSlotManager)
3957
+ .then(() => {
3958
+ if (this.audio && enabled) {
3959
+ // locus mutes the participant with brb enabled request,
3960
+ // so we need to explicitly update remote mute for correct logic flow
3961
+ this.audio.handleServerRemoteMuteUpdate(this, enabled);
3962
+ }
3963
+ })
3964
+ .catch((error) => Promise.reject(error));
3896
3965
  }
3897
3966
 
3898
3967
  /**
@@ -4123,6 +4192,9 @@ export default class Meeting extends StatelessWebexPlugin {
4123
4192
  isClosedCaptionActive: MeetingUtil.isClosedCaptionActive(this.userDisplayHints),
4124
4193
  canStartManualCaption: MeetingUtil.canStartManualCaption(this.userDisplayHints),
4125
4194
  canStopManualCaption: MeetingUtil.canStopManualCaption(this.userDisplayHints),
4195
+ isLocalRecordingStarted: MeetingUtil.isLocalRecordingStarted(this.userDisplayHints),
4196
+ isLocalRecordingStopped: MeetingUtil.isLocalRecordingStopped(this.userDisplayHints),
4197
+ isLocalRecordingPaused: MeetingUtil.isLocalRecordingPaused(this.userDisplayHints),
4126
4198
  isManualCaptionActive: MeetingUtil.isManualCaptionActive(this.userDisplayHints),
4127
4199
  isSaveTranscriptsEnabled: MeetingUtil.isSaveTranscriptsEnabled(this.userDisplayHints),
4128
4200
  isWebexAssistantActive: MeetingUtil.isWebexAssistantActive(this.userDisplayHints),
@@ -4359,6 +4431,14 @@ export default class Meeting extends StatelessWebexPlugin {
4359
4431
  requiredHints: [DISPLAY_HINTS.DISABLE_RDC_MEETING_OPTION],
4360
4432
  displayHints: this.userDisplayHints,
4361
4433
  }),
4434
+ canEnablePollingQA: ControlsOptionsUtil.hasHints({
4435
+ requiredHints: [DISPLAY_HINTS.ENABLE_ATTENDEE_START_POLLING_QA],
4436
+ displayHints: this.userDisplayHints,
4437
+ }),
4438
+ canDisablePollingQA: ControlsOptionsUtil.hasHints({
4439
+ requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
4440
+ displayHints: this.userDisplayHints,
4441
+ }),
4362
4442
  }) || changed;
4363
4443
  }
4364
4444
  if (changed) {
@@ -4874,11 +4954,6 @@ export default class Meeting extends StatelessWebexPlugin {
4874
4954
 
4875
4955
  // Only send restore event when it was disconnected before and for connected later
4876
4956
  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
4957
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_RESTORED, {
4883
4958
  correlation_id: this.correlationId,
4884
4959
  });
@@ -4889,11 +4964,6 @@ export default class Meeting extends StatelessWebexPlugin {
4889
4964
  // @ts-ignore
4890
4965
  this.webex.internal.mercury.on(OFFLINE, () => {
4891
4966
  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
4967
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_FAILURE, {
4898
4968
  correlation_id: this.correlationId,
4899
4969
  });
@@ -5882,15 +5952,6 @@ export default class Meeting extends StatelessWebexPlugin {
5882
5952
  this.meetingFiniteStateMachine.fail(error);
5883
5953
  LoggerProxy.logger.error('Meeting:index#join --> Failed', error);
5884
5954
 
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
5955
  // TODO: change this to error codes and pre defined dictionary
5895
5956
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_FAILURE, {
5896
5957
  correlation_id: this.correlationId,
@@ -6040,8 +6101,9 @@ export default class Meeting extends StatelessWebexPlugin {
6040
6101
  */
6041
6102
  private dialInPstn() {
6042
6103
  if (this.isPhoneProvisioned(this.dialInDeviceStatus)) return Promise.resolve(); // prevent multiple dial in devices from being provisioned
6104
+ this.pstnCorrelationId = uuid.v4();
6043
6105
 
6044
- const {correlationId, locusUrl} = this;
6106
+ const {pstnCorrelationId, locusUrl} = this;
6045
6107
 
6046
6108
  if (!this.dialInUrl) this.dialInUrl = `dialin:///${uuid.v4()}`;
6047
6109
 
@@ -6049,7 +6111,7 @@ export default class Meeting extends StatelessWebexPlugin {
6049
6111
  this.meetingRequest
6050
6112
  // @ts-ignore
6051
6113
  .dialIn({
6052
- correlationId,
6114
+ correlationId: pstnCorrelationId,
6053
6115
  dialInUrl: this.dialInUrl,
6054
6116
  locusUrl,
6055
6117
  clientUrl: this.deviceUrl,
@@ -6058,12 +6120,17 @@ export default class Meeting extends StatelessWebexPlugin {
6058
6120
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
6059
6121
  correlation_id: this.correlationId,
6060
6122
  dial_in_url: this.dialInUrl,
6123
+ dial_in_correlation_id: pstnCorrelationId,
6061
6124
  locus_id: locusUrl.split('/').pop(),
6062
6125
  client_url: this.deviceUrl,
6063
6126
  reason: error.error?.message,
6064
6127
  stack: error.stack,
6065
6128
  });
6066
6129
 
6130
+ if (this.pstnCorrelationId === pstnCorrelationId) {
6131
+ this.pstnCorrelationId = undefined;
6132
+ }
6133
+
6067
6134
  return Promise.reject(error);
6068
6135
  })
6069
6136
  );
@@ -6078,8 +6145,9 @@ export default class Meeting extends StatelessWebexPlugin {
6078
6145
  */
6079
6146
  private dialOutPstn(phoneNumber: string) {
6080
6147
  if (this.isPhoneProvisioned(this.dialOutDeviceStatus)) return Promise.resolve(); // prevent multiple dial out devices from being provisioned
6148
+ this.pstnCorrelationId = uuid.v4();
6081
6149
 
6082
- const {correlationId, locusUrl} = this;
6150
+ const {locusUrl, pstnCorrelationId} = this;
6083
6151
 
6084
6152
  if (!this.dialOutUrl) this.dialOutUrl = `dialout:///${uuid.v4()}`;
6085
6153
 
@@ -6087,7 +6155,7 @@ export default class Meeting extends StatelessWebexPlugin {
6087
6155
  this.meetingRequest
6088
6156
  // @ts-ignore
6089
6157
  .dialOut({
6090
- correlationId,
6158
+ correlationId: pstnCorrelationId,
6091
6159
  dialOutUrl: this.dialOutUrl,
6092
6160
  phoneNumber,
6093
6161
  locusUrl,
@@ -6097,12 +6165,17 @@ export default class Meeting extends StatelessWebexPlugin {
6097
6165
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
6098
6166
  correlation_id: this.correlationId,
6099
6167
  dial_out_url: this.dialOutUrl,
6168
+ dial_out_correlation_id: pstnCorrelationId,
6100
6169
  locus_id: locusUrl.split('/').pop(),
6101
6170
  client_url: this.deviceUrl,
6102
6171
  reason: error.error?.message,
6103
6172
  stack: error.stack,
6104
6173
  });
6105
6174
 
6175
+ if (this.pstnCorrelationId === pstnCorrelationId) {
6176
+ this.pstnCorrelationId = undefined;
6177
+ }
6178
+
6106
6179
  return Promise.reject(error);
6107
6180
  })
6108
6181
  );
@@ -6116,6 +6189,8 @@ export default class Meeting extends StatelessWebexPlugin {
6116
6189
  * @returns {Promise}
6117
6190
  */
6118
6191
  public disconnectPhoneAudio() {
6192
+ const correlationToClear = this.pstnCorrelationId;
6193
+
6119
6194
  return Promise.all([
6120
6195
  this.isPhoneProvisioned(this.dialInDeviceStatus)
6121
6196
  ? MeetingUtil.disconnectPhoneAudio(this, this.dialInUrl)
@@ -6123,7 +6198,11 @@ export default class Meeting extends StatelessWebexPlugin {
6123
6198
  this.isPhoneProvisioned(this.dialOutDeviceStatus)
6124
6199
  ? MeetingUtil.disconnectPhoneAudio(this, this.dialOutUrl)
6125
6200
  : Promise.resolve(),
6126
- ]);
6201
+ ]).then(() => {
6202
+ if (this.pstnCorrelationId === correlationToClear) {
6203
+ this.pstnCorrelationId = undefined;
6204
+ }
6205
+ });
6127
6206
  }
6128
6207
 
6129
6208
  /**
@@ -7723,8 +7802,21 @@ export default class Meeting extends StatelessWebexPlugin {
7723
7802
  shareVideoEnabled = true,
7724
7803
  remoteMediaManagerConfig,
7725
7804
  bundlePolicy = 'max-bundle',
7805
+ additionalMediaOptions = {},
7726
7806
  } = options;
7727
7807
 
7808
+ const {
7809
+ sendVideo: rawSendVideo,
7810
+ receiveVideo: rawReceiveVideo,
7811
+ sendAudio: rawSendAudio,
7812
+ receiveAudio: rawReceiveAudio,
7813
+ } = additionalMediaOptions;
7814
+
7815
+ const sendVideo = videoEnabled && (rawSendVideo ?? true);
7816
+ const receiveVideo = videoEnabled && (rawReceiveVideo ?? true);
7817
+ const sendAudio = audioEnabled && (rawSendAudio ?? true);
7818
+ const receiveAudio = audioEnabled && (rawReceiveAudio ?? true);
7819
+
7728
7820
  this.allowMediaInLobby = options?.allowMediaInLobby;
7729
7821
 
7730
7822
  // If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
@@ -7760,11 +7852,11 @@ export default class Meeting extends StatelessWebexPlugin {
7760
7852
  // when audioEnabled/videoEnabled is true, we set sendAudio/sendVideo to true even before any streams are published
7761
7853
  // to avoid doing an extra SDP exchange when they are published for the first time
7762
7854
  this.mediaProperties.setMediaDirection({
7763
- sendAudio: audioEnabled,
7764
- sendVideo: videoEnabled,
7855
+ sendAudio,
7856
+ sendVideo,
7765
7857
  sendShare: false,
7766
- receiveAudio: audioEnabled,
7767
- receiveVideo: videoEnabled,
7858
+ receiveAudio,
7859
+ receiveVideo,
7768
7860
  receiveShare: shareAudioEnabled || shareVideoEnabled,
7769
7861
  });
7770
7862
 
@@ -8332,6 +8424,10 @@ export default class Meeting extends StatelessWebexPlugin {
8332
8424
  }
8333
8425
 
8334
8426
  if (whiteboard) {
8427
+ // @ts-ignore
8428
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
8429
+ key: 'internal.client.share.initiated',
8430
+ });
8335
8431
  // @ts-ignore
8336
8432
  this.webex.internal.newMetrics.submitClientEvent({
8337
8433
  name: 'client.share.initiated',
@@ -8391,11 +8487,17 @@ export default class Meeting extends StatelessWebexPlugin {
8391
8487
  const whiteboard = this.locusInfo.mediaShares.find((element) => element.name === 'whiteboard');
8392
8488
 
8393
8489
  if (whiteboard) {
8490
+ // @ts-ignore
8491
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
8492
+ key: 'internal.client.share.stopped',
8493
+ });
8394
8494
  // @ts-ignore
8395
8495
  this.webex.internal.newMetrics.submitClientEvent({
8396
8496
  name: 'client.share.stopped',
8397
8497
  payload: {
8398
8498
  mediaType: 'whiteboard',
8499
+ // @ts-ignore
8500
+ shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
8399
8501
  },
8400
8502
  options: {
8401
8503
  meetingId: this.id,
@@ -8553,12 +8655,18 @@ export default class Meeting extends StatelessWebexPlugin {
8553
8655
  }
8554
8656
  this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
8555
8657
  if (content) {
8658
+ // @ts-ignore
8659
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
8660
+ key: 'internal.client.share.stopped',
8661
+ });
8556
8662
  // @ts-ignore
8557
8663
  this.webex.internal.newMetrics.submitClientEvent({
8558
8664
  name: 'client.share.stopped',
8559
8665
  payload: {
8560
8666
  mediaType: 'share',
8561
8667
  shareInstanceId: this.localShareInstanceId,
8668
+ // @ts-ignore
8669
+ shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
8562
8670
  },
8563
8671
  options: {meetingId: this.id},
8564
8672
  });
@@ -9535,6 +9643,11 @@ export default class Meeting extends StatelessWebexPlugin {
9535
9643
  this.shareCAEventSentStatus.transmitStart = false;
9536
9644
  this.shareCAEventSentStatus.transmitStop = false;
9537
9645
 
9646
+ // @ts-ignore
9647
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
9648
+ key: 'internal.client.share.initiated',
9649
+ });
9650
+
9538
9651
  // @ts-ignore
9539
9652
  this.webex.internal.newMetrics.submitClientEvent({
9540
9653
  name: 'client.share.initiated',
@@ -9690,21 +9803,91 @@ export default class Meeting extends StatelessWebexPlugin {
9690
9803
  return total;
9691
9804
  }, 0);
9692
9805
 
9806
+ const selectedSubnetFirstOctet = this.mediaServerIp?.split('.')[0];
9807
+
9693
9808
  let isSubnetReachable = null;
9694
- if (totalSuccessCases > 0) {
9695
- // @ts-ignore
9696
- isSubnetReachable = this.webex.meetings.reachability.isSubnetReachable(this.mediaServerIp);
9809
+ if (totalSuccessCases > 0 && selectedSubnetFirstOctet) {
9810
+ isSubnetReachable =
9811
+ // @ts-ignore
9812
+ this.webex.meetings.reachability.isSubnetReachable(selectedSubnetFirstOctet);
9697
9813
  }
9698
9814
 
9699
- let selectedCluster = null;
9700
- if (this.mediaConnections && this.mediaConnections.length > 0) {
9701
- selectedCluster = this.mediaConnections[0].mediaAgentCluster;
9702
- }
9815
+ const selectedCluster = this.mediaConnections?.[0]?.mediaAgentCluster ?? null;
9703
9816
 
9704
9817
  return {
9705
9818
  ...reachabilityMetrics,
9706
- isSubnetReachable,
9707
- selectedCluster,
9819
+ subnet_reachable: isSubnetReachable,
9820
+ selected_cluster: selectedCluster,
9821
+ selected_subnet: selectedSubnetFirstOctet ? `${selectedSubnetFirstOctet}.X.X.X` : null,
9822
+ };
9823
+ }
9824
+
9825
+ /**
9826
+ * Set the stage for the meeting
9827
+ *
9828
+ * @param {SetStageOptions} options Options to use when setting the stage
9829
+ * @returns {Promise} The locus request
9830
+ */
9831
+ setStage({
9832
+ activeSpeakerProportion = 0.5,
9833
+ customBackground,
9834
+ customLogo,
9835
+ customNameLabel,
9836
+ importantParticipants,
9837
+ lockAttendeeViewOnStage = false,
9838
+ showActiveSpeaker = false,
9839
+ }: SetStageOptions = {}) {
9840
+ const videoLayout: SetStageVideoLayout = {
9841
+ overrideDefault: true,
9842
+ lockAttendeeViewOnStageOnly: lockAttendeeViewOnStage,
9843
+ stageParameters: {
9844
+ activeSpeakerProportion,
9845
+ showActiveSpeaker: {show: showActiveSpeaker, order: 0},
9846
+ stageManagerType: 0,
9847
+ },
9708
9848
  };
9849
+
9850
+ if (importantParticipants?.length) {
9851
+ videoLayout.stageParameters.importantParticipants = importantParticipants.map(
9852
+ (importantParticipant, index) => ({...importantParticipant, order: index + 1})
9853
+ );
9854
+ }
9855
+
9856
+ if (customLogo) {
9857
+ if (!videoLayout.customLayouts) {
9858
+ videoLayout.customLayouts = {};
9859
+ }
9860
+ videoLayout.customLayouts.logo = customLogo;
9861
+ // eslint-disable-next-line no-bitwise
9862
+ videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.LOGO;
9863
+ }
9864
+
9865
+ if (customBackground) {
9866
+ if (!videoLayout.customLayouts) {
9867
+ videoLayout.customLayouts = {};
9868
+ }
9869
+ videoLayout.customLayouts.background = customBackground;
9870
+ // eslint-disable-next-line no-bitwise
9871
+ videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.BACKGROUND;
9872
+ }
9873
+
9874
+ if (customNameLabel) {
9875
+ videoLayout.nameLabelStyle = customNameLabel;
9876
+ // eslint-disable-next-line no-bitwise
9877
+ videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.NAME_LABEL;
9878
+ }
9879
+
9880
+ return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
9881
+ }
9882
+
9883
+ /**
9884
+ * Unset the stage for the meeting
9885
+ *
9886
+ * @returns {Promise} The locus request
9887
+ */
9888
+ unsetStage() {
9889
+ const videoLayout: UnsetStageVideoLayout = {overrideDefault: false};
9890
+
9891
+ return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
9709
9892
  }
9710
9893
  }
@@ -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
  }