@webex/plugin-meetings 3.8.1 → 3.9.0-multipleLLM.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 (317) 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 +34 -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 +107 -95
  16. package/dist/locus-info/index.js.map +1 -1
  17. package/dist/locus-info/parser.js +4 -1
  18. package/dist/locus-info/parser.js.map +1 -1
  19. package/dist/media/index.js +2 -2
  20. package/dist/media/index.js.map +1 -1
  21. package/dist/media/properties.js +53 -5
  22. package/dist/media/properties.js.map +1 -1
  23. package/dist/meeting/brbState.js +17 -14
  24. package/dist/meeting/brbState.js.map +1 -1
  25. package/dist/meeting/in-meeting-actions.js +13 -1
  26. package/dist/meeting/in-meeting-actions.js.map +1 -1
  27. package/dist/meeting/index.js +555 -296
  28. package/dist/meeting/index.js.map +1 -1
  29. package/dist/meeting/muteState.js +2 -5
  30. package/dist/meeting/muteState.js.map +1 -1
  31. package/dist/meeting/request.js +44 -0
  32. package/dist/meeting/request.js.map +1 -1
  33. package/dist/meeting/request.type.js.map +1 -1
  34. package/dist/{rtcMetrics/constants.js → meeting/type.js} +1 -5
  35. package/dist/meeting/type.js.map +1 -0
  36. package/dist/meeting/util.js +98 -13
  37. package/dist/meeting/util.js.map +1 -1
  38. package/dist/meeting-info/meeting-info-v2.js +29 -21
  39. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  40. package/dist/meetings/index.js +18 -10
  41. package/dist/meetings/index.js.map +1 -1
  42. package/dist/member/types.js.map +1 -1
  43. package/dist/members/collection.js +13 -0
  44. package/dist/members/collection.js.map +1 -1
  45. package/dist/members/index.js +53 -29
  46. package/dist/members/index.js.map +1 -1
  47. package/dist/members/request.js +3 -3
  48. package/dist/members/request.js.map +1 -1
  49. package/dist/members/util.js +25 -8
  50. package/dist/members/util.js.map +1 -1
  51. package/dist/metrics/constants.js +3 -1
  52. package/dist/metrics/constants.js.map +1 -1
  53. package/dist/multistream/mediaRequestManager.js +1 -1
  54. package/dist/multistream/mediaRequestManager.js.map +1 -1
  55. package/dist/multistream/remoteMedia.js +34 -5
  56. package/dist/multistream/remoteMedia.js.map +1 -1
  57. package/dist/multistream/remoteMediaGroup.js +42 -2
  58. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  59. package/dist/multistream/sendSlotManager.js +32 -2
  60. package/dist/multistream/sendSlotManager.js.map +1 -1
  61. package/dist/reachability/index.js +8 -13
  62. package/dist/reachability/index.js.map +1 -1
  63. package/dist/types/constants.d.ts +30 -0
  64. package/dist/types/controls-options-manager/enums.d.ts +2 -1
  65. package/dist/types/controls-options-manager/types.d.ts +4 -1
  66. package/dist/types/locus-info/index.d.ts +54 -10
  67. package/dist/types/media/properties.d.ts +21 -0
  68. package/dist/types/meeting/brbState.d.ts +0 -1
  69. package/dist/types/meeting/in-meeting-actions.d.ts +12 -0
  70. package/dist/types/meeting/index.d.ts +58 -20
  71. package/dist/types/meeting/request.d.ts +18 -1
  72. package/dist/types/meeting/request.type.d.ts +74 -0
  73. package/dist/types/meeting/type.d.ts +9 -0
  74. package/dist/types/meeting/util.d.ts +13 -3
  75. package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
  76. package/dist/types/meetings/index.d.ts +3 -1
  77. package/dist/types/member/types.d.ts +1 -0
  78. package/dist/types/members/collection.d.ts +6 -0
  79. package/dist/types/members/index.d.ts +22 -9
  80. package/dist/types/members/request.d.ts +1 -1
  81. package/dist/types/members/util.d.ts +13 -6
  82. package/dist/types/metrics/constants.d.ts +2 -0
  83. package/dist/types/multistream/remoteMedia.d.ts +20 -1
  84. package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
  85. package/dist/types/multistream/sendSlotManager.d.ts +16 -0
  86. package/dist/types/reachability/index.d.ts +2 -2
  87. package/dist/webinar/index.js +1 -1
  88. package/package.json +24 -25
  89. package/src/constants.ts +34 -2
  90. package/src/controls-options-manager/enums.ts +1 -0
  91. package/src/controls-options-manager/types.ts +6 -1
  92. package/src/controls-options-manager/util.ts +31 -0
  93. package/src/locus-info/controlsUtils.ts +15 -0
  94. package/src/locus-info/index.ts +174 -96
  95. package/src/locus-info/parser.ts +5 -1
  96. package/src/media/index.ts +2 -2
  97. package/src/media/properties.ts +43 -0
  98. package/src/meeting/brbState.ts +13 -9
  99. package/src/meeting/in-meeting-actions.ts +25 -0
  100. package/src/meeting/index.ts +362 -75
  101. package/src/meeting/muteState.ts +2 -6
  102. package/src/meeting/request.ts +39 -0
  103. package/src/meeting/request.type.ts +64 -0
  104. package/src/meeting/type.ts +9 -0
  105. package/src/meeting/util.ts +114 -22
  106. package/src/meeting-info/meeting-info-v2.ts +24 -5
  107. package/src/meetings/index.ts +12 -5
  108. package/src/member/types.ts +1 -0
  109. package/src/members/collection.ts +11 -0
  110. package/src/members/index.ts +51 -15
  111. package/src/members/request.ts +2 -2
  112. package/src/members/util.ts +34 -6
  113. package/src/metrics/constants.ts +2 -0
  114. package/src/multistream/mediaRequestManager.ts +7 -7
  115. package/src/multistream/remoteMedia.ts +34 -4
  116. package/src/multistream/remoteMediaGroup.ts +37 -2
  117. package/src/multistream/sendSlotManager.ts +34 -2
  118. package/src/reachability/index.ts +8 -16
  119. package/test/unit/spec/controls-options-manager/util.js +58 -0
  120. package/test/unit/spec/locus-info/controlsUtils.js +52 -0
  121. package/test/unit/spec/locus-info/index.js +270 -97
  122. package/test/unit/spec/locus-info/parser.js +3 -2
  123. package/test/unit/spec/media/index.ts +107 -0
  124. package/test/unit/spec/media/properties.ts +137 -0
  125. package/test/unit/spec/meeting/brbState.ts +23 -4
  126. package/test/unit/spec/meeting/in-meeting-actions.ts +12 -0
  127. package/test/unit/spec/meeting/index.js +1194 -97
  128. package/test/unit/spec/meeting/muteState.js +32 -6
  129. package/test/unit/spec/meeting/request.js +92 -0
  130. package/test/unit/spec/meeting/utils.js +167 -17
  131. package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
  132. package/test/unit/spec/meetings/index.js +12 -1
  133. package/test/unit/spec/members/collection.js +120 -0
  134. package/test/unit/spec/members/index.js +140 -12
  135. package/test/unit/spec/members/request.js +57 -2
  136. package/test/unit/spec/members/utils.js +139 -17
  137. package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
  138. package/test/unit/spec/multistream/remoteMedia.ts +66 -2
  139. package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
  140. package/test/unit/spec/reachability/index.ts +160 -9
  141. package/dist/annotation/annotation.types.d.ts +0 -42
  142. package/dist/annotation/constants.d.ts +0 -31
  143. package/dist/annotation/index.d.ts +0 -117
  144. package/dist/breakouts/breakout.d.ts +0 -8
  145. package/dist/breakouts/collection.d.ts +0 -5
  146. package/dist/breakouts/edit-lock-error.d.ts +0 -15
  147. package/dist/breakouts/events.d.ts +0 -8
  148. package/dist/breakouts/index.d.ts +0 -5
  149. package/dist/breakouts/request.d.ts +0 -22
  150. package/dist/breakouts/utils.d.ts +0 -15
  151. package/dist/common/browser-detection.d.ts +0 -9
  152. package/dist/common/collection.d.ts +0 -48
  153. package/dist/common/config.d.ts +0 -2
  154. package/dist/common/errors/captcha-error.d.ts +0 -15
  155. package/dist/common/errors/intent-to-join.d.ts +0 -16
  156. package/dist/common/errors/join-meeting.d.ts +0 -17
  157. package/dist/common/errors/media.d.ts +0 -15
  158. package/dist/common/errors/no-meeting-info.d.ts +0 -14
  159. package/dist/common/errors/parameter.d.ts +0 -15
  160. package/dist/common/errors/password-error.d.ts +0 -15
  161. package/dist/common/errors/permission.d.ts +0 -14
  162. package/dist/common/errors/reclaim-host-role-error.d.ts +0 -60
  163. package/dist/common/errors/reclaim-host-role-error.js +0 -158
  164. package/dist/common/errors/reclaim-host-role-error.js.map +0 -1
  165. package/dist/common/errors/reclaim-host-role-errors.d.ts +0 -60
  166. package/dist/common/errors/reconnection-in-progress.d.ts +0 -9
  167. package/dist/common/errors/reconnection-in-progress.js +0 -35
  168. package/dist/common/errors/reconnection-in-progress.js.map +0 -1
  169. package/dist/common/errors/reconnection.d.ts +0 -15
  170. package/dist/common/errors/stats.d.ts +0 -15
  171. package/dist/common/errors/webex-errors.d.ts +0 -81
  172. package/dist/common/errors/webex-meetings-error.d.ts +0 -20
  173. package/dist/common/events/events-scope.d.ts +0 -17
  174. package/dist/common/events/events.d.ts +0 -12
  175. package/dist/common/events/trigger-proxy.d.ts +0 -2
  176. package/dist/common/events/util.d.ts +0 -2
  177. package/dist/common/logs/logger-config.d.ts +0 -2
  178. package/dist/common/logs/logger-proxy.d.ts +0 -2
  179. package/dist/common/logs/request.d.ts +0 -34
  180. package/dist/common/queue.d.ts +0 -32
  181. package/dist/config.d.ts +0 -73
  182. package/dist/constants.d.ts +0 -952
  183. package/dist/controls-options-manager/constants.d.ts +0 -4
  184. package/dist/controls-options-manager/enums.d.ts +0 -5
  185. package/dist/controls-options-manager/index.d.ts +0 -120
  186. package/dist/controls-options-manager/types.d.ts +0 -43
  187. package/dist/controls-options-manager/util.d.ts +0 -7
  188. package/dist/index.d.ts +0 -4
  189. package/dist/interceptors/index.d.ts +0 -2
  190. package/dist/interceptors/locusRetry.d.ts +0 -27
  191. package/dist/interpretation/collection.d.ts +0 -5
  192. package/dist/interpretation/index.d.ts +0 -5
  193. package/dist/interpretation/siLanguage.d.ts +0 -5
  194. package/dist/locus-info/controlsUtils.d.ts +0 -2
  195. package/dist/locus-info/embeddedAppsUtils.d.ts +0 -2
  196. package/dist/locus-info/fullState.d.ts +0 -2
  197. package/dist/locus-info/hostUtils.d.ts +0 -2
  198. package/dist/locus-info/index.d.ts +0 -269
  199. package/dist/locus-info/infoUtils.d.ts +0 -2
  200. package/dist/locus-info/mediaSharesUtils.d.ts +0 -2
  201. package/dist/locus-info/parser.d.ts +0 -212
  202. package/dist/locus-info/selfUtils.d.ts +0 -2
  203. package/dist/media/index.d.ts +0 -32
  204. package/dist/media/properties.d.ts +0 -108
  205. package/dist/media/util.d.ts +0 -2
  206. package/dist/mediaQualityMetrics/config.d.ts +0 -233
  207. package/dist/mediaQualityMetrics/config.js +0 -513
  208. package/dist/mediaQualityMetrics/config.js.map +0 -1
  209. package/dist/meeting/effectsState.d.ts +0 -42
  210. package/dist/meeting/effectsState.js +0 -260
  211. package/dist/meeting/effectsState.js.map +0 -1
  212. package/dist/meeting/in-meeting-actions.d.ts +0 -79
  213. package/dist/meeting/index.d.ts +0 -1622
  214. package/dist/meeting/locusMediaRequest.d.ts +0 -74
  215. package/dist/meeting/muteState.d.ts +0 -116
  216. package/dist/meeting/request.d.ts +0 -257
  217. package/dist/meeting/request.type.d.ts +0 -11
  218. package/dist/meeting/state.d.ts +0 -9
  219. package/dist/meeting/util.d.ts +0 -2
  220. package/dist/meeting/voicea-meeting.d.ts +0 -16
  221. package/dist/meeting-info/collection.d.ts +0 -20
  222. package/dist/meeting-info/index.d.ts +0 -57
  223. package/dist/meeting-info/meeting-info-v2.d.ts +0 -93
  224. package/dist/meeting-info/request.d.ts +0 -22
  225. package/dist/meeting-info/util.d.ts +0 -2
  226. package/dist/meeting-info/utilv2.d.ts +0 -2
  227. package/dist/meetings/collection.d.ts +0 -23
  228. package/dist/meetings/index.d.ts +0 -296
  229. package/dist/meetings/meetings.types.d.ts +0 -4
  230. package/dist/meetings/request.d.ts +0 -27
  231. package/dist/meetings/util.d.ts +0 -18
  232. package/dist/member/index.d.ts +0 -148
  233. package/dist/member/member.types.d.ts +0 -11
  234. package/dist/member/member.types.js +0 -18
  235. package/dist/member/member.types.js.map +0 -1
  236. package/dist/member/types.d.ts +0 -32
  237. package/dist/member/util.d.ts +0 -2
  238. package/dist/members/collection.d.ts +0 -24
  239. package/dist/members/index.d.ts +0 -308
  240. package/dist/members/request.d.ts +0 -58
  241. package/dist/members/types.d.ts +0 -25
  242. package/dist/members/util.d.ts +0 -2
  243. package/dist/metrics/config.d.ts +0 -169
  244. package/dist/metrics/config.js +0 -289
  245. package/dist/metrics/config.js.map +0 -1
  246. package/dist/metrics/constants.d.ts +0 -59
  247. package/dist/metrics/index.d.ts +0 -152
  248. package/dist/multistream/mediaRequestManager.d.ts +0 -119
  249. package/dist/multistream/receiveSlot.d.ts +0 -68
  250. package/dist/multistream/receiveSlotManager.d.ts +0 -56
  251. package/dist/multistream/remoteMedia.d.ts +0 -72
  252. package/dist/multistream/remoteMediaGroup.d.ts +0 -49
  253. package/dist/multistream/remoteMediaManager.d.ts +0 -300
  254. package/dist/multistream/sendSlotManager.d.ts +0 -69
  255. package/dist/networkQualityMonitor/index.d.ts +0 -70
  256. package/dist/networkQualityMonitor/index.js +0 -226
  257. package/dist/networkQualityMonitor/index.js.map +0 -1
  258. package/dist/peer-connection-manager/index.d.ts +0 -6
  259. package/dist/peer-connection-manager/index.js +0 -671
  260. package/dist/peer-connection-manager/index.js.map +0 -1
  261. package/dist/peer-connection-manager/util.d.ts +0 -6
  262. package/dist/peer-connection-manager/util.js +0 -110
  263. package/dist/peer-connection-manager/util.js.map +0 -1
  264. package/dist/personal-meeting-room/index.d.ts +0 -47
  265. package/dist/personal-meeting-room/request.d.ts +0 -14
  266. package/dist/personal-meeting-room/util.d.ts +0 -2
  267. package/dist/reachability/clusterReachability.d.ts +0 -109
  268. package/dist/reachability/index.d.ts +0 -139
  269. package/dist/reachability/request.d.ts +0 -35
  270. package/dist/reachability/util.d.ts +0 -8
  271. package/dist/reactions/constants.d.ts +0 -3
  272. package/dist/reactions/reactions.d.ts +0 -4
  273. package/dist/reactions/reactions.type.d.ts +0 -32
  274. package/dist/reconnection-manager/index.d.ts +0 -112
  275. package/dist/recording-controller/enums.d.ts +0 -7
  276. package/dist/recording-controller/index.d.ts +0 -193
  277. package/dist/recording-controller/util.d.ts +0 -13
  278. package/dist/roap/collection.d.ts +0 -10
  279. package/dist/roap/collection.js +0 -63
  280. package/dist/roap/collection.js.map +0 -1
  281. package/dist/roap/handler.d.ts +0 -47
  282. package/dist/roap/handler.js +0 -279
  283. package/dist/roap/handler.js.map +0 -1
  284. package/dist/roap/index.d.ts +0 -116
  285. package/dist/roap/request.d.ts +0 -35
  286. package/dist/roap/state.d.ts +0 -9
  287. package/dist/roap/state.js +0 -127
  288. package/dist/roap/state.js.map +0 -1
  289. package/dist/roap/turnDiscovery.d.ts +0 -81
  290. package/dist/roap/util.d.ts +0 -2
  291. package/dist/roap/util.js +0 -76
  292. package/dist/roap/util.js.map +0 -1
  293. package/dist/rtcMetrics/constants.d.ts +0 -4
  294. package/dist/rtcMetrics/constants.js.map +0 -1
  295. package/dist/rtcMetrics/index.d.ts +0 -61
  296. package/dist/rtcMetrics/index.js +0 -197
  297. package/dist/rtcMetrics/index.js.map +0 -1
  298. package/dist/statsAnalyzer/global.d.ts +0 -118
  299. package/dist/statsAnalyzer/global.js +0 -127
  300. package/dist/statsAnalyzer/global.js.map +0 -1
  301. package/dist/statsAnalyzer/index.d.ts +0 -193
  302. package/dist/statsAnalyzer/index.js +0 -1019
  303. package/dist/statsAnalyzer/index.js.map +0 -1
  304. package/dist/statsAnalyzer/mqaUtil.d.ts +0 -22
  305. package/dist/statsAnalyzer/mqaUtil.js +0 -181
  306. package/dist/statsAnalyzer/mqaUtil.js.map +0 -1
  307. package/dist/transcription/index.d.ts +0 -64
  308. package/dist/types/common/errors/reconnection-in-progress.d.ts +0 -9
  309. package/dist/types/mediaQualityMetrics/config.d.ts +0 -241
  310. package/dist/types/networkQualityMonitor/index.d.ts +0 -70
  311. package/dist/types/rtcMetrics/constants.d.ts +0 -4
  312. package/dist/types/rtcMetrics/index.d.ts +0 -71
  313. package/dist/types/statsAnalyzer/global.d.ts +0 -36
  314. package/dist/types/statsAnalyzer/index.d.ts +0 -217
  315. package/dist/types/statsAnalyzer/mqaUtil.d.ts +0 -48
  316. package/dist/webinar/collection.d.ts +0 -16
  317. package/dist/webinar/index.d.ts +0 -5
