@webex/plugin-meetings 3.8.0 → 3.8.1-next.10

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 (361) hide show
  1. package/README.md +26 -13
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +70 -6
  4. package/dist/breakouts/index.js.map +1 -1
  5. package/dist/common/errors/webex-errors.js +12 -2
  6. package/dist/common/errors/webex-errors.js.map +1 -1
  7. package/dist/config.js +5 -1
  8. package/dist/config.js.map +1 -1
  9. package/dist/constants.js +28 -123
  10. package/dist/constants.js.map +1 -1
  11. package/dist/controls-options-manager/enums.js +3 -0
  12. package/dist/controls-options-manager/enums.js.map +1 -1
  13. package/dist/controls-options-manager/types.js.map +1 -1
  14. package/dist/controls-options-manager/util.js +78 -0
  15. package/dist/controls-options-manager/util.js.map +1 -1
  16. package/dist/interpretation/index.js +4 -4
  17. package/dist/interpretation/index.js.map +1 -1
  18. package/dist/interpretation/siLanguage.js +1 -1
  19. package/dist/locus-info/controlsUtils.js +37 -11
  20. package/dist/locus-info/controlsUtils.js.map +1 -1
  21. package/dist/locus-info/index.js +92 -12
  22. package/dist/locus-info/index.js.map +1 -1
  23. package/dist/locus-info/selfUtils.js +432 -418
  24. package/dist/locus-info/selfUtils.js.map +1 -1
  25. package/dist/media/index.js +17 -17
  26. package/dist/media/index.js.map +1 -1
  27. package/dist/media/properties.js +94 -6
  28. package/dist/media/properties.js.map +1 -1
  29. package/dist/meeting/brbState.js +9 -2
  30. package/dist/meeting/brbState.js.map +1 -1
  31. package/dist/meeting/in-meeting-actions.js +21 -1
  32. package/dist/meeting/in-meeting-actions.js.map +1 -1
  33. package/dist/meeting/index.js +678 -344
  34. package/dist/meeting/index.js.map +1 -1
  35. package/dist/meeting/locusMediaRequest.js +21 -22
  36. package/dist/meeting/locusMediaRequest.js.map +1 -1
  37. package/dist/meeting/muteState.js +4 -4
  38. package/dist/meeting/muteState.js.map +1 -1
  39. package/dist/meeting/request.js +30 -0
  40. package/dist/meeting/request.js.map +1 -1
  41. package/dist/meeting/request.type.js.map +1 -1
  42. package/dist/meeting/util.js +13 -2
  43. package/dist/meeting/util.js.map +1 -1
  44. package/dist/meeting-info/meeting-info-v2.js +373 -68
  45. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  46. package/dist/meeting-info/utilv2.js +5 -1
  47. package/dist/meeting-info/utilv2.js.map +1 -1
  48. package/dist/meetings/index.js +136 -1
  49. package/dist/meetings/index.js.map +1 -1
  50. package/dist/meetings/util.js +14 -0
  51. package/dist/meetings/util.js.map +1 -1
  52. package/dist/member/index.js +55 -9
  53. package/dist/member/index.js.map +1 -1
  54. package/dist/member/types.js +3 -0
  55. package/dist/member/types.js.map +1 -1
  56. package/dist/member/util.js +335 -353
  57. package/dist/member/util.js.map +1 -1
  58. package/dist/members/collection.js.map +1 -1
  59. package/dist/members/index.js +137 -29
  60. package/dist/members/index.js.map +1 -1
  61. package/dist/members/request.js +38 -0
  62. package/dist/members/request.js.map +1 -1
  63. package/dist/members/util.js +36 -1
  64. package/dist/members/util.js.map +1 -1
  65. package/dist/metrics/constants.js +10 -0
  66. package/dist/metrics/constants.js.map +1 -1
  67. package/dist/multistream/remoteMediaManager.js +40 -8
  68. package/dist/multistream/remoteMediaManager.js.map +1 -1
  69. package/dist/reachability/clusterReachability.js +63 -27
  70. package/dist/reachability/clusterReachability.js.map +1 -1
  71. package/dist/reachability/index.js +107 -47
  72. package/dist/reachability/index.js.map +1 -1
  73. package/dist/reachability/reachability.types.js +14 -0
  74. package/dist/reachability/reachability.types.js.map +1 -1
  75. package/dist/reachability/request.js +19 -3
  76. package/dist/reachability/request.js.map +1 -1
  77. package/dist/reconnection-manager/index.js +2 -2
  78. package/dist/reconnection-manager/index.js.map +1 -1
  79. package/dist/recording-controller/util.js +5 -5
  80. package/dist/recording-controller/util.js.map +1 -1
  81. package/dist/roap/index.js.map +1 -1
  82. package/dist/roap/turnDiscovery.js +45 -27
  83. package/dist/roap/turnDiscovery.js.map +1 -1
  84. package/dist/roap/types.js +17 -0
  85. package/dist/roap/types.js.map +1 -0
  86. package/dist/types/common/errors/webex-errors.d.ts +7 -1
  87. package/dist/types/config.d.ts +3 -0
  88. package/dist/types/constants.d.ts +20 -85
  89. package/dist/types/controls-options-manager/enums.d.ts +4 -1
  90. package/dist/types/controls-options-manager/types.d.ts +10 -1
  91. package/dist/types/locus-info/index.d.ts +3 -3
  92. package/dist/types/locus-info/selfUtils.d.ts +216 -1
  93. package/dist/types/media/properties.d.ts +15 -0
  94. package/dist/types/meeting/in-meeting-actions.d.ts +20 -0
  95. package/dist/types/meeting/index.d.ts +65 -1
  96. package/dist/types/meeting/muteState.d.ts +0 -1
  97. package/dist/types/meeting/request.d.ts +12 -1
  98. package/dist/types/meeting/request.type.d.ts +6 -0
  99. package/dist/types/meeting/util.d.ts +3 -1
  100. package/dist/types/meeting-info/meeting-info-v2.d.ts +82 -1
  101. package/dist/types/meetings/index.d.ts +57 -0
  102. package/dist/types/member/index.d.ts +21 -6
  103. package/dist/types/member/types.d.ts +73 -14
  104. package/dist/types/member/util.d.ts +156 -1
  105. package/dist/types/members/collection.d.ts +6 -5
  106. package/dist/types/members/index.d.ts +32 -43
  107. package/dist/types/members/request.d.ts +26 -0
  108. package/dist/types/members/util.d.ts +27 -0
  109. package/dist/types/metrics/constants.d.ts +10 -0
  110. package/dist/types/multistream/remoteMediaManager.d.ts +10 -1
  111. package/dist/types/reachability/clusterReachability.d.ts +15 -7
  112. package/dist/types/reachability/index.d.ts +10 -1
  113. package/dist/types/reachability/reachability.types.d.ts +5 -0
  114. package/dist/types/roap/index.d.ts +3 -2
  115. package/dist/types/roap/turnDiscovery.d.ts +5 -17
  116. package/dist/types/roap/types.d.ts +16 -0
  117. package/dist/webinar/index.js +2 -2
  118. package/dist/webinar/index.js.map +1 -1
  119. package/package.json +24 -23
  120. package/src/breakouts/index.ts +69 -0
  121. package/src/common/errors/webex-errors.ts +8 -1
  122. package/src/config.ts +3 -0
  123. package/src/constants.ts +30 -90
  124. package/src/controls-options-manager/enums.ts +3 -0
  125. package/src/controls-options-manager/types.ts +16 -1
  126. package/src/controls-options-manager/util.ts +93 -0
  127. package/src/interpretation/index.ts +3 -3
  128. package/src/locus-info/controlsUtils.ts +59 -14
  129. package/src/locus-info/index.ts +97 -13
  130. package/src/locus-info/selfUtils.ts +496 -442
  131. package/src/media/index.ts +23 -21
  132. package/src/media/properties.ts +96 -0
  133. package/src/meeting/brbState.ts +11 -2
  134. package/src/meeting/in-meeting-actions.ts +40 -0
  135. package/src/meeting/index.ts +470 -105
  136. package/src/meeting/locusMediaRequest.ts +27 -22
  137. package/src/meeting/muteState.ts +4 -4
  138. package/src/meeting/request.ts +36 -1
  139. package/src/meeting/request.type.ts +7 -0
  140. package/src/meeting/util.ts +11 -2
  141. package/src/meeting-info/meeting-info-v2.ts +254 -8
  142. package/src/meeting-info/utilv2.ts +5 -0
  143. package/src/meetings/index.ts +148 -1
  144. package/src/meetings/util.ts +18 -0
  145. package/src/member/index.ts +68 -22
  146. package/src/member/types.ts +82 -16
  147. package/src/member/util.ts +357 -350
  148. package/src/members/collection.ts +4 -3
  149. package/src/members/index.ts +137 -18
  150. package/src/members/request.ts +44 -0
  151. package/src/members/util.ts +43 -1
  152. package/src/metrics/constants.ts +10 -0
  153. package/src/multistream/remoteMediaManager.ts +32 -10
  154. package/src/reachability/clusterReachability.ts +73 -26
  155. package/src/reachability/index.ts +62 -1
  156. package/src/reachability/reachability.types.ts +6 -0
  157. package/src/reachability/request.ts +7 -0
  158. package/src/reconnection-manager/index.ts +2 -2
  159. package/src/recording-controller/util.ts +17 -13
  160. package/src/roap/index.ts +3 -7
  161. package/src/roap/turnDiscovery.ts +34 -39
  162. package/src/roap/types.ts +23 -0
  163. package/src/webinar/index.ts +1 -1
  164. package/test/unit/spec/breakouts/index.ts +167 -95
  165. package/test/unit/spec/controls-options-manager/util.js +178 -0
  166. package/test/unit/spec/interpretation/index.ts +39 -1
  167. package/test/unit/spec/locus-info/controlsUtils.js +155 -9
  168. package/test/unit/spec/locus-info/index.js +209 -73
  169. package/test/unit/spec/locus-info/selfUtils.js +98 -24
  170. package/test/unit/spec/media/index.ts +150 -18
  171. package/test/unit/spec/media/properties.ts +130 -0
  172. package/test/unit/spec/meeting/brbState.ts +40 -2
  173. package/test/unit/spec/meeting/in-meeting-actions.ts +23 -4
  174. package/test/unit/spec/meeting/index.js +804 -139
  175. package/test/unit/spec/meeting/locusMediaRequest.ts +95 -87
  176. package/test/unit/spec/meeting/muteState.js +73 -2
  177. package/test/unit/spec/meeting/request.js +32 -1
  178. package/test/unit/spec/meeting/utils.js +119 -18
  179. package/test/unit/spec/meeting-info/meetinginfov2.js +484 -114
  180. package/test/unit/spec/meeting-info/utilv2.js +19 -0
  181. package/test/unit/spec/meetings/index.js +146 -2
  182. package/test/unit/spec/member/index.js +7 -0
  183. package/test/unit/spec/member/util.js +24 -0
  184. package/test/unit/spec/members/index.js +304 -78
  185. package/test/unit/spec/members/request.js +68 -22
  186. package/test/unit/spec/members/utils.js +75 -0
  187. package/test/unit/spec/multistream/remoteMediaManager.ts +397 -118
  188. package/test/unit/spec/reachability/clusterReachability.ts +88 -56
  189. package/test/unit/spec/reachability/index.ts +97 -0
  190. package/test/unit/spec/reachability/request.js +47 -2
  191. package/test/unit/spec/reconnection-manager/index.js +4 -4
  192. package/test/unit/spec/roap/turnDiscovery.ts +110 -28
  193. package/test/unit/spec/webinar/index.ts +5 -0
  194. package/dist/annotation/annotation.types.d.ts +0 -42
  195. package/dist/annotation/constants.d.ts +0 -31
  196. package/dist/annotation/index.d.ts +0 -117
  197. package/dist/breakouts/breakout.d.ts +0 -8
  198. package/dist/breakouts/collection.d.ts +0 -5
  199. package/dist/breakouts/edit-lock-error.d.ts +0 -15
  200. package/dist/breakouts/events.d.ts +0 -8
  201. package/dist/breakouts/index.d.ts +0 -5
  202. package/dist/breakouts/request.d.ts +0 -22
  203. package/dist/breakouts/utils.d.ts +0 -15
  204. package/dist/common/browser-detection.d.ts +0 -9
  205. package/dist/common/collection.d.ts +0 -48
  206. package/dist/common/config.d.ts +0 -2
  207. package/dist/common/errors/captcha-error.d.ts +0 -15
  208. package/dist/common/errors/intent-to-join.d.ts +0 -16
  209. package/dist/common/errors/join-meeting.d.ts +0 -17
  210. package/dist/common/errors/media.d.ts +0 -15
  211. package/dist/common/errors/no-meeting-info.d.ts +0 -14
  212. package/dist/common/errors/parameter.d.ts +0 -15
  213. package/dist/common/errors/password-error.d.ts +0 -15
  214. package/dist/common/errors/permission.d.ts +0 -14
  215. package/dist/common/errors/reclaim-host-role-error.js +0 -149
  216. package/dist/common/errors/reclaim-host-role-error.js.map +0 -1
  217. package/dist/common/errors/reclaim-host-role-errors.d.ts +0 -60
  218. package/dist/common/errors/reconnection-in-progress.d.ts +0 -9
  219. package/dist/common/errors/reconnection-in-progress.js +0 -33
  220. package/dist/common/errors/reconnection-in-progress.js.map +0 -1
  221. package/dist/common/errors/reconnection.d.ts +0 -15
  222. package/dist/common/errors/stats.d.ts +0 -15
  223. package/dist/common/errors/webex-errors.d.ts +0 -93
  224. package/dist/common/errors/webex-meetings-error.d.ts +0 -20
  225. package/dist/common/events/events-scope.d.ts +0 -17
  226. package/dist/common/events/events.d.ts +0 -12
  227. package/dist/common/events/trigger-proxy.d.ts +0 -2
  228. package/dist/common/events/util.d.ts +0 -2
  229. package/dist/common/logs/logger-config.d.ts +0 -2
  230. package/dist/common/logs/logger-proxy.d.ts +0 -2
  231. package/dist/common/logs/request.d.ts +0 -36
  232. package/dist/common/queue.d.ts +0 -34
  233. package/dist/config.d.ts +0 -72
  234. package/dist/constants.d.ts +0 -1088
  235. package/dist/controls-options-manager/constants.d.ts +0 -4
  236. package/dist/controls-options-manager/enums.d.ts +0 -15
  237. package/dist/controls-options-manager/index.d.ts +0 -136
  238. package/dist/controls-options-manager/types.d.ts +0 -43
  239. package/dist/controls-options-manager/util.d.ts +0 -1
  240. package/dist/index.d.ts +0 -7
  241. package/dist/interceptors/index.d.ts +0 -2
  242. package/dist/interceptors/locusRetry.d.ts +0 -27
  243. package/dist/interpretation/collection.d.ts +0 -5
  244. package/dist/interpretation/index.d.ts +0 -5
  245. package/dist/interpretation/siLanguage.d.ts +0 -5
  246. package/dist/locus-info/controlsUtils.d.ts +0 -2
  247. package/dist/locus-info/embeddedAppsUtils.d.ts +0 -2
  248. package/dist/locus-info/fullState.d.ts +0 -2
  249. package/dist/locus-info/hostUtils.d.ts +0 -2
  250. package/dist/locus-info/index.d.ts +0 -322
  251. package/dist/locus-info/infoUtils.d.ts +0 -2
  252. package/dist/locus-info/mediaSharesUtils.d.ts +0 -2
  253. package/dist/locus-info/parser.d.ts +0 -272
  254. package/dist/locus-info/selfUtils.d.ts +0 -2
  255. package/dist/media/index.d.ts +0 -34
  256. package/dist/media/properties.d.ts +0 -93
  257. package/dist/media/util.d.ts +0 -2
  258. package/dist/mediaQualityMetrics/config.d.ts +0 -241
  259. package/dist/mediaQualityMetrics/config.js +0 -502
  260. package/dist/mediaQualityMetrics/config.js.map +0 -1
  261. package/dist/meeting/effectsState.js +0 -260
  262. package/dist/meeting/effectsState.js.map +0 -1
  263. package/dist/meeting/in-meeting-actions.d.ts +0 -167
  264. package/dist/meeting/index.d.ts +0 -1825
  265. package/dist/meeting/locusMediaRequest.d.ts +0 -74
  266. package/dist/meeting/muteState.d.ts +0 -178
  267. package/dist/meeting/request.d.ts +0 -295
  268. package/dist/meeting/request.type.d.ts +0 -11
  269. package/dist/meeting/state.d.ts +0 -9
  270. package/dist/meeting/util.d.ts +0 -119
  271. package/dist/meeting/voicea-meeting.d.ts +0 -16
  272. package/dist/meeting-info/collection.d.ts +0 -20
  273. package/dist/meeting-info/index.d.ts +0 -69
  274. package/dist/meeting-info/meeting-info-v2.d.ts +0 -123
  275. package/dist/meeting-info/request.d.ts +0 -22
  276. package/dist/meeting-info/util.d.ts +0 -2
  277. package/dist/meeting-info/utilv2.d.ts +0 -2
  278. package/dist/meetings/collection.d.ts +0 -40
  279. package/dist/meetings/index.d.ts +0 -390
  280. package/dist/meetings/meetings.types.d.ts +0 -4
  281. package/dist/meetings/request.d.ts +0 -27
  282. package/dist/meetings/util.d.ts +0 -18
  283. package/dist/member/index.d.ts +0 -160
  284. package/dist/member/member.types.js +0 -17
  285. package/dist/member/member.types.js.map +0 -1
  286. package/dist/member/types.d.ts +0 -32
  287. package/dist/member/util.d.ts +0 -2
  288. package/dist/members/collection.d.ts +0 -29
  289. package/dist/members/index.d.ts +0 -353
  290. package/dist/members/request.d.ts +0 -114
  291. package/dist/members/types.d.ts +0 -25
  292. package/dist/members/util.d.ts +0 -215
  293. package/dist/metrics/config.js +0 -276
  294. package/dist/metrics/config.js.map +0 -1
  295. package/dist/metrics/constants.d.ts +0 -70
  296. package/dist/metrics/index.d.ts +0 -45
  297. package/dist/multistream/mediaRequestManager.d.ts +0 -119
  298. package/dist/multistream/receiveSlot.d.ts +0 -68
  299. package/dist/multistream/receiveSlotManager.d.ts +0 -56
  300. package/dist/multistream/remoteMedia.d.ts +0 -72
  301. package/dist/multistream/remoteMediaGroup.d.ts +0 -49
  302. package/dist/multistream/remoteMediaManager.d.ts +0 -300
  303. package/dist/multistream/sendSlotManager.d.ts +0 -69
  304. package/dist/networkQualityMonitor/index.d.ts +0 -70
  305. package/dist/networkQualityMonitor/index.js +0 -221
  306. package/dist/networkQualityMonitor/index.js.map +0 -1
  307. package/dist/peer-connection-manager/index.js +0 -671
  308. package/dist/peer-connection-manager/index.js.map +0 -1
  309. package/dist/peer-connection-manager/util.js +0 -109
  310. package/dist/peer-connection-manager/util.js.map +0 -1
  311. package/dist/personal-meeting-room/index.d.ts +0 -47
  312. package/dist/personal-meeting-room/request.d.ts +0 -14
  313. package/dist/personal-meeting-room/util.d.ts +0 -2
  314. package/dist/reachability/clusterReachability.d.ts +0 -109
  315. package/dist/reachability/index.d.ts +0 -105
  316. package/dist/reachability/request.d.ts +0 -39
  317. package/dist/reachability/util.d.ts +0 -8
  318. package/dist/reactions/constants.d.ts +0 -3
  319. package/dist/reactions/reactions.d.ts +0 -4
  320. package/dist/reactions/reactions.type.d.ts +0 -52
  321. package/dist/reconnection-manager/index.d.ts +0 -136
  322. package/dist/recording-controller/enums.d.ts +0 -7
  323. package/dist/recording-controller/index.d.ts +0 -207
  324. package/dist/recording-controller/util.d.ts +0 -14
  325. package/dist/roap/collection.js +0 -62
  326. package/dist/roap/collection.js.map +0 -1
  327. package/dist/roap/handler.js +0 -275
  328. package/dist/roap/handler.js.map +0 -1
  329. package/dist/roap/index.d.ts +0 -86
  330. package/dist/roap/request.d.ts +0 -39
  331. package/dist/roap/state.js +0 -126
  332. package/dist/roap/state.js.map +0 -1
  333. package/dist/roap/turnDiscovery.d.ts +0 -155
  334. package/dist/roap/util.js +0 -75
  335. package/dist/roap/util.js.map +0 -1
  336. package/dist/rtcMetrics/constants.d.ts +0 -4
  337. package/dist/rtcMetrics/constants.js +0 -11
  338. package/dist/rtcMetrics/constants.js.map +0 -1
  339. package/dist/rtcMetrics/index.d.ts +0 -61
  340. package/dist/rtcMetrics/index.js +0 -197
  341. package/dist/rtcMetrics/index.js.map +0 -1
  342. package/dist/statsAnalyzer/global.d.ts +0 -36
  343. package/dist/statsAnalyzer/global.js +0 -126
  344. package/dist/statsAnalyzer/global.js.map +0 -1
  345. package/dist/statsAnalyzer/index.d.ts +0 -217
  346. package/dist/statsAnalyzer/index.js +0 -1013
  347. package/dist/statsAnalyzer/index.js.map +0 -1
  348. package/dist/statsAnalyzer/mqaUtil.d.ts +0 -48
  349. package/dist/statsAnalyzer/mqaUtil.js +0 -179
  350. package/dist/statsAnalyzer/mqaUtil.js.map +0 -1
  351. package/dist/transcription/index.d.ts +0 -64
  352. package/dist/types/common/errors/reconnection-in-progress.d.ts +0 -9
  353. package/dist/types/mediaQualityMetrics/config.d.ts +0 -241
  354. package/dist/types/networkQualityMonitor/index.d.ts +0 -70
  355. package/dist/types/rtcMetrics/constants.d.ts +0 -4
  356. package/dist/types/rtcMetrics/index.d.ts +0 -71
  357. package/dist/types/statsAnalyzer/global.d.ts +0 -36
  358. package/dist/types/statsAnalyzer/index.d.ts +0 -217
  359. package/dist/types/statsAnalyzer/mqaUtil.d.ts +0 -48
  360. package/dist/webinar/collection.d.ts +0 -16
  361. package/dist/webinar/index.d.ts +0 -5
