@webex/plugin-meetings 3.0.0-beta.26 → 3.0.0-beta.261

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 +46 -8
  2. package/dist/annotation/annotation.types.js +7 -0
  3. package/dist/annotation/annotation.types.js.map +1 -0
  4. package/dist/annotation/constants.js +49 -0
  5. package/dist/annotation/constants.js.map +1 -0
  6. package/dist/annotation/index.js +342 -0
  7. package/dist/annotation/index.js.map +1 -0
  8. package/dist/breakouts/breakout.js +114 -14
  9. package/dist/breakouts/breakout.js.map +1 -1
  10. package/dist/breakouts/edit-lock-error.js +52 -0
  11. package/dist/breakouts/edit-lock-error.js.map +1 -0
  12. package/dist/breakouts/events.js +45 -0
  13. package/dist/breakouts/events.js.map +1 -0
  14. package/dist/breakouts/index.js +841 -19
  15. package/dist/breakouts/index.js.map +1 -1
  16. package/dist/breakouts/request.js +78 -0
  17. package/dist/breakouts/request.js.map +1 -0
  18. package/dist/breakouts/utils.js +67 -0
  19. package/dist/breakouts/utils.js.map +1 -0
  20. package/dist/common/errors/webex-errors.js +28 -7
  21. package/dist/common/errors/webex-errors.js.map +1 -1
  22. package/dist/common/logs/logger-proxy.js +1 -1
  23. package/dist/common/logs/logger-proxy.js.map +1 -1
  24. package/dist/common/queue.js +24 -9
  25. package/dist/common/queue.js.map +1 -1
  26. package/dist/config.js +5 -10
  27. package/dist/config.js.map +1 -1
  28. package/dist/constants.js +196 -28
  29. package/dist/constants.js.map +1 -1
  30. package/dist/controls-options-manager/enums.js +14 -2
  31. package/dist/controls-options-manager/enums.js.map +1 -1
  32. package/dist/controls-options-manager/index.js +109 -15
  33. package/dist/controls-options-manager/index.js.map +1 -1
  34. package/dist/controls-options-manager/types.js +7 -0
  35. package/dist/controls-options-manager/types.js.map +1 -0
  36. package/dist/controls-options-manager/util.js +309 -18
  37. package/dist/controls-options-manager/util.js.map +1 -1
  38. package/dist/index.js +112 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/interpretation/collection.js +23 -0
  41. package/dist/interpretation/collection.js.map +1 -0
  42. package/dist/interpretation/index.js +366 -0
  43. package/dist/interpretation/index.js.map +1 -0
  44. package/dist/interpretation/siLanguage.js +25 -0
  45. package/dist/interpretation/siLanguage.js.map +1 -0
  46. package/dist/locus-info/controlsUtils.js +91 -2
  47. package/dist/locus-info/controlsUtils.js.map +1 -1
  48. package/dist/locus-info/index.js +381 -62
  49. package/dist/locus-info/index.js.map +1 -1
  50. package/dist/locus-info/infoUtils.js +7 -1
  51. package/dist/locus-info/infoUtils.js.map +1 -1
  52. package/dist/locus-info/mediaSharesUtils.js +43 -1
  53. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  54. package/dist/locus-info/parser.js +224 -63
  55. package/dist/locus-info/parser.js.map +1 -1
  56. package/dist/locus-info/selfUtils.js +89 -14
  57. package/dist/locus-info/selfUtils.js.map +1 -1
  58. package/dist/media/index.js +58 -116
  59. package/dist/media/index.js.map +1 -1
  60. package/dist/media/properties.js +60 -121
  61. package/dist/media/properties.js.map +1 -1
  62. package/dist/meeting/in-meeting-actions.js +82 -2
  63. package/dist/meeting/in-meeting-actions.js.map +1 -1
  64. package/dist/meeting/index.js +3022 -2795
  65. package/dist/meeting/index.js.map +1 -1
  66. package/dist/meeting/locusMediaRequest.js +292 -0
  67. package/dist/meeting/locusMediaRequest.js.map +1 -0
  68. package/dist/meeting/muteState.js +230 -124
  69. package/dist/meeting/muteState.js.map +1 -1
  70. package/dist/meeting/request.js +256 -196
  71. package/dist/meeting/request.js.map +1 -1
  72. package/dist/meeting/util.js +601 -417
  73. package/dist/meeting/util.js.map +1 -1
  74. package/dist/meeting-info/index.js +70 -7
  75. package/dist/meeting-info/index.js.map +1 -1
  76. package/dist/meeting-info/meeting-info-v2.js +189 -51
  77. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  78. package/dist/meeting-info/util.js +1 -1
  79. package/dist/meeting-info/util.js.map +1 -1
  80. package/dist/meeting-info/utilv2.js +36 -36
  81. package/dist/meeting-info/utilv2.js.map +1 -1
  82. package/dist/meetings/collection.js +22 -0
  83. package/dist/meetings/collection.js.map +1 -1
  84. package/dist/meetings/index.js +372 -90
  85. package/dist/meetings/index.js.map +1 -1
  86. package/dist/meetings/meetings.types.js +7 -0
  87. package/dist/meetings/meetings.types.js.map +1 -0
  88. package/dist/meetings/request.js +2 -0
  89. package/dist/meetings/request.js.map +1 -1
  90. package/dist/meetings/util.js +88 -1
  91. package/dist/meetings/util.js.map +1 -1
  92. package/dist/member/index.js +49 -0
  93. package/dist/member/index.js.map +1 -1
  94. package/dist/member/types.js +25 -0
  95. package/dist/member/types.js.map +1 -0
  96. package/dist/member/util.js +121 -25
  97. package/dist/member/util.js.map +1 -1
  98. package/dist/members/collection.js +10 -0
  99. package/dist/members/collection.js.map +1 -1
  100. package/dist/members/index.js +86 -5
  101. package/dist/members/index.js.map +1 -1
  102. package/dist/members/request.js +106 -38
  103. package/dist/members/request.js.map +1 -1
  104. package/dist/members/types.js +15 -0
  105. package/dist/members/types.js.map +1 -0
  106. package/dist/members/util.js +316 -233
  107. package/dist/members/util.js.map +1 -1
  108. package/dist/metrics/constants.js +10 -5
  109. package/dist/metrics/constants.js.map +1 -1
  110. package/dist/metrics/index.js +1 -468
  111. package/dist/metrics/index.js.map +1 -1
  112. package/dist/multistream/mediaRequestManager.js +238 -49
  113. package/dist/multistream/mediaRequestManager.js.map +1 -1
  114. package/dist/multistream/receiveSlot.js +49 -16
  115. package/dist/multistream/receiveSlot.js.map +1 -1
  116. package/dist/multistream/receiveSlotManager.js +52 -34
  117. package/dist/multistream/receiveSlotManager.js.map +1 -1
  118. package/dist/multistream/remoteMedia.js +44 -18
  119. package/dist/multistream/remoteMedia.js.map +1 -1
  120. package/dist/multistream/remoteMediaGroup.js +60 -3
  121. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  122. package/dist/multistream/remoteMediaManager.js +209 -59
  123. package/dist/multistream/remoteMediaManager.js.map +1 -1
  124. package/dist/multistream/sendSlotManager.js +233 -0
  125. package/dist/multistream/sendSlotManager.js.map +1 -0
  126. package/dist/reachability/index.js +161 -57
  127. package/dist/reachability/index.js.map +1 -1
  128. package/dist/reachability/request.js +17 -8
  129. package/dist/reachability/request.js.map +1 -1
  130. package/dist/reconnection-manager/index.js +199 -154
  131. package/dist/reconnection-manager/index.js.map +1 -1
  132. package/dist/recording-controller/index.js +21 -2
  133. package/dist/recording-controller/index.js.map +1 -1
  134. package/dist/recording-controller/util.js +9 -8
  135. package/dist/recording-controller/util.js.map +1 -1
  136. package/dist/roap/index.js +23 -29
  137. package/dist/roap/index.js.map +1 -1
  138. package/dist/roap/request.js +112 -97
  139. package/dist/roap/request.js.map +1 -1
  140. package/dist/roap/turnDiscovery.js +96 -36
  141. package/dist/roap/turnDiscovery.js.map +1 -1
  142. package/dist/rtcMetrics/constants.js +12 -0
  143. package/dist/rtcMetrics/constants.js.map +1 -0
  144. package/dist/rtcMetrics/index.js +117 -0
  145. package/dist/rtcMetrics/index.js.map +1 -0
  146. package/dist/statsAnalyzer/index.js +51 -34
  147. package/dist/statsAnalyzer/index.js.map +1 -1
  148. package/dist/statsAnalyzer/mqaUtil.js +6 -6
  149. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  150. package/dist/types/annotation/annotation.types.d.ts +42 -0
  151. package/dist/types/annotation/constants.d.ts +31 -0
  152. package/dist/types/annotation/index.d.ts +117 -0
  153. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  154. package/dist/types/breakouts/events.d.ts +8 -0
  155. package/dist/types/breakouts/request.d.ts +22 -0
  156. package/dist/types/breakouts/utils.d.ts +15 -0
  157. package/dist/types/common/errors/webex-errors.d.ts +13 -1
  158. package/dist/types/common/queue.d.ts +9 -7
  159. package/dist/types/config.d.ts +1 -6
  160. package/dist/types/constants.d.ts +155 -21
  161. package/dist/types/controls-options-manager/enums.d.ts +11 -1
  162. package/dist/types/controls-options-manager/index.d.ts +17 -1
  163. package/dist/types/controls-options-manager/types.d.ts +43 -0
  164. package/dist/types/controls-options-manager/util.d.ts +1 -7
  165. package/dist/types/index.d.ts +6 -4
  166. package/dist/types/interpretation/collection.d.ts +5 -0
  167. package/dist/types/interpretation/index.d.ts +5 -0
  168. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  169. package/dist/types/locus-info/index.d.ts +57 -4
  170. package/dist/types/locus-info/parser.d.ts +65 -6
  171. package/dist/types/media/index.d.ts +2 -0
  172. package/dist/types/media/properties.d.ts +34 -48
  173. package/dist/types/meeting/in-meeting-actions.d.ts +82 -2
  174. package/dist/types/meeting/index.d.ts +344 -506
  175. package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
  176. package/dist/types/meeting/muteState.d.ts +99 -23
  177. package/dist/types/meeting/request.d.ts +72 -43
  178. package/dist/types/meeting/util.d.ts +101 -1
  179. package/dist/types/meeting-info/index.d.ts +13 -1
  180. package/dist/types/meeting-info/meeting-info-v2.d.ts +31 -1
  181. package/dist/types/meetings/collection.d.ts +8 -0
  182. package/dist/types/meetings/index.d.ts +86 -12
  183. package/dist/types/meetings/meetings.types.d.ts +4 -0
  184. package/dist/types/member/index.d.ts +13 -0
  185. package/dist/types/member/types.d.ts +32 -0
  186. package/dist/types/members/collection.d.ts +5 -0
  187. package/dist/types/members/index.d.ts +35 -2
  188. package/dist/types/members/request.d.ts +73 -9
  189. package/dist/types/members/types.d.ts +24 -0
  190. package/dist/types/members/util.d.ts +209 -1
  191. package/dist/types/metrics/constants.d.ts +9 -4
  192. package/dist/types/metrics/index.d.ts +4 -119
  193. package/dist/types/multistream/mediaRequestManager.d.ts +73 -5
  194. package/dist/types/multistream/receiveSlot.d.ts +16 -12
  195. package/dist/types/multistream/receiveSlotManager.d.ts +19 -4
  196. package/dist/types/multistream/remoteMedia.d.ts +8 -29
  197. package/dist/types/multistream/remoteMediaGroup.d.ts +0 -9
  198. package/dist/types/multistream/remoteMediaManager.d.ts +46 -2
  199. package/dist/types/multistream/sendSlotManager.d.ts +61 -0
  200. package/dist/types/reachability/index.d.ts +44 -7
  201. package/dist/types/reachability/request.d.ts +7 -3
  202. package/dist/types/reconnection-manager/index.d.ts +9 -0
  203. package/dist/types/recording-controller/index.d.ts +15 -1
  204. package/dist/types/recording-controller/util.d.ts +5 -4
  205. package/dist/types/roap/request.d.ts +15 -11
  206. package/dist/types/roap/turnDiscovery.d.ts +18 -1
  207. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  208. package/dist/types/rtcMetrics/index.d.ts +47 -0
  209. package/dist/types/statsAnalyzer/index.d.ts +6 -1
  210. package/package.json +23 -20
  211. package/src/annotation/annotation.types.ts +50 -0
  212. package/src/annotation/constants.ts +36 -0
  213. package/src/annotation/index.ts +328 -0
  214. package/src/breakouts/README.md +44 -14
  215. package/src/breakouts/breakout.ts +87 -9
  216. package/src/breakouts/edit-lock-error.ts +25 -0
  217. package/src/breakouts/events.ts +56 -0
  218. package/src/breakouts/index.ts +710 -10
  219. package/src/breakouts/request.ts +55 -0
  220. package/src/breakouts/utils.ts +57 -0
  221. package/src/common/errors/webex-errors.ts +27 -2
  222. package/src/common/logs/logger-proxy.ts +1 -1
  223. package/src/common/queue.ts +22 -8
  224. package/src/config.ts +4 -9
  225. package/src/constants.ts +178 -18
  226. package/src/controls-options-manager/enums.ts +12 -0
  227. package/src/controls-options-manager/index.ts +116 -21
  228. package/src/controls-options-manager/types.ts +59 -0
  229. package/src/controls-options-manager/util.ts +294 -14
  230. package/src/index.ts +40 -0
  231. package/src/interpretation/README.md +60 -0
  232. package/src/interpretation/collection.ts +19 -0
  233. package/src/interpretation/index.ts +332 -0
  234. package/src/interpretation/siLanguage.ts +18 -0
  235. package/src/locus-info/controlsUtils.ts +108 -0
  236. package/src/locus-info/index.ts +412 -59
  237. package/src/locus-info/infoUtils.ts +10 -2
  238. package/src/locus-info/mediaSharesUtils.ts +48 -0
  239. package/src/locus-info/parser.ts +231 -39
  240. package/src/locus-info/selfUtils.ts +81 -5
  241. package/src/media/index.ts +100 -122
  242. package/src/media/properties.ts +70 -108
  243. package/src/meeting/in-meeting-actions.ts +163 -3
  244. package/src/meeting/index.ts +2471 -2306
  245. package/src/meeting/locusMediaRequest.ts +313 -0
  246. package/src/meeting/muteState.ts +229 -131
  247. package/src/meeting/request.ts +172 -121
  248. package/src/meeting/util.ts +588 -394
  249. package/src/meeting-info/index.ts +79 -8
  250. package/src/meeting-info/meeting-info-v2.ts +168 -14
  251. package/src/meeting-info/util.ts +1 -1
  252. package/src/meeting-info/utilv2.ts +23 -23
  253. package/src/meetings/collection.ts +20 -0
  254. package/src/meetings/index.ts +414 -108
  255. package/src/meetings/meetings.types.ts +12 -0
  256. package/src/meetings/request.ts +2 -0
  257. package/src/meetings/util.ts +103 -4
  258. package/src/member/index.ts +49 -0
  259. package/src/member/types.ts +38 -0
  260. package/src/member/util.ts +127 -25
  261. package/src/members/collection.ts +8 -0
  262. package/src/members/index.ts +107 -6
  263. package/src/members/request.ts +97 -17
  264. package/src/members/types.ts +28 -0
  265. package/src/members/util.ts +319 -240
  266. package/src/metrics/constants.ts +9 -4
  267. package/src/metrics/index.ts +1 -490
  268. package/src/multistream/mediaRequestManager.ts +289 -79
  269. package/src/multistream/receiveSlot.ts +55 -18
  270. package/src/multistream/receiveSlotManager.ts +46 -24
  271. package/src/multistream/remoteMedia.ts +27 -2
  272. package/src/multistream/remoteMediaGroup.ts +59 -0
  273. package/src/multistream/remoteMediaManager.ts +148 -30
  274. package/src/multistream/sendSlotManager.ts +170 -0
  275. package/src/reachability/index.ts +165 -37
  276. package/src/reachability/request.ts +17 -8
  277. package/src/reconnection-manager/index.ts +81 -54
  278. package/src/recording-controller/index.ts +20 -3
  279. package/src/recording-controller/util.ts +26 -9
  280. package/src/roap/index.ts +23 -30
  281. package/src/roap/request.ts +100 -104
  282. package/src/roap/turnDiscovery.ts +51 -25
  283. package/src/rtcMetrics/constants.ts +3 -0
  284. package/src/rtcMetrics/index.ts +100 -0
  285. package/src/statsAnalyzer/index.ts +73 -35
  286. package/src/statsAnalyzer/mqaUtil.ts +8 -10
  287. package/test/integration/spec/converged-space-meetings.js +233 -0
  288. package/test/integration/spec/journey.js +320 -261
  289. package/test/integration/spec/space-meeting.js +76 -3
  290. package/test/unit/spec/annotation/index.ts +418 -0
  291. package/test/unit/spec/breakouts/breakout.ts +142 -24
  292. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  293. package/test/unit/spec/breakouts/events.ts +89 -0
  294. package/test/unit/spec/breakouts/index.ts +1545 -48
  295. package/test/unit/spec/breakouts/request.ts +104 -0
  296. package/test/unit/spec/breakouts/utils.js +72 -0
  297. package/test/unit/spec/common/queue.js +31 -2
  298. package/test/unit/spec/controls-options-manager/index.js +163 -0
  299. package/test/unit/spec/controls-options-manager/util.js +576 -60
  300. package/test/unit/spec/fixture/locus.js +1 -0
  301. package/test/unit/spec/interpretation/collection.ts +15 -0
  302. package/test/unit/spec/interpretation/index.ts +589 -0
  303. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  304. package/test/unit/spec/locus-info/controlsUtils.js +316 -43
  305. package/test/unit/spec/locus-info/index.js +1283 -33
  306. package/test/unit/spec/locus-info/infoUtils.js +37 -15
  307. package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
  308. package/test/unit/spec/locus-info/parser.js +62 -22
  309. package/test/unit/spec/locus-info/selfConstant.js +27 -4
  310. package/test/unit/spec/locus-info/selfUtils.js +208 -17
  311. package/test/unit/spec/media/index.ts +104 -37
  312. package/test/unit/spec/meeting/in-meeting-actions.ts +81 -3
  313. package/test/unit/spec/meeting/index.js +4095 -1913
  314. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  315. package/test/unit/spec/meeting/muteState.js +408 -208
  316. package/test/unit/spec/meeting/request.js +440 -45
  317. package/test/unit/spec/meeting/utils.js +679 -64
  318. package/test/unit/spec/meeting-info/index.js +293 -0
  319. package/test/unit/spec/meeting-info/meetinginfov2.js +517 -5
  320. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  321. package/test/unit/spec/meetings/collection.js +14 -0
  322. package/test/unit/spec/meetings/index.js +941 -151
  323. package/test/unit/spec/meetings/utils.js +206 -2
  324. package/test/unit/spec/member/index.js +58 -4
  325. package/test/unit/spec/member/util.js +479 -35
  326. package/test/unit/spec/members/index.js +319 -1
  327. package/test/unit/spec/members/request.js +206 -27
  328. package/test/unit/spec/members/utils.js +184 -0
  329. package/test/unit/spec/metrics/index.js +1 -50
  330. package/test/unit/spec/multistream/mediaRequestManager.ts +803 -162
  331. package/test/unit/spec/multistream/receiveSlot.ts +72 -13
  332. package/test/unit/spec/multistream/receiveSlotManager.ts +58 -28
  333. package/test/unit/spec/multistream/remoteMedia.ts +30 -0
  334. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  335. package/test/unit/spec/multistream/remoteMediaManager.ts +326 -0
  336. package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
  337. package/test/unit/spec/reachability/index.ts +343 -9
  338. package/test/unit/spec/reachability/request.js +68 -0
  339. package/test/unit/spec/reconnection-manager/index.js +84 -9
  340. package/test/unit/spec/recording-controller/index.js +294 -218
  341. package/test/unit/spec/recording-controller/util.js +223 -96
  342. package/test/unit/spec/roap/index.ts +31 -51
  343. package/test/unit/spec/roap/request.ts +203 -85
  344. package/test/unit/spec/roap/turnDiscovery.ts +48 -13
  345. package/test/unit/spec/rtcMetrics/index.ts +68 -0
  346. package/test/unit/spec/stats-analyzer/index.js +29 -2
  347. package/test/utils/constants.js +9 -0
  348. package/test/utils/integrationTestUtils.js +46 -0
  349. package/test/utils/testUtils.js +0 -45
  350. package/test/utils/webex-config.js +4 -0
  351. package/test/utils/webex-test-users.js +6 -3
  352. package/dist/meeting/effectsState.js +0 -262
  353. package/dist/meeting/effectsState.js.map +0 -1
  354. package/dist/metrics/config.js +0 -299
  355. package/dist/metrics/config.js.map +0 -1
  356. package/dist/types/meeting/effectsState.d.ts +0 -42
  357. package/dist/types/metrics/config.d.ts +0 -178
  358. package/src/index.js +0 -16
  359. package/src/meeting/effectsState.ts +0 -211
  360. package/src/metrics/config.ts +0 -495
  361. package/test/unit/spec/meeting/effectsState.js +0 -285