@@ -28,6 +28,8 @@ import {
28
28
  StatsAnalyzerEventNames,
29
29
  NetworkQualityEventNames,
30
30
  NetworkQualityMonitor,
31
+ StatsMonitor,
32
+ StatsMonitorEventNames,
31
33
  } from '@webex/internal-media-core';
32
34
 
33
35
  import {
@@ -121,6 +123,7 @@ import {
121
123
  WEBINAR_ERROR_REGISTRATION_ID,
122
124
  JOIN_BEFORE_HOST,
123
125
  REGISTRATION_ID_STATUS,
126
+ STAGE_MANAGER_TYPE,
124
127
  } from '../constants';
125
128
  import BEHAVIORAL_METRICS from '../metrics/constants';
126
129
  import ParameterError from '../common/errors/parameter';
@@ -164,6 +167,8 @@ import {BrbState, createBrbState} from './brbState';
164
167
  import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error';
165
168
  import JoinForbiddenError from '../common/errors/join-forbidden-error';
166
169
  import {ReachabilityMetrics} from '../reachability/reachability.types';
170
+ import {SetStageOptions, SetStageVideoLayout, UnsetStageVideoLayout} from './request.type';
171
+ import {Invitee} from './type';
167
172
 
168
173
  // default callback so we don't call an undefined function, but in practice it should never be used
169
174
  const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
@@ -231,6 +236,14 @@ export type AddMediaOptions = {
231
236
  remoteMediaManagerConfig?: RemoteMediaManagerConfiguration; // applies only to multistream meetings
232
237
  bundlePolicy?: BundlePolicy; // applies only to multistream meetings
233
238
  allowMediaInLobby?: boolean; // allows adding media when in the lobby
239
+ additionalMediaOptions?: AdditionalMediaOptions; // allows adding additional options like send/receive audio/video
240
+ };
241
+
242
+ export type AdditionalMediaOptions = {
243
+ sendVideo?: boolean; // if not specified, default value of videoEnabled is used
244
+ receiveVideo?: boolean; // if not specified, default value of videoEnabled is used
245
+ sendAudio?: boolean; // if not specified, default value of audioEnabled true is used
246
+ receiveAudio?: boolean; // if not specified, default value of audioEnabled true is used
234
247
  };
235
248
 
236
249
  export type CallStateForMetrics = {
@@ -240,6 +253,7 @@ export type CallStateForMetrics = {
240
253
  loginType?: string;
241
254
  userNameInput?: string;
242
255
  emailInput?: string;
256
+ pstnCorrelationId?: string;
243
257
  };
244
258
 
245
259
  export const MEDIA_UPDATE_TYPE = {
@@ -257,14 +271,16 @@ export enum ScreenShareFloorStatus {
257
271
  type FetchMeetingInfoParams = {
258
272
  password?: string;
259
273
  registrationId?: string;
274
+ classificationId?: string;
260
275
  captchaCode?: string;
261
276
  extraParams?: Record<string, any>;
262
277
  sendCAevents?: boolean;
263
278
  };
264
279
 
265
280
  type MediaReachabilityMetrics = ReachabilityMetrics & {
266
- isSubnetReachable: boolean;
267
- selectedCluster: string | null;
281
+ subnet_reachable: boolean;
282
+ selected_cluster: string | null;
283
+ selected_subnet: string | null;
268
284
  };
269
285
 
270
286
  /**
@@ -620,6 +636,7 @@ export default class Meeting extends StatelessWebexPlugin {
620
636
  shareStatus: string;
621
637
  screenShareFloorState: ScreenShareFloorStatus;
622
638
  statsAnalyzer: StatsAnalyzer;
639
+ statsMonitor: StatsMonitor;
623
640
  transcription: Transcription;
624
641
  updateMediaConnections: (mediaConnections: any[]) => void;
625
642
  userDisplayHints: any;
@@ -732,10 +749,11 @@ export default class Meeting extends StatelessWebexPlugin {
732
749
  /**
733
750
  * @param {Object} attrs
734
751
  * @param {Object} options
752
+ * @param {Function} callback - if provided, it will be called with the newly created meeting object as soon as the meeting.id is set
735
753
  * @constructor
736
754
  * @memberof Meeting
737
755
  */
738
- constructor(attrs: any, options: object) {
756
+ constructor(attrs: any, options: object, callback: (meeting: Meeting) => void) {
739
757
  super({}, options);
740
758
  /**
741
759
  * @instance
@@ -761,6 +779,11 @@ export default class Meeting extends StatelessWebexPlugin {
761
779
  * @memberof Meeting
762
780
  */
763
781
  this.id = uuid.v4();
782
+
783
+ if (callback) {
784
+ callback(this);
785
+ }
786
+
764
787
  /**
765
788
  * Call state used for metrics
766
789
  * @instance
@@ -1267,6 +1290,13 @@ export default class Meeting extends StatelessWebexPlugin {
1267
1290
  * @memberof Meeting
1268
1291
  */
1269
1292
  this.networkQualityMonitor = null;
1293
+ /**
1294
+ * @instance
1295
+ * @type {StatsMonitor}
1296
+ * @private
1297
+ * @memberof Meeting
1298
+ */
1299
+ this.statsMonitor = null;
1270
1300
  /**
1271
1301
  * Indicates network status of the webrtc media connection
1272
1302
  * @instance
@@ -1344,7 +1374,7 @@ export default class Meeting extends StatelessWebexPlugin {
1344
1374
  captions: [],
1345
1375
  isListening: false,
1346
1376
  commandText: '',
1347
- languageOptions: {},
1377
+ languageOptions: {currentSpokenLanguage: 'en'},
1348
1378
  showCaptionBox: false,
1349
1379
  transcribingRequestStatus: 'INACTIVE',
1350
1380
  isCaptioning: false,
@@ -1665,6 +1695,22 @@ export default class Meeting extends StatelessWebexPlugin {
1665
1695
  this.callStateForMetrics.correlationId = correlationId;
1666
1696
  }
1667
1697
 
1698
+ /**
1699
+ * Getter - Returns callStateForMetrics.pstnCorrelationId
1700
+ * @returns {string | undefined}
1701
+ */
1702
+ get pstnCorrelationId(): string | undefined {
1703
+ return this.callStateForMetrics.pstnCorrelationId;
1704
+ }
1705
+
1706
+ /**
1707
+ * Setter - sets callStateForMetrics.pstnCorrelationId
1708
+ * @param {string | undefined} correlationId
1709
+ */
1710
+ set pstnCorrelationId(correlationId: string | undefined) {
1711
+ this.callStateForMetrics.pstnCorrelationId = correlationId;
1712
+ }
1713
+
1668
1714
  /**
1669
1715
  * Getter - Returns callStateForMetrics.userNameInput
1670
1716
  * @returns {string}
@@ -1867,6 +1913,7 @@ export default class Meeting extends StatelessWebexPlugin {
1867
1913
  extraParams = {},
1868
1914
  sendCAevents = false,
1869
1915
  registrationId = null,
1916
+ classificationId = null,
1870
1917
  }): Promise<void> {
1871
1918
  try {
1872
1919
  const captchaInfo = captchaCode
@@ -1883,7 +1930,9 @@ export default class Meeting extends StatelessWebexPlugin {
1883
1930
  this.locusId,
1884
1931
  extraParams,
1885
1932
  {meetingId: this.id, sendCAevents},
1886
- registrationId
1933
+ registrationId,
1934
+ null,
1935
+ classificationId
1887
1936
  );
1888
1937
 
1889
1938
  this.parseMeetingInfo(info?.body, this.destination, info?.errors);
@@ -2753,6 +2802,29 @@ export default class Meeting extends StatelessWebexPlugin {
2753
2802
  }
2754
2803
  );
2755
2804
 
2805
+ this.locusInfo.on(
2806
+ LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
2807
+ ({spokenLanguage}) => {
2808
+ if (spokenLanguage) {
2809
+ if (this.transcription?.languageOptions) {
2810
+ this.transcription.languageOptions.currentSpokenLanguage = spokenLanguage;
2811
+ }
2812
+ // @ts-ignore
2813
+ this.webex.internal.voicea.onSpokenLanguageUpdate(spokenLanguage, this.id);
2814
+
2815
+ Trigger.trigger(
2816
+ this,
2817
+ {
2818
+ file: 'meeting/index',
2819
+ function: 'setupLocusControlsListener',
2820
+ },
2821
+ EVENT_TRIGGERS.MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
2822
+ {spokenLanguage, meetingId: this.id}
2823
+ );
2824
+ }
2825
+ }
2826
+ );
2827
+
2756
2828
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_MANUAL_CAPTION_UPDATED, ({enable}) => {
2757
2829
  Trigger.trigger(
2758
2830
  this,
@@ -2921,6 +2993,15 @@ export default class Meeting extends StatelessWebexPlugin {
2921
2993
  {state}
2922
2994
  );
2923
2995
  });
2996
+
2997
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_POLLING_QA_CHANGED, ({state}) => {
2998
+ Trigger.trigger(
2999
+ this,
3000
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
3001
+ EVENT_TRIGGERS.MEETING_CONTROLS_POLLING_QA_UPDATED,
3002
+ {state}
3003
+ );
3004
+ });
2924
3005
  }
2925
3006
 
2926
3007
  /**
@@ -3015,12 +3096,16 @@ export default class Meeting extends StatelessWebexPlugin {
3015
3096
  // There is no concept of local/remote share for whiteboard
3016
3097
  // It does not matter who requested to share the whiteboard, everyone gets the same view
3017
3098
  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;
3099
+ if (this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee) {
3100
+ // WHITEBOARD - sharing whiteboard
3101
+ // Webinar attendee should receive whiteboard as remote share
3102
+ newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
3103
+ } else if (this.guest) {
3104
+ // If user is a guest to a meeting, they should receive whiteboard as remote share
3105
+ newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
3106
+ } else {
3107
+ newShareStatus = SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
3108
+ }
3024
3109
  }
3025
3110
  // or if content share is either released or null and whiteboard share is either released or null, no one is sharing
3026
3111
  else if (
@@ -3078,6 +3163,23 @@ export default class Meeting extends StatelessWebexPlugin {
3078
3163
  },
3079
3164
  EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD
3080
3165
  );
3166
+ // @ts-ignore
3167
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
3168
+ key: 'internal.client.share.stopped',
3169
+ });
3170
+ // @ts-ignore
3171
+ this.webex.internal.newMetrics.submitClientEvent({
3172
+ name: 'client.share.stopped',
3173
+ payload: {
3174
+ mediaType: 'whiteboard',
3175
+ shareDuration:
3176
+ // @ts-ignore
3177
+ this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
3178
+ },
3179
+ options: {
3180
+ meetingId: this.id,
3181
+ },
3182
+ });
3081
3183
  break;
3082
3184
 
3083
3185
  case SHARE_STATUS.NO_SHARE:
@@ -3096,6 +3198,14 @@ export default class Meeting extends StatelessWebexPlugin {
3096
3198
  this.shareCAEventSentStatus.receiveStart = false;
3097
3199
  this.shareCAEventSentStatus.receiveStop = false;
3098
3200
 
3201
+ let finalBeneficiaryId = contentShare.beneficiaryId;
3202
+ // In case of attendee in webinar, the whiteboard is shared by other participants
3203
+ if (this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee) {
3204
+ if (!finalBeneficiaryId && whiteboardShare.beneficiaryId) {
3205
+ finalBeneficiaryId = whiteboardShare.beneficiaryId;
3206
+ }
3207
+ }
3208
+
3099
3209
  Trigger.trigger(
3100
3210
  this,
3101
3211
  {
@@ -3104,7 +3214,7 @@ export default class Meeting extends StatelessWebexPlugin {
3104
3214
  },
3105
3215
  EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
3106
3216
  {
3107
- memberId: contentShare.beneficiaryId,
3217
+ memberId: finalBeneficiaryId,
3108
3218
  url: contentShare.url,
3109
3219
  shareInstanceId: this.remoteShareInstanceId,
3110
3220
  annotationInfo: contentShare.annotation,
@@ -3786,49 +3896,44 @@ export default class Meeting extends StatelessWebexPlugin {
3786
3896
 
3787
3897
  /**
3788
3898
  * Invite a guest to the call that isn't normally part of this call
3789
- * @param {Object} invitee
3899
+ * @param {Invitee} invitee
3790
3900
  * @param {String} invitee.emailAddress
3791
3901
  * @param {String} invitee.email
3792
3902
  * @param {String} invitee.phoneNumber
3793
3903
  * @param {Boolean} [alertIfActive]
3904
+ * @param {Boolean} [invitee.skipEmailValidation]
3905
+ * @param {Boolean} [invitee.isInternalNumber]
3794
3906
  * @returns {Promise} see #members.addMember
3795
3907
  * @public
3796
3908
  * @memberof Meeting
3797
3909
  */
3798
- public invite(
3799
- invitee: {
3800
- emailAddress: string;
3801
- email: string;
3802
- phoneNumber: string;
3803
- roles: Array<string>;
3804
- },
3805
- alertIfActive = true
3806
- ) {
3910
+ public invite(invitee: Invitee, alertIfActive = true) {
3807
3911
  return this.members.addMember(invitee, alertIfActive);
3808
3912
  }
3809
3913
 
3810
3914
  /**
3811
3915
  * Cancel an outgoing phone call invitation made during a meeting
3812
- * @param {Object} invitee
3916
+ * @param {Invitee} invitee
3813
3917
  * @param {String} invitee.phoneNumber
3814
3918
  * @returns {Promise} see #members.cancelPhoneInvite
3815
3919
  * @public
3816
3920
  * @memberof Meeting
3817
3921
  */
3818
- public cancelPhoneInvite(invitee: {phoneNumber: string}) {
3922
+ public cancelPhoneInvite(invitee: Invitee) {
3819
3923
  return this.members.cancelPhoneInvite(invitee);
3820
3924
  }
3821
3925
 
3822
3926
  /**
3823
- * Cancel an SIP call invitation made during a meeting
3824
- * @param {Object} invitee
3927
+ * Cancel an SIP/phone call invitation made during a meeting
3928
+ * @param {Invitee} invitee
3825
3929
  * @param {String} invitee.memberId
3826
- * @returns {Promise} see #members.cancelSIPInvite
3930
+ * @param {Boolean} [invitee.isInternalNumber] - When cancel phone invitation, if the number is internal
3931
+ * @returns {Promise} see #members.cancelInviteByMemberId
3827
3932
  * @public
3828
3933
  * @memberof Meeting
3829
3934
  */
3830
- public cancelSIPInvite(invitee: {memberId: string}) {
3831
- return this.members.cancelSIPInvite(invitee);
3935
+ public cancelInviteByMemberId(invitee: Invitee) {
3936
+ return this.members.cancelInviteByMemberId(invitee);
3832
3937
  }
3833
3938
 
3834
3939
  /**
@@ -3886,13 +3991,16 @@ export default class Meeting extends StatelessWebexPlugin {
3886
3991
  return Promise.reject(error);
3887
3992
  }
3888
3993
 
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
- });
3994
+ return this.brbState
3995
+ .enable(enabled, this.sendSlotManager)
3996
+ .then(() => {
3997
+ if (this.audio && enabled) {
3998
+ // locus mutes the participant with brb enabled request,
3999
+ // so we need to explicitly update remote mute for correct logic flow
4000
+ this.audio.handleServerRemoteMuteUpdate(this, enabled);
4001
+ }
4002
+ })
4003
+ .catch((error) => Promise.reject(error));
3896
4004
  }
3897
4005
 
3898
4006
  /**
@@ -4123,8 +4231,14 @@ export default class Meeting extends StatelessWebexPlugin {
4123
4231
  isClosedCaptionActive: MeetingUtil.isClosedCaptionActive(this.userDisplayHints),
4124
4232
  canStartManualCaption: MeetingUtil.canStartManualCaption(this.userDisplayHints),
4125
4233
  canStopManualCaption: MeetingUtil.canStopManualCaption(this.userDisplayHints),
4234
+ isLocalRecordingStarted: MeetingUtil.isLocalRecordingStarted(this.userDisplayHints),
4235
+ isLocalRecordingStopped: MeetingUtil.isLocalRecordingStopped(this.userDisplayHints),
4236
+ isLocalRecordingPaused: MeetingUtil.isLocalRecordingPaused(this.userDisplayHints),
4126
4237
  isManualCaptionActive: MeetingUtil.isManualCaptionActive(this.userDisplayHints),
4127
4238
  isSaveTranscriptsEnabled: MeetingUtil.isSaveTranscriptsEnabled(this.userDisplayHints),
4239
+ isSpokenLanguageAutoDetectionEnabled: MeetingUtil.isSpokenLanguageAutoDetectionEnabled(
4240
+ this.userDisplayHints
4241
+ ),
4128
4242
  isWebexAssistantActive: MeetingUtil.isWebexAssistantActive(this.userDisplayHints),
4129
4243
  canViewCaptionPanel: MeetingUtil.canViewCaptionPanel(this.userDisplayHints),
4130
4244
  isRealTimeTranslationEnabled: MeetingUtil.isRealTimeTranslationEnabled(
@@ -4359,6 +4473,14 @@ export default class Meeting extends StatelessWebexPlugin {
4359
4473
  requiredHints: [DISPLAY_HINTS.DISABLE_RDC_MEETING_OPTION],
4360
4474
  displayHints: this.userDisplayHints,
4361
4475
  }),
4476
+ canEnablePollingQA: ControlsOptionsUtil.hasHints({
4477
+ requiredHints: [DISPLAY_HINTS.ENABLE_ATTENDEE_START_POLLING_QA],
4478
+ displayHints: this.userDisplayHints,
4479
+ }),
4480
+ canDisablePollingQA: ControlsOptionsUtil.hasHints({
4481
+ requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
4482
+ displayHints: this.userDisplayHints,
4483
+ }),
4362
4484
  }) || changed;
4363
4485
  }
4364
4486
  if (changed) {
@@ -4874,11 +4996,6 @@ export default class Meeting extends StatelessWebexPlugin {
4874
4996
 
4875
4997
  // Only send restore event when it was disconnected before and for connected later
4876
4998
  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
4999
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_RESTORED, {
4883
5000
  correlation_id: this.correlationId,
4884
5001
  });
@@ -4889,11 +5006,6 @@ export default class Meeting extends StatelessWebexPlugin {
4889
5006
  // @ts-ignore
4890
5007
  this.webex.internal.mercury.on(OFFLINE, () => {
4891
5008
  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
5009
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_FAILURE, {
4898
5010
  correlation_id: this.correlationId,
4899
5011
  });
@@ -5882,15 +5994,6 @@ export default class Meeting extends StatelessWebexPlugin {
5882
5994
  this.meetingFiniteStateMachine.fail(error);
5883
5995
  LoggerProxy.logger.error('Meeting:index#join --> Failed', error);
5884
5996
 
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
5997
  // TODO: change this to error codes and pre defined dictionary
5895
5998
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_FAILURE, {
5896
5999
  correlation_id: this.correlationId,
@@ -6040,8 +6143,9 @@ export default class Meeting extends StatelessWebexPlugin {
6040
6143
  */
6041
6144
  private dialInPstn() {
6042
6145
  if (this.isPhoneProvisioned(this.dialInDeviceStatus)) return Promise.resolve(); // prevent multiple dial in devices from being provisioned
6146
+ this.pstnCorrelationId = uuid.v4();
6043
6147
 
6044
- const {correlationId, locusUrl} = this;
6148
+ const {pstnCorrelationId, locusUrl} = this;
6045
6149
 
6046
6150
  if (!this.dialInUrl) this.dialInUrl = `dialin:///${uuid.v4()}`;
6047
6151
 
@@ -6049,7 +6153,7 @@ export default class Meeting extends StatelessWebexPlugin {
6049
6153
  this.meetingRequest
6050
6154
  // @ts-ignore
6051
6155
  .dialIn({
6052
- correlationId,
6156
+ correlationId: pstnCorrelationId,
6053
6157
  dialInUrl: this.dialInUrl,
6054
6158
  locusUrl,
6055
6159
  clientUrl: this.deviceUrl,
@@ -6058,12 +6162,17 @@ export default class Meeting extends StatelessWebexPlugin {
6058
6162
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
6059
6163
  correlation_id: this.correlationId,
6060
6164
  dial_in_url: this.dialInUrl,
6165
+ dial_in_correlation_id: pstnCorrelationId,
6061
6166
  locus_id: locusUrl.split('/').pop(),
6062
6167
  client_url: this.deviceUrl,
6063
6168
  reason: error.error?.message,
6064
6169
  stack: error.stack,
6065
6170
  });
6066
6171
 
6172
+ if (this.pstnCorrelationId === pstnCorrelationId) {
6173
+ this.pstnCorrelationId = undefined;
6174
+ }
6175
+
6067
6176
  return Promise.reject(error);
6068
6177
  })
6069
6178
  );
@@ -6078,8 +6187,9 @@ export default class Meeting extends StatelessWebexPlugin {
6078
6187
  */
6079
6188
  private dialOutPstn(phoneNumber: string) {
6080
6189
  if (this.isPhoneProvisioned(this.dialOutDeviceStatus)) return Promise.resolve(); // prevent multiple dial out devices from being provisioned
6190
+ this.pstnCorrelationId = uuid.v4();
6081
6191
 
6082
- const {correlationId, locusUrl} = this;
6192
+ const {locusUrl, pstnCorrelationId} = this;
6083
6193
 
6084
6194
  if (!this.dialOutUrl) this.dialOutUrl = `dialout:///${uuid.v4()}`;
6085
6195
 
@@ -6087,7 +6197,7 @@ export default class Meeting extends StatelessWebexPlugin {
6087
6197
  this.meetingRequest
6088
6198
  // @ts-ignore
6089
6199
  .dialOut({
6090
- correlationId,
6200
+ correlationId: pstnCorrelationId,
6091
6201
  dialOutUrl: this.dialOutUrl,
6092
6202
  phoneNumber,
6093
6203
  locusUrl,
@@ -6097,12 +6207,17 @@ export default class Meeting extends StatelessWebexPlugin {
6097
6207
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
6098
6208
  correlation_id: this.correlationId,
6099
6209
  dial_out_url: this.dialOutUrl,
6210
+ dial_out_correlation_id: pstnCorrelationId,
6100
6211
  locus_id: locusUrl.split('/').pop(),
6101
6212
  client_url: this.deviceUrl,
6102
6213
  reason: error.error?.message,
6103
6214
  stack: error.stack,
6104
6215
  });
6105
6216
 
6217
+ if (this.pstnCorrelationId === pstnCorrelationId) {
6218
+ this.pstnCorrelationId = undefined;
6219
+ }
6220
+
6106
6221
  return Promise.reject(error);
6107
6222
  })
6108
6223
  );
@@ -6116,6 +6231,8 @@ export default class Meeting extends StatelessWebexPlugin {
6116
6231
  * @returns {Promise}
6117
6232
  */
6118
6233
  public disconnectPhoneAudio() {
6234
+ const correlationToClear = this.pstnCorrelationId;
6235
+
6119
6236
  return Promise.all([
6120
6237
  this.isPhoneProvisioned(this.dialInDeviceStatus)
6121
6238
  ? MeetingUtil.disconnectPhoneAudio(this, this.dialInUrl)
@@ -6123,7 +6240,11 @@ export default class Meeting extends StatelessWebexPlugin {
6123
6240
  this.isPhoneProvisioned(this.dialOutDeviceStatus)
6124
6241
  ? MeetingUtil.disconnectPhoneAudio(this, this.dialOutUrl)
6125
6242
  : Promise.resolve(),
6126
- ]);
6243
+ ]).then(() => {
6244
+ if (this.pstnCorrelationId === correlationToClear) {
6245
+ this.pstnCorrelationId = undefined;
6246
+ }
6247
+ });
6127
6248
  }
6128
6249
 
6129
6250
  /**
@@ -6700,6 +6821,10 @@ export default class Meeting extends StatelessWebexPlugin {
6700
6821
  // @ts-ignore
6701
6822
  this.webex.internal.newMetrics.submitClientEvent({
6702
6823
  name: 'client.ice.start',
6824
+ payload: {
6825
+ // @ts-ignore
6826
+ labels: MeetingUtil.getCaEventLabelsForIpVersion(this.webex),
6827
+ },
6703
6828
  options: {
6704
6829
  meetingId: this.id,
6705
6830
  },
@@ -6869,10 +6994,10 @@ export default class Meeting extends StatelessWebexPlugin {
6869
6994
  }
6870
6995
  }
6871
6996
 
6872
- // Count members that are in the meeting.
6997
+ // Count members that are in the meeting or in the lobby.
6873
6998
  const {members} = this.getMembers().membersCollection;
6874
6999
  event.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
6875
- (member: Member) => member.isInMeeting
7000
+ (member: Member) => member.isInMeeting || member.isInLobby
6876
7001
  ).length;
6877
7002
 
6878
7003
  // @ts-ignore
@@ -7231,10 +7356,12 @@ export default class Meeting extends StatelessWebexPlugin {
7231
7356
  if (this.config.stats.enableStatsAnalyzer) {
7232
7357
  // @ts-ignore - config coming from registerPlugin
7233
7358
  this.networkQualityMonitor = new NetworkQualityMonitor(this.config.stats);
7359
+ this.statsMonitor = new StatsMonitor();
7234
7360
  this.statsAnalyzer = new StatsAnalyzer({
7235
7361
  // @ts-ignore - config coming from registerPlugin
7236
7362
  config: this.config.stats,
7237
7363
  networkQualityMonitor: this.networkQualityMonitor,
7364
+ statsMonitor: this.statsMonitor,
7238
7365
  isMultistream: this.isMultistream,
7239
7366
  });
7240
7367
  this.shareCAEventSentStatus = {
@@ -7248,6 +7375,33 @@ export default class Meeting extends StatelessWebexPlugin {
7248
7375
  NetworkQualityEventNames.NETWORK_QUALITY,
7249
7376
  this.sendNetworkQualityEvent.bind(this)
7250
7377
  );
7378
+
7379
+ this.statsMonitor.on(StatsMonitorEventNames.INBOUND_AUDIO_ISSUE, (data) => {
7380
+ // Before forwarding any inbound audio issues to the app, make sure that we have at least one other
7381
+ // participant in the meeting with unmuted audio.
7382
+ // We don't check this.mediaProperties.mediaDirection here, because that's already handled in statsAnalyzer,
7383
+ // so we won't get this event if we are not setup to receive any audio
7384
+ const atLeastOneUnmutedOtherMember = Object.values(
7385
+ this.members.membersCollection.getAll()
7386
+ ).find((member) => {
7387
+ return !member.isSelf && !member.isPairedWithSelf && !member.isAudioMuted;
7388
+ });
7389
+
7390
+ if (atLeastOneUnmutedOtherMember) {
7391
+ this.mediaProperties.sendMediaIssueMetric(
7392
+ 'inbound_audio',
7393
+ data.issueSubType,
7394
+ this.correlationId
7395
+ );
7396
+
7397
+ Trigger.trigger(
7398
+ this,
7399
+ {file: 'meeting/index', function: 'createStatsAnalyzer'},
7400
+ EVENT_TRIGGERS.MEDIA_INBOUND_AUDIO_ISSUE_DETECTED,
7401
+ data
7402
+ );
7403
+ }
7404
+ });
7251
7405
  }
7252
7406
  }
7253
7407
 
@@ -7546,6 +7700,10 @@ export default class Meeting extends StatelessWebexPlugin {
7546
7700
  }
7547
7701
 
7548
7702
  this.statsAnalyzer = null;
7703
+ this.networkQualityMonitor?.removeAllListeners();
7704
+ this.networkQualityMonitor = null;
7705
+ this.statsMonitor?.removeAllListeners();
7706
+ this.statsMonitor = null;
7549
7707
 
7550
7708
  // when media fails, we want to upload a webrtc dump to see whats going on
7551
7709
  // this function is async, but returns once the stats have been gathered
@@ -7569,6 +7727,10 @@ export default class Meeting extends StatelessWebexPlugin {
7569
7727
  await this.statsAnalyzer.stopAnalyzer();
7570
7728
  }
7571
7729
  this.statsAnalyzer = null;
7730
+ this.networkQualityMonitor?.removeAllListeners();
7731
+ this.networkQualityMonitor = null;
7732
+ this.statsMonitor?.removeAllListeners();
7733
+ this.statsMonitor = null;
7572
7734
 
7573
7735
  this.isMultistream = false;
7574
7736
 
@@ -7723,10 +7885,26 @@ export default class Meeting extends StatelessWebexPlugin {
7723
7885
  shareVideoEnabled = true,
7724
7886
  remoteMediaManagerConfig,
7725
7887
  bundlePolicy = 'max-bundle',
7888
+ additionalMediaOptions = {},
7726
7889
  } = options;
7727
7890
 
7891
+ const {
7892
+ sendVideo: rawSendVideo,
7893
+ receiveVideo: rawReceiveVideo,
7894
+ sendAudio: rawSendAudio,
7895
+ receiveAudio: rawReceiveAudio,
7896
+ } = additionalMediaOptions;
7897
+
7898
+ const sendVideo = videoEnabled && (rawSendVideo ?? true);
7899
+ const receiveVideo = videoEnabled && (rawReceiveVideo ?? true);
7900
+ const sendAudio = audioEnabled && (rawSendAudio ?? true);
7901
+ const receiveAudio = audioEnabled && (rawReceiveAudio ?? true);
7902
+
7728
7903
  this.allowMediaInLobby = options?.allowMediaInLobby;
7729
7904
 
7905
+ // @ts-ignore
7906
+ const ipver = MeetingUtil.getIpVersion(this.webex); // used just for metrics
7907
+
7730
7908
  // If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
7731
7909
  // @ts-ignore - isUserUnadmitted coming from SelfUtil
7732
7910
  if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
@@ -7760,11 +7938,11 @@ export default class Meeting extends StatelessWebexPlugin {
7760
7938
  // when audioEnabled/videoEnabled is true, we set sendAudio/sendVideo to true even before any streams are published
7761
7939
  // to avoid doing an extra SDP exchange when they are published for the first time
7762
7940
  this.mediaProperties.setMediaDirection({
7763
- sendAudio: audioEnabled,
7764
- sendVideo: videoEnabled,
7941
+ sendAudio,
7942
+ sendVideo,
7765
7943
  sendShare: false,
7766
- receiveAudio: audioEnabled,
7767
- receiveVideo: videoEnabled,
7944
+ receiveAudio,
7945
+ receiveVideo,
7768
7946
  receiveShare: shareAudioEnabled || shareVideoEnabled,
7769
7947
  });
7770
7948
 
@@ -7825,6 +8003,7 @@ export default class Meeting extends StatelessWebexPlugin {
7825
8003
  locus_id: this.locusUrl.split('/').pop(),
7826
8004
  connectionType,
7827
8005
  ipVersion,
8006
+ ipver,
7828
8007
  selectedCandidatePairChanges,
7829
8008
  numTransports,
7830
8009
  isMultistream: this.isMultistream,
@@ -7893,6 +8072,7 @@ export default class Meeting extends StatelessWebexPlugin {
7893
8072
  ...reachabilityMetrics,
7894
8073
  ...iceCandidateErrors,
7895
8074
  iceCandidatesCount: this.iceCandidatesCount,
8075
+ ipver,
7896
8076
  });
7897
8077
 
7898
8078
  await this.cleanUpOnAddMediaFailure();
@@ -8332,6 +8512,10 @@ export default class Meeting extends StatelessWebexPlugin {
8332
8512
  }
8333
8513
 
8334
8514
  if (whiteboard) {
8515
+ // @ts-ignore
8516
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
8517
+ key: 'internal.client.share.initiated',
8518
+ });
8335
8519
  // @ts-ignore
8336
8520
  this.webex.internal.newMetrics.submitClientEvent({
8337
8521
  name: 'client.share.initiated',
@@ -8391,11 +8575,17 @@ export default class Meeting extends StatelessWebexPlugin {
8391
8575
  const whiteboard = this.locusInfo.mediaShares.find((element) => element.name === 'whiteboard');
8392
8576
 
8393
8577
  if (whiteboard) {
8578
+ // @ts-ignore
8579
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
8580
+ key: 'internal.client.share.stopped',
8581
+ });
8394
8582
  // @ts-ignore
8395
8583
  this.webex.internal.newMetrics.submitClientEvent({
8396
8584
  name: 'client.share.stopped',
8397
8585
  payload: {
8398
8586
  mediaType: 'whiteboard',
8587
+ // @ts-ignore
8588
+ shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
8399
8589
  },
8400
8590
  options: {
8401
8591
  meetingId: this.id,
@@ -8553,12 +8743,18 @@ export default class Meeting extends StatelessWebexPlugin {
8553
8743
  }
8554
8744
  this.screenShareFloorState = ScreenShareFloorStatus.RELEASED;
8555
8745
  if (content) {
8746
+ // @ts-ignore
8747
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
8748
+ key: 'internal.client.share.stopped',
8749
+ });
8556
8750
  // @ts-ignore
8557
8751
  this.webex.internal.newMetrics.submitClientEvent({
8558
8752
  name: 'client.share.stopped',
8559
8753
  payload: {
8560
8754
  mediaType: 'share',
8561
8755
  shareInstanceId: this.localShareInstanceId,
8756
+ // @ts-ignore
8757
+ shareDuration: this.webex.internal.newMetrics.callDiagnosticLatencies.getShareDuration(),
8562
8758
  },
8563
8759
  options: {meetingId: this.id},
8564
8760
  });
@@ -9535,6 +9731,11 @@ export default class Meeting extends StatelessWebexPlugin {
9535
9731
  this.shareCAEventSentStatus.transmitStart = false;
9536
9732
  this.shareCAEventSentStatus.transmitStop = false;
9537
9733
 
9734
+ // @ts-ignore
9735
+ this.webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp({
9736
+ key: 'internal.client.share.initiated',
9737
+ });
9738
+
9538
9739
  // @ts-ignore
9539
9740
  this.webex.internal.newMetrics.submitClientEvent({
9540
9741
  name: 'client.share.initiated',
@@ -9690,21 +9891,107 @@ export default class Meeting extends StatelessWebexPlugin {
9690
9891
  return total;
9691
9892
  }, 0);
9692
9893
 
9894
+ const selectedSubnetFirstOctet = this.mediaServerIp?.split('.')[0];
9895
+
9693
9896
  let isSubnetReachable = null;
9694
- if (totalSuccessCases > 0) {
9695
- // @ts-ignore
9696
- isSubnetReachable = this.webex.meetings.reachability.isSubnetReachable(this.mediaServerIp);
9897
+ if (totalSuccessCases > 0 && selectedSubnetFirstOctet) {
9898
+ isSubnetReachable =
9899
+ // @ts-ignore
9900
+ this.webex.meetings.reachability.isSubnetReachable(selectedSubnetFirstOctet);
9697
9901
  }
9698
9902
 
9699
- let selectedCluster = null;
9700
- if (this.mediaConnections && this.mediaConnections.length > 0) {
9701
- selectedCluster = this.mediaConnections[0].mediaAgentCluster;
9702
- }
9903
+ const selectedCluster = this.mediaConnections?.[0]?.mediaAgentCluster ?? null;
9703
9904
 
9704
9905
  return {
9705
9906
  ...reachabilityMetrics,
9706
- isSubnetReachable,
9707
- selectedCluster,
9907
+ subnet_reachable: isSubnetReachable,
9908
+ selected_cluster: selectedCluster,
9909
+ selected_subnet: selectedSubnetFirstOctet ? `${selectedSubnetFirstOctet}.X.X.X` : null,
9708
9910
  };
9709
9911
  }
9912
+
9913
+ /**
9914
+ * Set the stage for the meeting
9915
+ *
9916
+ * @param {SetStageOptions} options Options to use when setting the stage
9917
+ * @returns {Promise} The locus request
9918
+ */
9919
+ setStage({
9920
+ activeSpeakerProportion = 0.5,
9921
+ customBackground,
9922
+ customLogo,
9923
+ customNameLabel,
9924
+ importantParticipants,
9925
+ lockAttendeeViewOnStage = false,
9926
+ showActiveSpeaker = false,
9927
+ }: SetStageOptions = {}) {
9928
+ const videoLayout: SetStageVideoLayout = {
9929
+ overrideDefault: true,
9930
+ lockAttendeeViewOnStageOnly: lockAttendeeViewOnStage,
9931
+ stageParameters: {
9932
+ activeSpeakerProportion,
9933
+ showActiveSpeaker: {show: showActiveSpeaker, order: 0},
9934
+ stageManagerType: 0,
9935
+ },
9936
+ };
9937
+
9938
+ if (importantParticipants?.length) {
9939
+ videoLayout.stageParameters.importantParticipants = importantParticipants.map(
9940
+ (importantParticipant, index) => ({...importantParticipant, order: index + 1})
9941
+ );
9942
+ }
9943
+
9944
+ if (customLogo) {
9945
+ if (!videoLayout.customLayouts) {
9946
+ videoLayout.customLayouts = {};
9947
+ }
9948
+ videoLayout.customLayouts.logo = customLogo;
9949
+ // eslint-disable-next-line no-bitwise
9950
+ videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.LOGO;
9951
+ }
9952
+
9953
+ if (customBackground) {
9954
+ if (!videoLayout.customLayouts) {
9955
+ videoLayout.customLayouts = {};
9956
+ }
9957
+ videoLayout.customLayouts.background = customBackground;
9958
+ // eslint-disable-next-line no-bitwise
9959
+ videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.BACKGROUND;
9960
+ }
9961
+
9962
+ if (customNameLabel) {
9963
+ videoLayout.nameLabelStyle = customNameLabel;
9964
+ // eslint-disable-next-line no-bitwise
9965
+ videoLayout.stageParameters.stageManagerType |= STAGE_MANAGER_TYPE.NAME_LABEL;
9966
+ }
9967
+
9968
+ return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
9969
+ }
9970
+
9971
+ /**
9972
+ * Unset the stage for the meeting
9973
+ *
9974
+ * @returns {Promise} The locus request
9975
+ */
9976
+ unsetStage() {
9977
+ const videoLayout: UnsetStageVideoLayout = {overrideDefault: false};
9978
+
9979
+ return this.meetingRequest.synchronizeStage(this.locusUrl, videoLayout);
9980
+ }
9981
+
9982
+ /**
9983
+ * Notifies the host with the given meeting UUID and display names.
9984
+ *
9985
+ * @param {string} meetingUuid - The UUID of the meeting.
9986
+ * @param {string[]} displayName - An array of display names to notify the host with.
9987
+ * @returns {Promise<any>} The result of the notifyHost request.
9988
+ */
9989
+ notifyHost(meetingUuid: string, displayName: string[]) {
9990
+ return this.meetingRequest.notifyHost(
9991
+ this.meetingInfo.siteFullUrl,
9992
+ this.locusId,
9993
+ meetingUuid,
9994
+ displayName
9995
+ );
9996
+ }
9710
9997
  }