@@ -60,11 +60,8 @@ import {
60
60
  import LoggerProxy from '../common/logs/logger-proxy';
61
61
  import EventsUtil from '../common/events/util';
62
62
  import Trigger from '../common/events/trigger-proxy';
63
- import Roap, {
64
- type TurnDiscoveryResult,
65
- type TurnServerInfo,
66
- type TurnDiscoverySkipReason,
67
- } from '../roap/index';
63
+ import Roap, {type TurnDiscoveryResult, type TurnDiscoverySkipReason} from '../roap/index';
64
+ import {type TurnServerInfo} from '../roap/types';
68
65
  import Media, {type BundlePolicy} from '../media';
69
66
  import MediaProperties from '../media/properties';
70
67
  import MeetingStateMachine from './state';
@@ -103,7 +100,6 @@ import {
103
100
  MEETING_STATE_MACHINE,
104
101
  MEETING_STATE,
105
102
  MEETINGS,
106
- MQA_STATS,
107
103
  NETWORK_STATUS,
108
104
  ONLINE,
109
105
  OFFLINE,
@@ -167,6 +163,7 @@ import Member from '../member';
167
163
  import {BrbState, createBrbState} from './brbState';
168
164
  import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error';
169
165
  import JoinForbiddenError from '../common/errors/join-forbidden-error';
166
+ import {ReachabilityMetrics} from '../reachability/reachability.types';
170
167
 
171
168
  // default callback so we don't call an undefined function, but in practice it should never be used
172
169
  const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
@@ -241,6 +238,8 @@ export type CallStateForMetrics = {
241
238
  sessionCorrelationId?: string;
242
239
  joinTrigger?: string;
243
240
  loginType?: string;
241
+ userNameInput?: string;
242
+ emailInput?: string;
244
243
  };
245
244
 
246
245
  export const MEDIA_UPDATE_TYPE = {
@@ -263,6 +262,12 @@ type FetchMeetingInfoParams = {
263
262
  sendCAevents?: boolean;
264
263
  };
265
264
 
265
+ type MediaReachabilityMetrics = ReachabilityMetrics & {
266
+ subnet_reachable: boolean;
267
+ selected_cluster: string | null;
268
+ selected_subnet: string | null;
269
+ };
270
+
266
271
  /**
267
272
  * MediaDirection
268
273
  * @typedef {Object} MediaDirection
@@ -648,6 +653,13 @@ export default class Meeting extends StatelessWebexPlugin {
648
653
  allowMediaInLobby: boolean;
649
654
  localShareInstanceId: string;
650
655
  remoteShareInstanceId: string;
656
+ shareCAEventSentStatus: {
657
+ transmitStart: boolean;
658
+ transmitStop: boolean;
659
+ receiveStart: boolean;
660
+ receiveStop: boolean;
661
+ };
662
+
651
663
  turnDiscoverySkippedReason: TurnDiscoverySkipReason;
652
664
  turnServerUsed: boolean;
653
665
  areVoiceaEventsSetup = false;
@@ -716,6 +728,7 @@ export default class Meeting extends StatelessWebexPlugin {
716
728
  private rtcMetrics?: RtcMetrics;
717
729
  private uploadLogsTimer?: ReturnType<typeof setTimeout>;
718
730
  private logUploadIntervalIndex: number;
731
+ private mediaServerIp: string;
719
732
 
720
733
  /**
721
734
  * @param {Object} attrs
@@ -1332,7 +1345,7 @@ export default class Meeting extends StatelessWebexPlugin {
1332
1345
  captions: [],
1333
1346
  isListening: false,
1334
1347
  commandText: '',
1335
- languageOptions: {},
1348
+ languageOptions: {currentSpokenLanguage: 'en'},
1336
1349
  showCaptionBox: false,
1337
1350
  transcribingRequestStatus: 'INACTIVE',
1338
1351
  isCaptioning: false,
@@ -1420,6 +1433,19 @@ export default class Meeting extends StatelessWebexPlugin {
1420
1433
  */
1421
1434
  this.remoteShareInstanceId = null;
1422
1435
 
1436
+ /**
1437
+ * Status used for ensuring we do not oversend metrics
1438
+ * @instance
1439
+ * @private
1440
+ * @memberof Meeting
1441
+ */
1442
+ this.shareCAEventSentStatus = {
1443
+ transmitStart: false,
1444
+ transmitStop: false,
1445
+ receiveStart: false,
1446
+ receiveStop: false,
1447
+ };
1448
+
1423
1449
  /**
1424
1450
  * The class that helps to control recording functions: start, stop, pause, resume, etc
1425
1451
  * @instance
@@ -1579,6 +1605,19 @@ export default class Meeting extends StatelessWebexPlugin {
1579
1605
  * @memberof Meeting
1580
1606
  */
1581
1607
  this.#isoLocalClientMeetingJoinTime = undefined;
1608
+
1609
+ // We clear the error cache of CA events on every new meeting instance
1610
+ // @ts-ignore - Fix type
1611
+ this.webex.internal.newMetrics.callDiagnosticMetrics.clearErrorCache();
1612
+
1613
+ /**
1614
+ * IP Address of the remote media server
1615
+ * @instance
1616
+ * @type {string}
1617
+ * @private
1618
+ * @memberof Meeting
1619
+ */
1620
+ this.mediaServerIp = undefined;
1582
1621
  }
1583
1622
 
1584
1623
  /**
@@ -1627,6 +1666,38 @@ export default class Meeting extends StatelessWebexPlugin {
1627
1666
  this.callStateForMetrics.correlationId = correlationId;
1628
1667
  }
1629
1668
 
1669
+ /**
1670
+ * Getter - Returns callStateForMetrics.userNameInput
1671
+ * @returns {string}
1672
+ */
1673
+ get userNameInput() {
1674
+ return this.callStateForMetrics?.userNameInput;
1675
+ }
1676
+
1677
+ /**
1678
+ * Setter - sets callStateForMetrics.userNameInput
1679
+ * @param {string} userNameInput
1680
+ */
1681
+ set userNameInput(userNameInput: string) {
1682
+ this.callStateForMetrics.userNameInput = userNameInput;
1683
+ }
1684
+
1685
+ /**
1686
+ * Getter - Returns callStateForMetrics.emailInput
1687
+ * @returns {string}
1688
+ */
1689
+ get emailInput() {
1690
+ return this.callStateForMetrics?.emailInput;
1691
+ }
1692
+
1693
+ /**
1694
+ * Setter - sets callStateForMetrics.emailInput
1695
+ * @param {string} emailInput
1696
+ */
1697
+ set emailInput(emailInput: string) {
1698
+ this.callStateForMetrics.emailInput = emailInput;
1699
+ }
1700
+
1630
1701
  /**
1631
1702
  * Getter - Returns callStateForMetrics.sessionCorrelationId
1632
1703
  * @returns {string}
@@ -1652,6 +1723,33 @@ export default class Meeting extends StatelessWebexPlugin {
1652
1723
  return this.#isoLocalClientMeetingJoinTime;
1653
1724
  }
1654
1725
 
1726
+ /**
1727
+ * Setter - sets isoLocalClientMeetingJoinTime
1728
+ * This will be set once on meeting join, and not updated again
1729
+ * this will always produce an ISO string
1730
+ * If the iso string is invalid, it will fallback to the current system time
1731
+ * @param {string | undefined} time
1732
+ */
1733
+ set isoLocalClientMeetingJoinTime(time: string | undefined) {
1734
+ const fallback = new Date().toISOString();
1735
+ if (!time) {
1736
+ this.#isoLocalClientMeetingJoinTime = fallback;
1737
+ } else {
1738
+ const date = new Date(time);
1739
+
1740
+ // Check if the date is valid
1741
+ if (Number.isNaN(date.getTime())) {
1742
+ LoggerProxy.logger.info(
1743
+ // @ts-ignore
1744
+ `Meeting:index#isoLocalClientMeetingJoinTime --> Invalid date provided: ${time}. Falling back to system clock.`
1745
+ );
1746
+ this.#isoLocalClientMeetingJoinTime = fallback;
1747
+ } else {
1748
+ this.#isoLocalClientMeetingJoinTime = date.toISOString();
1749
+ }
1750
+ }
1751
+ }
1752
+
1655
1753
  /**
1656
1754
  * Set meeting info and trigger `MEETING_INFO_AVAILABLE` event
1657
1755
  * @param {any} info
@@ -2543,6 +2641,19 @@ export default class Meeting extends StatelessWebexPlugin {
2543
2641
  this.locusInfo.on(EVENTS.LOCUS_INFO_UPDATE_PARTICIPANTS, (payload) => {
2544
2642
  this.members.locusParticipantsUpdate(payload);
2545
2643
  });
2644
+ this.locusInfo.on(LOCUSINFO.EVENTS.PARTICIPANT_REASON_CHANGED, (payload) => {
2645
+ Trigger.trigger(
2646
+ this,
2647
+ {
2648
+ file: 'meeting/index',
2649
+ function: 'setUpLocusParticipantsListener',
2650
+ },
2651
+ EVENT_TRIGGERS.MEETING_PARTICIPANT_REASON_CHANGED,
2652
+ {
2653
+ payload,
2654
+ }
2655
+ );
2656
+ });
2546
2657
  }
2547
2658
 
2548
2659
  /**
@@ -2643,6 +2754,29 @@ export default class Meeting extends StatelessWebexPlugin {
2643
2754
  }
2644
2755
  );
2645
2756
 
2757
+ this.locusInfo.on(
2758
+ LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
2759
+ ({spokenLanguage}) => {
2760
+ if (spokenLanguage) {
2761
+ if (this.transcription?.languageOptions) {
2762
+ this.transcription.languageOptions.currentSpokenLanguage = spokenLanguage;
2763
+ }
2764
+ // @ts-ignore
2765
+ this.webex.internal.voicea.onSpokenLanguageUpdate(spokenLanguage);
2766
+
2767
+ Trigger.trigger(
2768
+ this,
2769
+ {
2770
+ file: 'meeting/index',
2771
+ function: 'setupLocusControlsListener',
2772
+ },
2773
+ EVENT_TRIGGERS.MEETING_TRANSCRIPTION_SPOKEN_LANGUAGE_UPDATED,
2774
+ {spokenLanguage}
2775
+ );
2776
+ }
2777
+ }
2778
+ );
2779
+
2646
2780
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_MANUAL_CAPTION_UPDATED, ({enable}) => {
2647
2781
  Trigger.trigger(
2648
2782
  this,
@@ -2793,6 +2927,33 @@ export default class Meeting extends StatelessWebexPlugin {
2793
2927
  {state}
2794
2928
  );
2795
2929
  });
2930
+
2931
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_ANNOTATION_CHANGED, ({state}) => {
2932
+ Trigger.trigger(
2933
+ this,
2934
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2935
+ EVENT_TRIGGERS.MEETING_CONTROLS_ANNOTATION_UPDATED,
2936
+ {state}
2937
+ );
2938
+ });
2939
+
2940
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_REMOTE_DESKTOP_CONTROL_CHANGED, ({state}) => {
2941
+ Trigger.trigger(
2942
+ this,
2943
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2944
+ EVENT_TRIGGERS.MEETING_CONTROLS_REMOTE_DESKTOP_CONTROL_UPDATED,
2945
+ {state}
2946
+ );
2947
+ });
2948
+
2949
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_POLLING_QA_CHANGED, ({state}) => {
2950
+ Trigger.trigger(
2951
+ this,
2952
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2953
+ EVENT_TRIGGERS.MEETING_CONTROLS_POLLING_QA_UPDATED,
2954
+ {state}
2955
+ );
2956
+ });
2796
2957
  }
2797
2958
 
2798
2959
  /**
@@ -2965,6 +3126,8 @@ export default class Meeting extends StatelessWebexPlugin {
2965
3126
  case SHARE_STATUS.REMOTE_SHARE_ACTIVE: {
2966
3127
  const sendStartedSharingRemote = () => {
2967
3128
  this.remoteShareInstanceId = contentShare.shareInstanceId;
3129
+ this.shareCAEventSentStatus.receiveStart = false;
3130
+ this.shareCAEventSentStatus.receiveStop = false;
2968
3131
 
2969
3132
  Trigger.trigger(
2970
3133
  this,
@@ -3018,6 +3181,7 @@ export default class Meeting extends StatelessWebexPlugin {
3018
3181
  },
3019
3182
  options: {meetingId: this.id},
3020
3183
  });
3184
+
3021
3185
  break;
3022
3186
 
3023
3187
  case SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE:
@@ -3058,6 +3222,8 @@ export default class Meeting extends StatelessWebexPlugin {
3058
3222
  // if we got here, then some remote participant has stolen
3059
3223
  // the presentation from another remote participant
3060
3224
  this.remoteShareInstanceId = contentShare.shareInstanceId;
3225
+ this.shareCAEventSentStatus.receiveStart = false;
3226
+ this.shareCAEventSentStatus.receiveStop = false;
3061
3227
 
3062
3228
  Trigger.trigger(
3063
3229
  this,
@@ -3686,6 +3852,18 @@ export default class Meeting extends StatelessWebexPlugin {
3686
3852
  return this.members.cancelPhoneInvite(invitee);
3687
3853
  }
3688
3854
 
3855
+ /**
3856
+ * Cancel an SIP call invitation made during a meeting
3857
+ * @param {Object} invitee
3858
+ * @param {String} invitee.memberId
3859
+ * @returns {Promise} see #members.cancelSIPInvite
3860
+ * @public
3861
+ * @memberof Meeting
3862
+ */
3863
+ public cancelSIPInvite(invitee: {memberId: string}) {
3864
+ return this.members.cancelSIPInvite(invitee);
3865
+ }
3866
+
3689
3867
  /**
3690
3868
  * Admit the guest(s) to the call once they are waiting.
3691
3869
  * If the host/cohost is in a breakout session, the locus url
@@ -3741,7 +3919,16 @@ export default class Meeting extends StatelessWebexPlugin {
3741
3919
  return Promise.reject(error);
3742
3920
  }
3743
3921
 
3744
- return this.brbState.enable(enabled, this.sendSlotManager);
3922
+ return this.brbState
3923
+ .enable(enabled, this.sendSlotManager)
3924
+ .then(() => {
3925
+ if (this.audio && enabled) {
3926
+ // locus mutes the participant with brb enabled request,
3927
+ // so we need to explicitly update remote mute for correct logic flow
3928
+ this.audio.handleServerRemoteMuteUpdate(this, enabled);
3929
+ }
3930
+ })
3931
+ .catch((error) => Promise.reject(error));
3745
3932
  }
3746
3933
 
3747
3934
  /**
@@ -3933,7 +4120,10 @@ export default class Meeting extends StatelessWebexPlugin {
3933
4120
  canAdmitParticipant: MeetingUtil.canAdmitParticipant(this.userDisplayHints),
3934
4121
  canLock: MeetingUtil.canUserLock(this.userDisplayHints),
3935
4122
  canUnlock: MeetingUtil.canUserUnlock(this.userDisplayHints),
3936
- canShareWhiteBoard: MeetingUtil.canShareWhiteBoard(this.userDisplayHints),
4123
+ canShareWhiteBoard: MeetingUtil.canShareWhiteBoard(
4124
+ this.userDisplayHints,
4125
+ this.selfUserPolicies
4126
+ ),
3937
4127
  canSetDisallowUnmute: ControlsOptionsUtil.canSetDisallowUnmute(this.userDisplayHints),
3938
4128
  canUnsetDisallowUnmute: ControlsOptionsUtil.canUnsetDisallowUnmute(this.userDisplayHints),
3939
4129
  canSetMuteOnEntry: ControlsOptionsUtil.canSetMuteOnEntry(this.userDisplayHints),
@@ -3982,6 +4172,9 @@ export default class Meeting extends StatelessWebexPlugin {
3982
4172
  this.inMeetingActions.canSendReactions,
3983
4173
  this.userDisplayHints
3984
4174
  ),
4175
+ requiresPostMeetingDataConsentPrompt: MeetingUtil.requiresPostMeetingDataConsentPrompt(
4176
+ this.userDisplayHints
4177
+ ),
3985
4178
  canManageBreakout: MeetingUtil.canManageBreakout(this.userDisplayHints),
3986
4179
  canStartBreakout: MeetingUtil.canStartBreakout(this.userDisplayHints),
3987
4180
  canBroadcastMessageToBreakout: MeetingUtil.canBroadcastMessageToBreakout(
@@ -3997,6 +4190,7 @@ export default class Meeting extends StatelessWebexPlugin {
3997
4190
  this.userDisplayHints
3998
4191
  ),
3999
4192
  canUserRenameOthers: MeetingUtil.canUserRenameOthers(this.userDisplayHints),
4193
+ canMoveToLobby: MeetingUtil.canMoveToLobby(this.userDisplayHints),
4000
4194
  canMuteAll: ControlsOptionsUtil.hasHints({
4001
4195
  requiredHints: [DISPLAY_HINTS.MUTE_ALL],
4002
4196
  displayHints: this.userDisplayHints,
@@ -4131,6 +4325,14 @@ export default class Meeting extends StatelessWebexPlugin {
4131
4325
  requiredPolicies: [SELF_POLICY.SUPPORT_FILE_TRANSFER],
4132
4326
  policies: this.selfUserPolicies,
4133
4327
  }),
4328
+ canRealtimeCloseCaption: ControlsOptionsUtil.hasPolicies({
4329
+ requiredPolicies: [SELF_POLICY.SUPPORT_REALTIME_CLOSE_CAPTION],
4330
+ policies: this.selfUserPolicies,
4331
+ }),
4332
+ canRealtimeCloseCaptionManual: ControlsOptionsUtil.hasPolicies({
4333
+ requiredPolicies: [SELF_POLICY.SUPPORT_REALTIME_CLOSE_CAPTION_MANUAL],
4334
+ policies: this.selfUserPolicies,
4335
+ }),
4134
4336
  canChat: ControlsOptionsUtil.hasPolicies({
4135
4337
  requiredPolicies: [SELF_POLICY.SUPPORT_CHAT],
4136
4338
  policies: this.selfUserPolicies,
@@ -4177,6 +4379,30 @@ export default class Meeting extends StatelessWebexPlugin {
4177
4379
  requiredPolicies: [SELF_POLICY.SUPPORT_ANNOTATION],
4178
4380
  policies: this.selfUserPolicies,
4179
4381
  }),
4382
+ canEnableAnnotation: ControlsOptionsUtil.hasHints({
4383
+ requiredHints: [DISPLAY_HINTS.ENABLE_ANNOTATION_MEETING_OPTION],
4384
+ displayHints: this.userDisplayHints,
4385
+ }),
4386
+ canDisableAnnotation: ControlsOptionsUtil.hasHints({
4387
+ requiredHints: [DISPLAY_HINTS.DISABLE_ANNOTATION_MEETING_OPTION],
4388
+ displayHints: this.userDisplayHints,
4389
+ }),
4390
+ canEnableRemoteDesktopControl: ControlsOptionsUtil.hasHints({
4391
+ requiredHints: [DISPLAY_HINTS.ENABLE_RDC_MEETING_OPTION],
4392
+ displayHints: this.userDisplayHints,
4393
+ }),
4394
+ canDisableRemoteDesktopControl: ControlsOptionsUtil.hasHints({
4395
+ requiredHints: [DISPLAY_HINTS.DISABLE_RDC_MEETING_OPTION],
4396
+ displayHints: this.userDisplayHints,
4397
+ }),
4398
+ canEnablePollingQA: ControlsOptionsUtil.hasHints({
4399
+ requiredHints: [DISPLAY_HINTS.ENABLE_ATTENDEE_START_POLLING_QA],
4400
+ displayHints: this.userDisplayHints,
4401
+ }),
4402
+ canDisablePollingQA: ControlsOptionsUtil.hasHints({
4403
+ requiredHints: [DISPLAY_HINTS.DISABLE_ATTENDEE_START_POLLING_QA],
4404
+ displayHints: this.userDisplayHints,
4405
+ }),
4180
4406
  }) || changed;
4181
4407
  }
4182
4408
  if (changed) {
@@ -4692,11 +4918,6 @@ export default class Meeting extends StatelessWebexPlugin {
4692
4918
 
4693
4919
  // Only send restore event when it was disconnected before and for connected later
4694
4920
  if (!this.hasWebsocketConnected) {
4695
- // @ts-ignore
4696
- this.webex.internal.newMetrics.submitClientEvent({
4697
- name: 'client.mercury.connection.restored',
4698
- options: {meetingId: this.id},
4699
- });
4700
4921
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_RESTORED, {
4701
4922
  correlation_id: this.correlationId,
4702
4923
  });
@@ -4707,11 +4928,6 @@ export default class Meeting extends StatelessWebexPlugin {
4707
4928
  // @ts-ignore
4708
4929
  this.webex.internal.mercury.on(OFFLINE, () => {
4709
4930
  LoggerProxy.logger.error('Meeting:index#setMercuryListener --> Web socket offline');
4710
- // @ts-ignore
4711
- this.webex.internal.newMetrics.submitClientEvent({
4712
- name: 'client.mercury.connection.lost',
4713
- options: {meetingId: this.id},
4714
- });
4715
4931
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_FAILURE, {
4716
4932
  correlation_id: this.correlationId,
4717
4933
  });
@@ -5684,8 +5900,6 @@ export default class Meeting extends StatelessWebexPlugin {
5684
5900
  // @ts-ignore
5685
5901
  this.webex.internal.device.meetingStarted();
5686
5902
 
5687
- this.#isoLocalClientMeetingJoinTime = new Date().toISOString();
5688
-
5689
5903
  LoggerProxy.logger.log('Meeting:index#join --> Success');
5690
5904
 
5691
5905
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_SUCCESS, {
@@ -5794,7 +6008,14 @@ export default class Meeting extends StatelessWebexPlugin {
5794
6008
  return undefined;
5795
6009
  }
5796
6010
  // @ts-ignore - Fix type
5797
- await this.webex.internal.llm.disconnectLLM();
6011
+ await this.webex.internal.llm.disconnectLLM(
6012
+ isJoined
6013
+ ? {
6014
+ code: 3050,
6015
+ reason: 'done (permanent)',
6016
+ }
6017
+ : undefined
6018
+ );
5798
6019
  // @ts-ignore - Fix type
5799
6020
  this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
5800
6021
  }
@@ -6139,10 +6360,7 @@ export default class Meeting extends StatelessWebexPlugin {
6139
6360
  },
6140
6361
  options: {meetingId: this.id, rawError: error},
6141
6362
  });
6142
- } else if (
6143
- error instanceof Errors.SdpOfferHandlingError ||
6144
- error instanceof Errors.SdpAnswerHandlingError
6145
- ) {
6363
+ } else if (error instanceof Errors.SdpOfferHandlingError) {
6146
6364
  sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.correlationId);
6147
6365
 
6148
6366
  // @ts-ignore
@@ -6153,6 +6371,24 @@ export default class Meeting extends StatelessWebexPlugin {
6153
6371
  },
6154
6372
  options: {meetingId: this.id, rawError: error},
6155
6373
  });
6374
+ } else if (error instanceof Errors.SdpAnswerHandlingError) {
6375
+ sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.correlationId);
6376
+
6377
+ // @ts-ignore
6378
+ this.webex.internal.newMetrics.submitClientEvent({
6379
+ name: 'client.media-engine.remote-sdp-received',
6380
+ payload: {
6381
+ canProceed: false,
6382
+ },
6383
+ options: {meetingId: this.id, rawError: error},
6384
+ });
6385
+
6386
+ if (this.deferSDPAnswer) {
6387
+ clearTimeout(this.sdpResponseTimer);
6388
+ this.sdpResponseTimer = undefined;
6389
+
6390
+ this.deferSDPAnswer.reject();
6391
+ }
6156
6392
  } else if (error instanceof Errors.SdpError) {
6157
6393
  // this covers also the case of Errors.IceGatheringError which extends Errors.SdpError
6158
6394
  sendBehavioralMetric(BEHAVIORAL_METRICS.INVALID_ICE_CANDIDATE, error, this.correlationId);
@@ -6180,6 +6416,11 @@ export default class Meeting extends StatelessWebexPlugin {
6180
6416
  ? MeetingsUtil.getMediaServer(roapMessage.sdp)
6181
6417
  : undefined;
6182
6418
 
6419
+ const mediaServerIp =
6420
+ roapMessage.messageType === 'ANSWER'
6421
+ ? MeetingsUtil.getMediaServerIp(roapMessage.sdp)
6422
+ : undefined;
6423
+
6183
6424
  if (this.isMultistream && mediaServer && mediaServer !== 'homer') {
6184
6425
  throw new MultistreamNotSupportedError(
6185
6426
  `Client asked for multistream backend (Homer), but got ${mediaServer} instead`
@@ -6190,6 +6431,10 @@ export default class Meeting extends StatelessWebexPlugin {
6190
6431
  if (mediaServer) {
6191
6432
  this.mediaProperties.webrtcMediaConnection.mediaServer = mediaServer;
6192
6433
  }
6434
+
6435
+ if (this.isMultistream && mediaServerIp) {
6436
+ this.mediaServerIp = mediaServerIp;
6437
+ }
6193
6438
  };
6194
6439
 
6195
6440
  /**
@@ -6647,20 +6892,20 @@ export default class Meeting extends StatelessWebexPlugin {
6647
6892
  * @memberof Meetings
6648
6893
  */
6649
6894
  setupStatsAnalyzerEventHandlers = () => {
6650
- this.statsAnalyzer.on(StatsAnalyzerEventNames.MEDIA_QUALITY, (options) => {
6651
- // TODO: might have to send the same event to the developer
6652
- // Add ip address info if geo hint is present
6653
- // @ts-ignore fix type
6654
- options.data.intervalMetadata.peerReflexiveIP =
6655
- // @ts-ignore
6656
- this.webex.meetings.geoHintInfo?.clientAddress ||
6657
- options.data.intervalMetadata.peerReflexiveIP ||
6658
- MQA_STATS.DEFAULT_IP;
6895
+ this.statsAnalyzer.on(StatsAnalyzerEventNames.MEDIA_QUALITY, (event) => {
6896
+ // Add IP address from geoHintInfo if missing.
6897
+ if (event.data.intervalMetadata.maskedPeerReflexiveIP === '0.0.0.0') {
6898
+ // @ts-ignore fix type
6899
+ const clientAddressFromGeoHint = this.webex.meetings.geoHintInfo?.clientAddress;
6900
+ if (clientAddressFromGeoHint) {
6901
+ event.data.intervalMetadata.maskedPeerReflexiveIP =
6902
+ CallDiagnosticUtils.anonymizeIPAddress(clientAddressFromGeoHint);
6903
+ }
6904
+ }
6659
6905
 
6906
+ // Count members that are in the meeting.
6660
6907
  const {members} = this.getMembers().membersCollection;
6661
-
6662
- // Count members that are in the meeting
6663
- options.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
6908
+ event.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
6664
6909
  (member: Member) => member.isInMeeting
6665
6910
  ).length;
6666
6911
 
@@ -6669,10 +6914,10 @@ export default class Meeting extends StatelessWebexPlugin {
6669
6914
  name: 'client.mediaquality.event',
6670
6915
  options: {
6671
6916
  meetingId: this.id,
6672
- networkType: options.data.networkType,
6917
+ networkType: this.statsAnalyzer.getNetworkType(),
6673
6918
  },
6674
6919
  payload: {
6675
- intervals: [options.data],
6920
+ intervals: [event.data],
6676
6921
  },
6677
6922
  });
6678
6923
  });
@@ -6687,30 +6932,42 @@ export default class Meeting extends StatelessWebexPlugin {
6687
6932
  EVENT_TRIGGERS.MEETING_MEDIA_LOCAL_STARTED,
6688
6933
  data
6689
6934
  );
6690
- // @ts-ignore
6691
- this.webex.internal.newMetrics.submitClientEvent({
6692
- name: 'client.media.tx.start',
6693
- payload: {
6694
- mediaType: data.mediaType,
6695
- shareInstanceId: data.mediaType === 'share' ? this.localShareInstanceId : undefined,
6696
- },
6697
- options: {
6698
- meetingId: this.id,
6699
- },
6700
- });
6935
+ if (data.mediaType !== 'share' || !this.shareCAEventSentStatus.transmitStart) {
6936
+ // @ts-ignore
6937
+ this.webex.internal.newMetrics.submitClientEvent({
6938
+ name: 'client.media.tx.start',
6939
+ payload: {
6940
+ mediaType: data.mediaType,
6941
+ shareInstanceId: data.mediaType === 'share' ? this.localShareInstanceId : undefined,
6942
+ },
6943
+ options: {
6944
+ meetingId: this.id,
6945
+ },
6946
+ });
6947
+
6948
+ if (data.mediaType === 'share') {
6949
+ this.shareCAEventSentStatus.transmitStart = true;
6950
+ }
6951
+ }
6701
6952
  });
6702
6953
  this.statsAnalyzer.on(StatsAnalyzerEventNames.LOCAL_MEDIA_STOPPED, (data) => {
6703
- // @ts-ignore
6704
- this.webex.internal.newMetrics.submitClientEvent({
6705
- name: 'client.media.tx.stop',
6706
- payload: {
6707
- mediaType: data.mediaType,
6708
- shareInstanceId: data.mediaType === 'share' ? this.localShareInstanceId : undefined,
6709
- },
6710
- options: {
6711
- meetingId: this.id,
6712
- },
6713
- });
6954
+ if (data.mediaType !== 'share' || !this.shareCAEventSentStatus.transmitStop) {
6955
+ // @ts-ignore
6956
+ this.webex.internal.newMetrics.submitClientEvent({
6957
+ name: 'client.media.tx.stop',
6958
+ payload: {
6959
+ mediaType: data.mediaType,
6960
+ shareInstanceId: data.mediaType === 'share' ? this.localShareInstanceId : undefined,
6961
+ },
6962
+ options: {
6963
+ meetingId: this.id,
6964
+ },
6965
+ });
6966
+
6967
+ if (data.mediaType === 'share') {
6968
+ this.shareCAEventSentStatus.transmitStop = true;
6969
+ }
6970
+ }
6714
6971
  });
6715
6972
  this.statsAnalyzer.on(StatsAnalyzerEventNames.REMOTE_MEDIA_STARTED, (data) => {
6716
6973
  Trigger.trigger(
@@ -6722,57 +6979,65 @@ export default class Meeting extends StatelessWebexPlugin {
6722
6979
  EVENT_TRIGGERS.MEETING_MEDIA_REMOTE_STARTED,
6723
6980
  data
6724
6981
  );
6725
- // @ts-ignore
6726
- this.webex.internal.newMetrics.submitClientEvent({
6727
- name: 'client.media.rx.start',
6728
- payload: {
6729
- mediaType: data.mediaType,
6730
- shareInstanceId: data.mediaType === 'share' ? this.remoteShareInstanceId : undefined,
6731
- },
6732
- options: {
6733
- meetingId: this.id,
6734
- },
6735
- });
6736
-
6737
- if (data.mediaType === 'share') {
6982
+ if (data.mediaType !== 'share' || !this.shareCAEventSentStatus.receiveStart) {
6738
6983
  // @ts-ignore
6739
6984
  this.webex.internal.newMetrics.submitClientEvent({
6740
- name: 'client.media.render.start',
6985
+ name: 'client.media.rx.start',
6741
6986
  payload: {
6742
- mediaType: 'share',
6743
- shareInstanceId: this.remoteShareInstanceId,
6987
+ mediaType: data.mediaType,
6988
+ shareInstanceId: data.mediaType === 'share' ? this.remoteShareInstanceId : undefined,
6744
6989
  },
6745
6990
  options: {
6746
6991
  meetingId: this.id,
6747
6992
  },
6748
6993
  });
6994
+
6995
+ if (data.mediaType === 'share') {
6996
+ // @ts-ignore
6997
+ this.webex.internal.newMetrics.submitClientEvent({
6998
+ name: 'client.media.render.start',
6999
+ payload: {
7000
+ mediaType: 'share',
7001
+ shareInstanceId: this.remoteShareInstanceId,
7002
+ },
7003
+ options: {
7004
+ meetingId: this.id,
7005
+ },
7006
+ });
7007
+
7008
+ this.shareCAEventSentStatus.receiveStart = true;
7009
+ }
6749
7010
  }
6750
7011
  });
6751
7012
  this.statsAnalyzer.on(StatsAnalyzerEventNames.REMOTE_MEDIA_STOPPED, (data) => {
6752
- // @ts-ignore
6753
- this.webex.internal.newMetrics.submitClientEvent({
6754
- name: 'client.media.rx.stop',
6755
- payload: {
6756
- mediaType: data.mediaType,
6757
- shareInstanceId: data.mediaType === 'share' ? this.remoteShareInstanceId : undefined,
6758
- },
6759
- options: {
6760
- meetingId: this.id,
6761
- },
6762
- });
6763
-
6764
- if (data.mediaType === 'share') {
7013
+ if (data.mediaType !== 'share' || !this.shareCAEventSentStatus.receiveStop) {
6765
7014
  // @ts-ignore
6766
7015
  this.webex.internal.newMetrics.submitClientEvent({
6767
- name: 'client.media.render.stop',
7016
+ name: 'client.media.rx.stop',
6768
7017
  payload: {
6769
- mediaType: 'share',
6770
- shareInstanceId: this.remoteShareInstanceId,
7018
+ mediaType: data.mediaType,
7019
+ shareInstanceId: data.mediaType === 'share' ? this.remoteShareInstanceId : undefined,
6771
7020
  },
6772
7021
  options: {
6773
7022
  meetingId: this.id,
6774
7023
  },
6775
7024
  });
7025
+
7026
+ if (data.mediaType === 'share') {
7027
+ // @ts-ignore
7028
+ this.webex.internal.newMetrics.submitClientEvent({
7029
+ name: 'client.media.render.stop',
7030
+ payload: {
7031
+ mediaType: 'share',
7032
+ shareInstanceId: this.remoteShareInstanceId,
7033
+ },
7034
+ options: {
7035
+ meetingId: this.id,
7036
+ },
7037
+ });
7038
+
7039
+ this.shareCAEventSentStatus.receiveStop = true;
7040
+ }
6776
7041
  }
6777
7042
  });
6778
7043
  };
@@ -6789,7 +7054,10 @@ export default class Meeting extends StatelessWebexPlugin {
6789
7054
  * @param {AddMediaOptions} [options] Options for enabling/disabling audio/video
6790
7055
  * @returns {RoapMediaConnection | MultistreamRoapMediaConnection}
6791
7056
  */
6792
- private async createMediaConnection(turnServerInfo, bundlePolicy?: BundlePolicy) {
7057
+ private async createMediaConnection(
7058
+ turnServerInfo?: TurnServerInfo,
7059
+ bundlePolicy?: BundlePolicy
7060
+ ) {
6793
7061
  this.rtcMetrics = this.isMultistream
6794
7062
  ? // @ts-ignore
6795
7063
  new RtcMetrics(this.webex, {meetingId: this.id}, this.correlationId)
@@ -6814,6 +7082,13 @@ export default class Meeting extends StatelessWebexPlugin {
6814
7082
  bundlePolicy,
6815
7083
  // @ts-ignore - config coming from registerPlugin
6816
7084
  iceCandidatesTimeout: this.config.iceCandidatesGatheringTimeout,
7085
+ // @ts-ignore - config coming from registerPlugin
7086
+ disableAudioMainDtx: this.config.experimental.disableAudioMainDtx,
7087
+ // @ts-ignore - config coming from registerPlugin
7088
+ enableAudioTwcc: this.config.enableAudioTwccForMultistream,
7089
+ stopIceGatheringAfterFirstRelayCandidate:
7090
+ // @ts-ignore - config coming from registerPlugin
7091
+ this.config.stopIceGatheringAfterFirstRelayCandidate,
6817
7092
  }
6818
7093
  );
6819
7094
 
@@ -6964,12 +7239,18 @@ export default class Meeting extends StatelessWebexPlugin {
6964
7239
  },
6965
7240
  options: {
6966
7241
  meetingId: this.id,
7242
+ rawError: error,
6967
7243
  },
6968
7244
  });
6969
7245
  }
6970
- throw new Error(
7246
+
7247
+ const timedOutError = new Error(
6971
7248
  `Timed out waiting for media connection to be connected, correlationId=${this.correlationId}`
6972
7249
  );
7250
+
7251
+ timedOutError.cause = error;
7252
+
7253
+ throw timedOutError;
6973
7254
  }
6974
7255
  }
6975
7256
 
@@ -6990,6 +7271,12 @@ export default class Meeting extends StatelessWebexPlugin {
6990
7271
  networkQualityMonitor: this.networkQualityMonitor,
6991
7272
  isMultistream: this.isMultistream,
6992
7273
  });