@@ -1,4 +1,4 @@
1
- import {isEqual} from 'lodash';
1
+ import {isEqual, assignWith, cloneDeep, isEmpty} from 'lodash';
2
2
 
3
3
  import LoggerProxy from '../common/logs/logger-proxy';
4
4
  import EventsScope from '../common/events/events-scope';
@@ -17,8 +17,6 @@ import {
17
17
  CALL_REMOVED_REASON,
18
18
  RECORDING_STATE,
19
19
  } from '../constants';
20
- import Metrics from '../metrics';
21
- import {eventType} from '../metrics/config';
22
20
  import InfoUtils from './infoUtils';
23
21
  import FullState from './fullState';
24
22
  import SelfUtils from './selfUtils';
@@ -27,6 +25,8 @@ import ControlsUtils from './controlsUtils';
27
25
  import EmbeddedAppsUtils from './embeddedAppsUtils';
28
26
  import MediaSharesUtils from './mediaSharesUtils';
29
27
  import LocusDeltaParser from './parser';
28
+ import Metrics from '../metrics';
29
+ import BEHAVIORAL_METRICS from '../metrics/constants';
30
30
 
31
31
  /**
32
32
  * @description LocusInfo extends ChildEmitter to convert locusInfo info a private emitter to parent object
@@ -59,11 +59,19 @@ export default class LocusInfo extends EventsScope {
59
59
  fullState: any;
60
60
  host: any;
61
61
  info: any;
62
+ roles: any;
62
63
  mediaShares: any;
63
64
  replace: any;
64
65
  url: any;
65
66
  services: any;
66
-
67
+ mainSessionLocusCache: any;
68
+ /**
69
+ * Constructor
70
+ * @param {function} updateMeeting callback to update the meeting object from an object
71
+ * @param {object} webex
72
+ * @param {string} meetingId
73
+ * @returns {undefined}
74
+ */
67
75
  constructor(updateMeeting, webex, meetingId) {
68
76
  super();
69
77
  this.parsedLocus = {
@@ -77,6 +85,82 @@ export default class LocusInfo extends EventsScope {
77
85
  this.locusParser = new LocusDeltaParser();
78
86
  }
79
87
 
88
+ /**
89
+ * Does a Locus sync. It tries to get the latest delta DTO or if it can't, it falls back to getting the full Locus DTO.
90
+ *
91
+ * @param {Meeting} meeting
92
+ * @returns {undefined}
93
+ */
94
+ private doLocusSync(meeting: any) {
95
+ let isDelta;
96
+ let url;
97
+
98
+ if (this.locusParser.workingCopy.syncUrl) {
99
+ url = this.locusParser.workingCopy.syncUrl;
100
+ isDelta = true;
101
+ } else {
102
+ url = meeting.locusUrl;
103
+ isDelta = false;
104
+ }
105
+
106
+ LoggerProxy.logger.info(
107
+ `Locus-info:index#doLocusSync --> doing Locus sync (getting ${
108
+ isDelta ? 'delta' : 'full'
109
+ } DTO)`
110
+ );
111
+
112
+ // return value ignored on purpose
113
+ meeting.meetingRequest
114
+ .getLocusDTO({url})
115
+ .catch((e) => {
116
+ if (isDelta) {
117
+ LoggerProxy.logger.info(
118
+ 'Locus-info:index#doLocusSync --> delta sync failed, falling back to full sync'
119
+ );
120
+
121
+ Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.LOCUS_DELTA_SYNC_FAILED, {
122
+ correlationId: meeting.correlationId,
123
+ url,
124
+ reason: e.message,
125
+ errorName: e.name,
126
+ stack: e.stack,
127
+ code: e.code,
128
+ });
129
+
130
+ isDelta = false;
131
+
132
+ return meeting.meetingRequest.getLocusDTO({url: meeting.locusUrl}).catch((err) => {
133
+ LoggerProxy.logger.info(
134
+ 'Locus-info:index#doLocusSync --> fallback full sync failed, destroying the meeting'
135
+ );
136
+ this.webex.meetings.destroy(meeting, MEETING_REMOVED_REASON.LOCUS_DTO_SYNC_FAILED);
137
+ throw err;
138
+ });
139
+ }
140
+ LoggerProxy.logger.info(
141
+ 'Locus-info:index#doLocusSync --> fallback full sync failed, destroying the meeting'
142
+ );
143
+ this.webex.meetings.destroy(meeting, MEETING_REMOVED_REASON.LOCUS_DTO_SYNC_FAILED);
144
+ throw e;
145
+ })
146
+ .then((res) => {
147
+ if (isDelta) {
148
+ if (!isEmpty(res.body)) {
149
+ meeting.locusInfo.handleLocusDelta(res.body, meeting);
150
+ } else {
151
+ LoggerProxy.logger.info(
152
+ 'Locus-info:index#doLocusSync --> received empty body from syncUrl, so we already have latest Locus DTO'
153
+ );
154
+ }
155
+ } else {
156
+ meeting.locusInfo.onFullLocus(res.body);
157
+ }
158
+ // Notify parser to resume processing delta events.
159
+ // Any deltas in the queue that have now been superseded by this sync will simply be ignored
160
+ this.locusParser.resume();
161
+ });
162
+ }
163
+
80
164
  /**
81
165
  * Apply locus delta data to meeting
82
166
  * @param {string} action Locus delta action
@@ -85,28 +169,18 @@ export default class LocusInfo extends EventsScope {
85
169
  * @returns {undefined}
86
170
  */
87
171
  applyLocusDeltaData(action: string, locus: any, meeting: any) {
88
- const {DESYNC, USE_CURRENT, USE_INCOMING} = LocusDeltaParser.loci;
172
+ const {DESYNC, USE_CURRENT, USE_INCOMING, WAIT} = LocusDeltaParser.loci;
89
173
 
90
174
  switch (action) {
91
175
  case USE_INCOMING:
92
176
  meeting.locusInfo.onDeltaLocus(locus);
93
177
  break;
94
178
  case USE_CURRENT:
95
- meeting.locusDesync = false;
96
- meeting.needToGetFullLocus = false;
179
+ case WAIT:
180
+ // do nothing
97
181
  break;
98
182
  case DESYNC:
99
- meeting.meetingRequest
100
- .getFullLocus({
101
- desync: true,
102
- locusUrl: meeting.locusUrl,
103
- })
104
- .then((res) => {
105
- meeting.locusInfo.onFullLocus(res.body);
106
- // Notify parser to resume processing delta events
107
- // now that we have full locus from DESYNC.
108
- this.locusParser.resume();
109
- });
183
+ this.doLocusSync(meeting);
110
184
  break;
111
185
  default:
112
186
  LoggerProxy.logger.info(
@@ -172,12 +246,13 @@ export default class LocusInfo extends EventsScope {
172
246
  */
173
247
  this.deltaParticipants = [];
174
248
 
249
+ this.updateLocusCache(locus);
175
250
  // above section only updates the locusInfo object
176
251
  // The below section makes sure it updates the locusInfo as well as updates the meeting object
177
252
  this.updateParticipants(locus.participants);
178
253
  // For 1:1 space meeting the conversation Url does not exist in locus.conversation
179
254
  this.updateConversationUrl(locus.conversationUrl, locus.info);
180
- this.updateControls(locus.controls);
255
+ this.updateControls(locus.controls, locus.self);
181
256
  this.updateLocusUrl(locus.url);
182
257
  this.updateFullState(locus.fullState);
183
258
  this.updateMeetingInfo(locus.info);
@@ -195,6 +270,7 @@ export default class LocusInfo extends EventsScope {
195
270
  * @memberof LocusInfo
196
271
  */
197
272
  initialSetup(locus: object) {
273
+ this.updateLocusCache(locus);
198
274
  this.onFullLocus(locus);
199
275
 
200
276
  // Change it to true after it receives it first locus object
@@ -210,7 +286,7 @@ export default class LocusInfo extends EventsScope {
210
286
  parse(meeting: any, data: any) {
211
287
  // eslint-disable-next-line @typescript-eslint/no-shadow
212
288
  const {eventType} = data;
213
-
289
+ const locus = this.getTheLocusToUpdate(data.locus);
214
290
  LoggerProxy.logger.info(`Locus-info:index#parse --> received locus data: ${eventType}`);
215
291
 
216
292
  switch (eventType) {
@@ -228,16 +304,16 @@ export default class LocusInfo extends EventsScope {
228
304
  case LOCUSEVENT.PARTICIPANT_DECLINED:
229
305
  case LOCUSEVENT.FLOOR_GRANTED:
230
306
  case LOCUSEVENT.FLOOR_RELEASED:
231
- this.onFullLocus(data.locus, eventType);
307
+ this.onFullLocus(locus, eventType);
232
308
  break;
233
309
  case LOCUSEVENT.DIFFERENCE:
234
- this.handleLocusDelta(data.locus, meeting);
310
+ this.handleLocusDelta(locus, meeting);
235
311
  break;
236
312
 
237
313
  default:
238
314
  // Why will there be a event with no eventType ????
239
315
  // we may not need this, we can get full locus
240
- this.handleLocusDelta(data.locus, meeting);
316
+ this.handleLocusDelta(locus, meeting);
241
317
  }
242
318
  }
243
319
 
@@ -259,18 +335,27 @@ export default class LocusInfo extends EventsScope {
259
335
  * @returns {object} null
260
336
  * @memberof LocusInfo
261
337
  */
262
- // eslint-disable-next-line @typescript-eslint/no-shadow
263
338
  onFullLocus(locus: any, eventType?: string) {
264
339
  if (!locus) {
265
340
  LoggerProxy.logger.error(
266
341
  'Locus-info:index#onFullLocus --> object passed as argument was invalid, continuing.'
267
342
  );
268
343
  }
344
+
345
+ if (!this.locusParser.isNewFullLocus(locus)) {
346
+ LoggerProxy.logger.info(
347
+ `Locus-info:index#onFullLocus --> ignoring old full locus DTO, eventType=${eventType}`
348
+ );
349
+
350
+ return;
351
+ }
352
+
269
353
  this.updateParticipantDeltas(locus.participants);
270
354
  this.scheduledMeeting = locus.meeting || null;
271
355
  this.participants = locus.participants;
356
+ const isReplaceMembers = ControlsUtils.isNeedReplaceMembers(this.controls, locus.controls);
272
357
  this.updateLocusInfo(locus);
273
- this.updateParticipants(locus.participants);
358
+ this.updateParticipants(locus.participants, isReplaceMembers);
274
359
  this.isMeetingActive();
275
360
  this.handleOneOnOneEvent(eventType);
276
361
  this.updateEmbeddedApps(locus.embeddedApps);
@@ -329,8 +414,9 @@ export default class LocusInfo extends EventsScope {
329
414
  * @memberof LocusInfo
330
415
  */
331
416
  onDeltaLocus(locus: any) {
417
+ const isReplaceMembers = ControlsUtils.isNeedReplaceMembers(this.controls, locus.controls);
332
418
  this.updateLocusInfo(locus);
333
- this.updateParticipants(locus.participants);
419
+ this.updateParticipants(locus.participants, isReplaceMembers);
334
420
  this.isMeetingActive();
335
421
  }
336
422
 
@@ -347,7 +433,7 @@ export default class LocusInfo extends EventsScope {
347
433
  return;
348
434
  }
349
435
 
350
- this.updateControls(locus.controls);
436
+ this.updateControls(locus.controls, locus.self);
351
437
  this.updateConversationUrl(locus.conversationUrl, locus.info);
352
438
  this.updateCreated(locus.created);
353
439
  this.updateFullState(locus.fullState);
@@ -418,10 +504,15 @@ export default class LocusInfo extends EventsScope {
418
504
  LoggerProxy.logger.warn(
419
505
  'Locus-info:index#isMeetingActive --> Call Ended, locus state is inactive.'
420
506
  );
421
- Metrics.postEvent({
422
- event: eventType.REMOTE_ENDED,
423
- meetingId: this.meetingId,
507
+
508
+ // @ts-ignore
509
+ this.webex.internal.newMetrics.submitClientEvent({
510
+ name: 'client.call.remote-ended',
511
+ options: {
512
+ meetingId: this.meetingId,
513
+ },
424
514
  });
515
+
425
516
  this.emitScoped(
426
517
  {
427
518
  file: 'locus-info',
@@ -440,9 +531,12 @@ export default class LocusInfo extends EventsScope {
440
531
  this.parsedLocus.self.state === MEETING_STATE.STATES.NOTIFIED ||
441
532
  this.parsedLocus.self.state === MEETING_STATE.STATES.JOINED)
442
533
  ) {
443
- Metrics.postEvent({
444
- event: eventType.REMOTE_ENDED,
445
- meetingId: this.meetingId,
534
+ // @ts-ignore
535
+ this.webex.internal.newMetrics.submitClientEvent({
536
+ name: 'client.call.remote-ended',
537
+ options: {
538
+ meetingId: this.meetingId,
539
+ },
446
540
  });
447
541
  this.emitScoped(
448
542
  {
@@ -464,10 +558,14 @@ export default class LocusInfo extends EventsScope {
464
558
  partner.state === MEETING_STATE.STATES.NOTIFIED ||
465
559
  partner.state === MEETING_STATE.STATES.IDLE) // Happens when user just joins and adds no Media
466
560
  ) {
467
- Metrics.postEvent({
468
- event: eventType.REMOTE_ENDED,
469
- meetingId: this.meetingId,
561
+ // @ts-ignore
562
+ this.webex.internal.newMetrics.submitClientEvent({
563
+ name: 'client.call.remote-ended',
564
+ options: {
565
+ meetingId: this.meetingId,
566
+ },
470
567
  });
568
+
471
569
  this.emitScoped(
472
570
  {
473
571
  file: 'locus-info',
@@ -490,9 +588,13 @@ export default class LocusInfo extends EventsScope {
490
588
  LoggerProxy.logger.warn(
491
589
  'Locus-info:index#isMeetingActive --> Meeting is ending due to inactive or terminating'
492
590
  );
493
- Metrics.postEvent({
494
- event: eventType.REMOTE_ENDED,
495
- meetingId: this.meetingId,
591
+
592
+ // @ts-ignore
593
+ this.webex.internal.newMetrics.submitClientEvent({
594
+ name: 'client.call.remote-ended',
595
+ options: {
596
+ meetingId: this.meetingId,
597
+ },
496
598
  });
497
599
  this.emitScoped(
498
600
  {
@@ -507,9 +609,13 @@ export default class LocusInfo extends EventsScope {
507
609
  );
508
610
  } else if (this.fullState && this.fullState.removed) {
509
611
  // user has been dropped from a meeting
510
- Metrics.postEvent({
511
- event: eventType.REMOTE_ENDED,
512
- meetingId: this.meetingId,
612
+
613
+ // @ts-ignore
614
+ this.webex.internal.newMetrics.submitClientEvent({
615
+ name: 'client.call.remote-ended',
616
+ options: {
617
+ meetingId: this.meetingId,
618
+ },
513
619
  });
514
620
  this.emitScoped(
515
621
  {
@@ -646,13 +752,13 @@ export default class LocusInfo extends EventsScope {
646
752
  }
647
753
 
648
754
  /**
649
- *
755
+ * update meeting's members
650
756
  * @param {Object} participants new participants object
651
- * @param {boolen} deltaParticpantFlag delta event
757
+ * @param {Boolean} isReplace is replace the whole members
652
758
  * @returns {Array} updatedParticipants
653
759
  * @memberof LocusInfo
654
760
  */
655
- updateParticipants(participants: object) {
761
+ updateParticipants(participants: object, isReplace?: boolean) {
656
762
  this.emitScoped(
657
763
  {
658
764
  file: 'locus-info',
@@ -665,16 +771,18 @@ export default class LocusInfo extends EventsScope {
665
771
  selfIdentity: this.parsedLocus.self && this.parsedLocus.self.selfIdentity,
666
772
  selfId: this.parsedLocus.self && this.parsedLocus.self.selfId,
667
773
  hostId: this.parsedLocus.host && this.parsedLocus.host.hostId,
774
+ isReplace,
668
775
  }
669
776
  );
670
777
  }
671
778
 
672
779
  /**
673
780
  * @param {Object} controls
781
+ * @param {Object} self
674
782
  * @returns {undefined}
675
783
  * @memberof LocusInfo
676
784
  */
677
- updateControls(controls: object) {
785
+ updateControls(controls: object, self: object) {
678
786
  if (controls && !isEqual(this.controls, controls)) {
679
787
  this.parsedLocus.controls = ControlsUtils.parse(controls);
680
788
  const {
@@ -685,10 +793,76 @@ export default class LocusInfo extends EventsScope {
685
793
  hasTranscribeChanged,
686
794
  hasEntryExitToneChanged,
687
795
  hasBreakoutChanged,
796
+ hasVideoEnabledChanged,
797
+ hasMuteOnEntryChanged,
798
+ hasShareControlChanged,
799
+ hasDisallowUnmuteChanged,
800
+ hasReactionsChanged,
801
+ hasReactionDisplayNamesChanged,
802
+ hasViewTheParticipantListChanged,
803
+ hasRaiseHandChanged,
804
+ hasVideoChanged,
805
+ hasInterpretationChanged,
688
806
  },
689
807
  current,
690
808
  } = ControlsUtils.getControls(this.controls, controls);
691
809
 
810
+ if (hasMuteOnEntryChanged) {
811
+ this.emitScoped(
812
+ {file: 'locus-info', function: 'updateControls'},
813
+ LOCUSINFO.EVENTS.CONTROLS_MUTE_ON_ENTRY_CHANGED,
814
+ {state: current.muteOnEntry}
815
+ );
816
+ }
817
+
818
+ if (hasShareControlChanged) {
819
+ this.emitScoped(
820
+ {file: 'locus-info', function: 'updateControls'},
821
+ LOCUSINFO.EVENTS.CONTROLS_SHARE_CONTROL_CHANGED,
822
+ {state: current.shareControl}
823
+ );
824
+ }
825
+
826
+ if (hasDisallowUnmuteChanged) {
827
+ this.emitScoped(
828
+ {file: 'locus-info', function: 'updateControls'},
829
+ LOCUSINFO.EVENTS.CONTROLS_DISALLOW_UNMUTE_CHANGED,
830
+ {state: current.disallowUnmute}
831
+ );
832
+ }
833
+
834
+ if (hasReactionsChanged || hasReactionDisplayNamesChanged) {
835
+ this.emitScoped(
836
+ {file: 'locus-info', function: 'updateControls'},
837
+ LOCUSINFO.EVENTS.CONTROLS_REACTIONS_CHANGED,
838
+ {state: current.reactions}
839
+ );
840
+ }
841
+
842
+ if (hasViewTheParticipantListChanged) {
843
+ this.emitScoped(
844
+ {file: 'locus-info', function: 'updateControls'},
845
+ LOCUSINFO.EVENTS.CONTROLS_VIEW_THE_PARTICIPANTS_LIST_CHANGED,
846
+ {state: current.viewTheParticipantList}
847
+ );
848
+ }
849
+
850
+ if (hasRaiseHandChanged) {
851
+ this.emitScoped(
852
+ {file: 'locus-info', function: 'updateControls'},
853
+ LOCUSINFO.EVENTS.CONTROLS_RAISE_HAND_CHANGED,
854
+ {state: current.raiseHand}
855
+ );
856
+ }
857
+
858
+ if (hasVideoChanged) {
859
+ this.emitScoped(
860
+ {file: 'locus-info', function: 'updateControls'},
861
+ LOCUSINFO.EVENTS.CONTROLS_VIDEO_CHANGED,
862
+ {state: current.video}
863
+ );
864
+ }
865
+
692
866
  if (hasRecordingChanged || hasRecordingPausedChanged) {
693
867
  let state = null;
694
868
 
@@ -750,7 +924,10 @@ export default class LocusInfo extends EventsScope {
750
924
 
751
925
  if (hasBreakoutChanged) {
752
926
  const {breakout} = current;
753
-
927
+ breakout.breakoutMoveId = SelfUtils.getReplacedBreakoutMoveId(
928
+ self,
929
+ this.webex.internal.device.url
930
+ );
754
931
  this.emitScoped(
755
932
  {
756
933
  file: 'locus-info',
@@ -763,9 +940,25 @@ export default class LocusInfo extends EventsScope {
763
940
  );
764
941
  }
765
942
 
943
+ if (hasInterpretationChanged) {
944
+ const {interpretation} = current;
945
+ this.emitScoped(
946
+ {
947
+ file: 'locus-info',
948
+ function: 'updateControls',
949
+ },
950
+ LOCUSINFO.EVENTS.CONTROLS_MEETING_INTERPRETATION_UPDATED,
951
+ {
952
+ interpretation,
953
+ }
954
+ );
955
+ }
956
+
766
957
  if (hasEntryExitToneChanged) {
767
958
  const {entryExitTone} = current;
768
959
 
960
+ this.updateMeeting({entryExitTone});
961
+
769
962
  this.emitScoped(
770
963
  {
771
964
  file: 'locus-info',
@@ -776,8 +969,26 @@ export default class LocusInfo extends EventsScope {
776
969
  entryExitTone,
777
970
  }
778
971
  );
972
+ }
779
973
 
780
- this.updateMeeting({entryExitTone});
974
+ // videoEnabled is handled differently than other controls,
975
+ // to fit with audio mute status logic
976
+ if (hasVideoEnabledChanged) {
977
+ const {videoEnabled} = current;
978
+
979
+ this.updateMeeting({unmuteVideoAllowed: videoEnabled});
980
+
981
+ this.emitScoped(
982
+ {
983
+ file: 'locus-info',
984
+ function: 'updateControls',
985
+ },
986
+ LOCUSINFO.EVENTS.SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED,
987
+ {
988
+ // muted: not part of locus.controls
989
+ unmuteAllowed: videoEnabled,
990
+ }
991
+ );
781
992
  }
782
993
 
783
994
  this.controls = controls;
@@ -918,20 +1129,14 @@ export default class LocusInfo extends EventsScope {
918
1129
  * @memberof LocusInfo
919
1130
  */
920
1131
  updateMeetingInfo(info: object, self?: object) {
921
- if (info && !isEqual(this.info, info)) {
922
- const roles = self ? SelfUtils.getRoles(self) : this.parsedLocus.self?.roles || [];
1132
+ const roles = self ? SelfUtils.getRoles(self) : this.parsedLocus.self?.roles || [];
1133
+ if (
1134
+ (info && !isEqual(this.info, info)) ||
1135
+ (roles.length && !isEqual(this.roles, roles) && info)
1136
+ ) {
923
1137
  const isJoined = SelfUtils.isJoined(self || this.parsedLocus.self);
924
1138
  const parsedInfo = InfoUtils.getInfos(this.parsedLocus.info, info, roles, isJoined);
925
1139
 
926
- this.emitScoped(
927
- {
928
- file: 'locus-info',
929
- function: 'updateMeetingInfo',
930
- },
931
- LOCUSINFO.EVENTS.MEETING_INFO_UPDATED,
932
- {info: parsedInfo.current, self}
933
- );
934
-
935
1140
  if (parsedInfo.updates.isLocked) {
936
1141
  this.emitScoped(
937
1142
  {
@@ -957,7 +1162,16 @@ export default class LocusInfo extends EventsScope {
957
1162
  this.parsedLocus.info = parsedInfo.current;
958
1163
  // Parses the info and adds necessary values
959
1164
  this.updateMeeting(parsedInfo.current);
1165
+
1166
+ this.emitScoped(
1167
+ {
1168
+ file: 'locus-info',
1169
+ function: 'updateMeetingInfo',
1170
+ },
1171
+ LOCUSINFO.EVENTS.MEETING_INFO_UPDATED
1172
+ );
960
1173
  }
1174
+ this.roles = roles;
961
1175
  }
962
1176
 
963
1177
  /**
@@ -1099,6 +1313,20 @@ export default class LocusInfo extends EventsScope {
1099
1313
  );
1100
1314
  }
1101
1315
 
1316
+ if (parsedSelves.updates.interpretationChanged) {
1317
+ this.emitScoped(
1318
+ {
1319
+ file: 'locus-info',
1320
+ function: 'updateSelf',
1321
+ },
1322
+ LOCUSINFO.EVENTS.SELF_MEETING_INTERPRETATION_CHANGED,
1323
+ {
1324
+ interpretation: parsedSelves.current.interpretation,
1325
+ selfParticipantId: parsedSelves.current.selfId,
1326
+ }
1327
+ );
1328
+ }
1329
+
1102
1330
  if (parsedSelves.updates.isMediaInactiveOrReleased) {
1103
1331
  this.emitScoped(
1104
1332
  {
@@ -1120,6 +1348,31 @@ export default class LocusInfo extends EventsScope {
1120
1348
  self
1121
1349
  );
1122
1350
  }
1351
+
1352
+ if (parsedSelves.updates.isRolesChanged) {
1353
+ this.emitScoped(
1354
+ {
1355
+ file: 'locus-info',
1356
+ function: 'updateSelf',
1357
+ },
1358
+ LOCUSINFO.EVENTS.SELF_ROLES_CHANGED,
1359
+ {oldRoles: parsedSelves.previous?.roles, newRoles: parsedSelves.current?.roles}
1360
+ );
1361
+ }
1362
+
1363
+ if (parsedSelves.updates.isVideoMutedByOthersChanged) {
1364
+ this.emitScoped(
1365
+ {
1366
+ file: 'locus-info',
1367
+ function: 'updateSelf',
1368
+ },
1369
+ LOCUSINFO.EVENTS.SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED,
1370
+ {
1371
+ muted: parsedSelves.current.remoteVideoMuted,
1372
+ // unmuteAllowed: not part of .self
1373
+ }
1374
+ );
1375
+ }
1123
1376
  if (parsedSelves.updates.localAudioUnmuteRequiredByServer) {
1124
1377
  this.emitScoped(
1125
1378
  {
@@ -1334,4 +1587,104 @@ export default class LocusInfo extends EventsScope {
1334
1587
  this.identities = identities;
1335
1588
  }
1336
1589
  }
1590
+
1591
+ /**
1592
+ * check the locus is main session's one or not, if is main session's, update main session cache
1593
+ * @param {Object} locus
1594
+ * @returns {undefined}
1595
+ * @memberof LocusInfo
1596
+ */
1597
+ updateLocusCache(locus: any) {
1598
+ const isMainSessionDTO = ControlsUtils.isMainSessionDTO(locus);
1599
+ if (isMainSessionDTO) {
1600
+ this.updateMainSessionLocusCache(locus);
1601
+ }
1602
+ }
1603
+
1604
+ /**
1605
+ * if return from breakout to main session, need to use cached main session DTO since locus won't send the full locus (participants)
1606
+ * if join breakout from main session, need to query main locus url (if response with 403 means no privilege, need to clear the cache)
1607
+ * @param {Object} newLocus
1608
+ * @returns {Object}
1609
+ * @memberof LocusInfo
1610
+ */
1611
+ getTheLocusToUpdate(newLocus: any) {
1612
+ const switchStatus = ControlsUtils.getSessionSwitchStatus(this.controls, newLocus?.controls);
1613
+ if (switchStatus.isReturnToMain && this.mainSessionLocusCache) {
1614
+ return cloneDeep(this.mainSessionLocusCache);
1615
+ }
1616
+ if (switchStatus.isJoinToBreakout) {
1617
+ this.emitScoped(
1618
+ {
1619
+ file: 'locus-info',
1620
+ function: 'updateControls',
1621
+ },
1622
+ LOCUSINFO.EVENTS.CONTROLS_JOIN_BREAKOUT_FROM_MAIN,
1623
+ {
1624
+ mainLocusUrl: this.url,
1625
+ }
1626
+ );
1627
+ }
1628
+
1629
+ return newLocus;
1630
+ }
1631
+
1632
+ /**
1633
+ * merge participants by participant id
1634
+ * @param {Array} participants
1635
+ * @param {Array} sourceParticipants
1636
+ * @returns {Array} merged participants
1637
+ * @memberof LocusInfo
1638
+ */
1639
+ // eslint-disable-next-line class-methods-use-this
1640
+ mergeParticipants(participants, sourceParticipants) {
1641
+ if (!sourceParticipants || !sourceParticipants.length) return participants;
1642
+ if (!participants || !participants.length) {
1643
+ return sourceParticipants;
1644
+ }
1645
+ sourceParticipants.forEach((participant) => {
1646
+ const existIndex = participants.findIndex((p) => p.id === participant.id);
1647
+ if (existIndex > -1) {
1648
+ participants.splice(existIndex, 1, participant);
1649
+ } else {
1650
+ participants.push(participant);
1651
+ }
1652
+ });
1653
+
1654
+ return participants;
1655
+ }
1656
+
1657
+ /**
1658
+ * need cache main sessions' participants since locus will not send the full list when cohost/host leave breakout
1659
+ * @param {Object} mainLocus
1660
+ * @returns {undefined}
1661
+ * @memberof LocusInfo
1662
+ */
1663
+ updateMainSessionLocusCache(mainLocus: any) {
1664
+ if (!mainLocus) {
1665
+ return;
1666
+ }
1667
+ const locusClone = cloneDeep(mainLocus);
1668
+ if (this.mainSessionLocusCache) {
1669
+ // shallow merge and do special merge for participants
1670
+ assignWith(this.mainSessionLocusCache, locusClone, (objValue, srcValue, key) => {
1671
+ if (key === 'participants') {
1672
+ return this.mergeParticipants(objValue, srcValue);
1673
+ }
1674
+
1675
+ return srcValue || objValue;
1676
+ });
1677
+ } else {
1678
+ this.mainSessionLocusCache = locusClone;
1679
+ }
1680
+ }
1681
+
1682
+ /**
1683
+ * clear main session cache
1684
+ * @returns {undefined}
1685
+ * @memberof LocusInfo
1686
+ */
1687
+ clearMainSessionLocusCache() {
1688
+ this.mainSessionLocusCache = null;
1689
+ }
1337
1690
  }