7274
+ this.shareCAEventSentStatus = {
7275
+ transmitStart: false,
7276
+ transmitStop: false,
7277
+ receiveStart: false,
7278
+ receiveStop: false,
7279
+ };
6993
7280
  this.setupStatsAnalyzerEventHandlers();
6994
7281
  this.networkQualityMonitor.on(
6995
7282
  NetworkQualityEventNames.NETWORK_QUALITY,
@@ -7024,6 +7311,9 @@ export default class Meeting extends StatelessWebexPlugin {
7024
7311
  ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT / 1000
7025
7312
  } seconds`
7026
7313
  );
7314
+
7315
+ const error = new Error('Timed out waiting for REMOTE SDP ANSWER');
7316
+
7027
7317
  // @ts-ignore
7028
7318
  this.webex.internal.newMetrics.submitClientEvent({
7029
7319
  name: 'client.media-engine.remote-sdp-received',
@@ -7036,10 +7326,10 @@ export default class Meeting extends StatelessWebexPlugin {
7036
7326
  }),
7037
7327
  ],
7038
7328
  },
7039
- options: {meetingId: this.id, rawError: new Error('Timeout waiting for SDP answer')},
7329
+ options: {meetingId: this.id, rawError: error},
7040
7330
  });
7041
7331
 
7042
- deferSDPAnswer.reject(new Error('Timed out waiting for REMOTE SDP ANSWER'));
7332
+ deferSDPAnswer.reject(error);
7043
7333
  }, ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT);
7044
7334
 
7045
7335
  LoggerProxy.logger.info(`${LOG_HEADER} waiting for REMOTE SDP ANSWER...`);
@@ -7144,7 +7434,7 @@ export default class Meeting extends StatelessWebexPlugin {
7144
7434
  error
7145
7435
  );
7146
7436
 
7147
- throw new AddMediaFailed();
7437
+ throw new AddMediaFailed(error);
7148
7438
  }
7149
7439
  }
7150
7440
 
@@ -7557,28 +7847,33 @@ export default class Meeting extends StatelessWebexPlugin {
7557
7847
  await this.enqueueScreenShareFloorRequest();
7558
7848
  }
7559
7849
 
7560
- const {connectionType, selectedCandidatePairChanges, numTransports} =
7850
+ const {connectionType, ipVersion, selectedCandidatePairChanges, numTransports} =
7561
7851
  await this.mediaProperties.getCurrentConnectionInfo();
7562
- // @ts-ignore
7563
- const reachabilityStats = await this.webex.meetings.reachability.getReachabilityMetrics();
7852
+
7564
7853
  const iceCandidateErrors = Object.fromEntries(this.iceCandidateErrors);
7565
7854
 
7855
+ const reachabilityMetrics = await this.getMediaReachabilityMetricFields();
7856
+
7566
7857
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS, {
7567
7858
  correlation_id: this.correlationId,
7568
7859
  locus_id: this.locusUrl.split('/').pop(),
7569
7860
  connectionType,
7861
+ ipVersion,
7570
7862
  selectedCandidatePairChanges,
7571
7863
  numTransports,
7572
7864
  isMultistream: this.isMultistream,
7573
7865
  retriedWithTurnServer: this.addMediaData.retriedWithTurnServer,
7574
7866
  isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
7575
- ...reachabilityStats,
7867
+ ...reachabilityMetrics,
7576
7868
  ...iceCandidateErrors,
7577
7869
  iceCandidatesCount: this.iceCandidatesCount,
7578
7870
  });
7579
7871
  // @ts-ignore
7580
7872
  this.webex.internal.newMetrics.submitClientEvent({
7581
7873
  name: 'client.media-engine.ready',
7874
+ payload: {
7875
+ ipVersion,
7876
+ },
7582
7877
  options: {
7583
7878
  meetingId: this.id,
7584
7879
  },
@@ -7594,7 +7889,7 @@ export default class Meeting extends StatelessWebexPlugin {
7594
7889
  LoggerProxy.logger.error(`${LOG_HEADER} failed to establish media connection: `, error);
7595
7890
 
7596
7891
  // @ts-ignore
7597
- const reachabilityMetrics = await this.webex.meetings.reachability.getReachabilityMetrics();
7892
+ const reachabilityMetrics = await this.getMediaReachabilityMetricFields();
7598
7893
 
7599
7894
  const {selectedCandidatePairChanges, numTransports} =
7600
7895
  await this.mediaProperties.getCurrentConnectionInfo();
@@ -8674,6 +8969,9 @@ export default class Meeting extends StatelessWebexPlugin {
8674
8969
  LoggerProxy.logger.log(
8675
8970
  `Meeting:index#handleShareVideoStreamMuteStateChange --> Share video stream mute state changed to muted ${muted}`
8676
8971
  );
8972
+
8973
+ const shareVideoStreamSettings = this.mediaProperties?.shareVideoStream?.getSettings();
8974
+
8677
8975
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE, {
8678
8976
  correlationId: this.correlationId,
8679
8977
  muted,
@@ -8682,8 +8980,9 @@ export default class Meeting extends StatelessWebexPlugin {
8682
8980
  // SDK to TypeScript 5, which may affect other packages, use bracket notation for now, since
8683
8981
  // all we're doing here is adding metrics.
8684
8982
  // eslint-disable-next-line dot-notation
8685
- displaySurface: this.mediaProperties?.shareVideoStream?.getSettings()['displaySurface'],
8983
+ displaySurface: shareVideoStreamSettings?.['displaySurface'],
8686
8984
  isMultistream: this.isMultistream,
8985
+ frameRate: shareVideoStreamSettings?.frameRate,
8687
8986
  });
8688
8987
  };
8689
8988
 
@@ -9010,6 +9309,23 @@ export default class Meeting extends StatelessWebexPlugin {
9010
9309
  });
9011
9310
  }
9012
9311
 
9312
+ /**
9313
+ * Method to set post meeting data consent.
9314
+ *
9315
+ * @param {boolean} accept - whether consent accepted or declined
9316
+ * @returns {Promise}
9317
+ * @public
9318
+ * @memberof Meeting
9319
+ */
9320
+ public setPostMeetingDataConsent(accept: boolean) {
9321
+ return this.meetingRequest.setPostMeetingDataConsent({
9322
+ postMeetingDataConsent: accept,
9323
+ locusUrl: this.locusUrl,
9324
+ deviceUrl: this.deviceUrl,
9325
+ selfId: this.members.selfId,
9326
+ });
9327
+ }
9328
+
9013
9329
  /**
9014
9330
  * Throws if we don't have a media connection created
9015
9331
  *
@@ -9250,6 +9566,8 @@ export default class Meeting extends StatelessWebexPlugin {
9250
9566
 
9251
9567
  if (floorRequestNeeded) {
9252
9568
  this.localShareInstanceId = uuid.v4();
9569
+ this.shareCAEventSentStatus.transmitStart = false;
9570
+ this.shareCAEventSentStatus.transmitStop = false;
9253
9571
 
9254
9572
  // @ts-ignore
9255
9573
  this.webex.internal.newMetrics.submitClientEvent({
@@ -9377,4 +9695,51 @@ export default class Meeting extends StatelessWebexPlugin {
9377
9695
 
9378
9696
  return Promise.resolve();
9379
9697
  }
9698
+
9699
+ /**
9700
+ * Gets the media reachability metrics
9701
+ *
9702
+ * @returns {Promise<MediaReachabilityMetrics>}
9703
+ */
9704
+ private async getMediaReachabilityMetricFields(): Promise<MediaReachabilityMetrics> {
9705
+ const reachabilityMetrics: ReachabilityMetrics =
9706
+ // @ts-ignore
9707
+ await this.webex.meetings.reachability.getReachabilityMetrics();
9708
+
9709
+ const successKeys: Array<keyof ReachabilityMetrics> = [
9710
+ 'reachability_public_udp_success',
9711
+ 'reachability_public_tcp_success',
9712
+ 'reachability_public_xtls_success',
9713
+ 'reachability_vmn_udp_success',
9714
+ 'reachability_vmn_tcp_success',
9715
+ 'reachability_vmn_xtls_success',
9716
+ ];
9717
+
9718
+ const totalSuccessCases = successKeys.reduce((total, key) => {
9719
+ const value = reachabilityMetrics[key];
9720
+ if (typeof value === 'number') {
9721
+ return total + value;
9722
+ }
9723
+
9724
+ return total;
9725
+ }, 0);
9726
+
9727
+ const selectedSubnetFirstOctet = this.mediaServerIp?.split('.')[0];
9728
+
9729
+ let isSubnetReachable = null;
9730
+ if (totalSuccessCases > 0 && selectedSubnetFirstOctet) {
9731
+ isSubnetReachable =
9732
+ // @ts-ignore
9733
+ this.webex.meetings.reachability.isSubnetReachable(selectedSubnetFirstOctet);
9734
+ }
9735
+
9736
+ const selectedCluster = this.mediaConnections?.[0]?.mediaAgentCluster ?? null;
9737
+
9738
+ return {
9739
+ ...reachabilityMetrics,
9740
+ subnet_reachable: isSubnetReachable,
9741
+ selected_cluster: selectedCluster,
9742
+ selected_subnet: selectedSubnetFirstOctet ? `${selectedSubnetFirstOctet}.X.X.X` : null,
9743
+ };
9744
+ }
9380
9745
  }