@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
@@ -4,9 +4,11 @@
4
4
 
5
5
  /* eslint-disable class-methods-use-this */
6
6
  /* globals window */
7
- import _ from 'lodash';
7
+ import {uniq, mapValues, pick} from 'lodash';
8
8
 
9
9
  import LoggerProxy from '../common/logs/logger-proxy';
10
+ import MeetingUtil from '../meeting/util';
11
+
10
12
  import {ICE_GATHERING_STATE, CONNECTION_STATE, REACHABILITY} from '../constants';
11
13
 
12
14
  import ReachabilityRequest from './request';
@@ -14,6 +16,39 @@ import ReachabilityRequest from './request';
14
16
  const DEFAULT_TIMEOUT = 3000;
15
17
  const VIDEO_MESH_TIMEOUT = 1000;
16
18
 
19
+ // result for a specific transport protocol (like udp or tcp)
20
+ export type TransportResult = {
21
+ reachable: 'true' | 'false';
22
+ latencyInMilliseconds?: string;
23
+ clientMediaIPs?: string[];
24
+ untested?: 'true';
25
+ };
26
+
27
+ // reachability result for a specifc media cluster
28
+ type ReachabilityResult = {
29
+ udp: TransportResult;
30
+ tcp: TransportResult;
31
+ xtls: {
32
+ untested: 'true';
33
+ };
34
+ };
35
+ // this is the type that is required by the backend when we send them reachability results
36
+ export type ReachabilityResults = Record<string, ReachabilityResult>;
37
+
38
+ // this is the type used by Reachability class internally and stored in local storage
39
+ type InternalReachabilityResults = Record<
40
+ string,
41
+ ReachabilityResult & {
42
+ isVideoMesh?: boolean;
43
+ }
44
+ >;
45
+
46
+ export type ICECandidateResult = {
47
+ clusterId: string;
48
+ isVideoMesh: boolean;
49
+ elapsed?: string | null;
50
+ publicIPs?: string[];
51
+ };
17
52
  /**
18
53
  * @class Reachability
19
54
  * @export
@@ -58,16 +93,20 @@ export default class Reachability {
58
93
  * @async
59
94
  * @memberof Reachability
60
95
  */
61
- public async gatherReachability() {
96
+ public async gatherReachability(): Promise<InternalReachabilityResults> {
62
97
  this.setup();
63
98
 
64
99
  // Remove stored reachability results to ensure no stale data
65
100
  // @ts-ignore
66
- await this.webex.boundedStorage.del(this.namespace, REACHABILITY.localStorage);
101
+ await this.webex.boundedStorage.del(this.namespace, REACHABILITY.localStorageResult);
102
+ // @ts-ignore
103
+ await this.webex.boundedStorage.del(this.namespace, REACHABILITY.localStorageJoinCookie);
67
104
 
68
105
  // Fetch clusters and measure latency
69
106
  try {
70
- const clusters = await this.reachabilityRequest.getClusters();
107
+ const {clusters, joinCookie} = await this.reachabilityRequest.getClusters(
108
+ MeetingUtil.getIpVersion(this.webex)
109
+ );
71
110
 
72
111
  // Perform Reachability Check
73
112
  const results = await this.performReachabilityCheck(clusters);
@@ -75,9 +114,15 @@ export default class Reachability {
75
114
  // @ts-ignore
76
115
  await this.webex.boundedStorage.put(
77
116
  this.namespace,
78
- REACHABILITY.localStorage,
117
+ REACHABILITY.localStorageResult,
79
118
  JSON.stringify(results)
80
119
  );
120
+ // @ts-ignore
121
+ await this.webex.boundedStorage.put(
122
+ this.namespace,
123
+ REACHABILITY.localStorageJoinCookie,
124
+ JSON.stringify(joinCookie)
125
+ );
81
126
 
82
127
  LoggerProxy.logger.log(
83
128
  'Reachability:index#gatherReachability --> Reachability checks completed'
@@ -93,25 +138,59 @@ export default class Reachability {
93
138
  }
94
139
  }
95
140
 
141
+ /**
142
+ * Reachability results as an object in the format that backend expects
143
+ *
144
+ * @returns {any} reachability results that need to be sent to the backend
145
+ */
146
+ async getReachabilityResults(): Promise<ReachabilityResults | undefined> {
147
+ let results: ReachabilityResults;
148
+
149
+ // these are the only props that backend needs in the reachability results:
150
+ const reachabilityResultsProps: Array<keyof ReachabilityResult> = ['udp', 'tcp', 'xtls'];
151
+
152
+ try {
153
+ // @ts-ignore
154
+ const resultsJson = await this.webex.boundedStorage.get(
155
+ REACHABILITY.namespace,
156
+ REACHABILITY.localStorageResult
157
+ );
158
+
159
+ const internalResults: InternalReachabilityResults = JSON.parse(resultsJson);
160
+
161
+ results = mapValues(internalResults, (result) => pick(result, reachabilityResultsProps));
162
+ } catch (e) {
163
+ // empty storage, that's ok
164
+ LoggerProxy.logger.warn(
165
+ 'Roap:request#attachReachabilityData --> Error parsing reachability data: ',
166
+ e
167
+ );
168
+ }
169
+
170
+ return results;
171
+ }
172
+
96
173
  /**
97
174
  * fetches reachability data and checks for cluster reachability
98
175
  * @returns {boolean}
99
176
  * @public
100
177
  * @memberof Reachability
101
178
  */
102
- async isAnyClusterReachable() {
179
+ async isAnyPublicClusterReachable() {
103
180
  let reachable = false;
104
181
  // @ts-ignore
105
182
  const reachabilityData = await this.webex.boundedStorage
106
- .get(this.namespace, REACHABILITY.localStorage)
183
+ .get(this.namespace, REACHABILITY.localStorageResult)
107
184
  .catch(() => {});
108
185
 
109
186
  if (reachabilityData) {
110
187
  try {
111
- const reachabilityResults = JSON.parse(reachabilityData);
188
+ const reachabilityResults: InternalReachabilityResults = JSON.parse(reachabilityData);
112
189
 
113
190
  reachable = Object.values(reachabilityResults).some(
114
- (result: any) => result.udp?.reachable === 'true' || result.tcp?.reachable === 'true'
191
+ (result) =>
192
+ !result.isVideoMesh &&
193
+ (result.udp?.reachable === 'true' || result.tcp?.reachable === 'true')
115
194
  );
116
195
  } catch (e) {
117
196
  LoggerProxy.logger.error(
@@ -131,7 +210,7 @@ export default class Reachability {
131
210
  * @memberof Reachability
132
211
  */
133
212
  private buildPeerConnectionConfig(cluster: any) {
134
- const iceServers = _.uniq([...cluster.udp, ...cluster.tcp]).map((url) => ({
213
+ const iceServers = uniq(cluster.udp).map((url) => ({
135
214
  username: '',
136
215
  credential: '',
137
216
  urls: [url],
@@ -192,7 +271,7 @@ export default class Reachability {
192
271
  * @private
193
272
  * @memberof Reachability
194
273
  */
195
- private getLocalSDPForClusters(clusterList: object) {
274
+ private getLocalSDPForClusters(clusterList: object): Promise<InternalReachabilityResults> {
196
275
  let clusters: any[] = [...Object.keys(clusterList)];
197
276
 
198
277
  clusters = clusters.map(async (key) => {
@@ -205,18 +284,17 @@ export default class Reachability {
205
284
  peerConnection.begin = Date.now();
206
285
  peerConnection.setLocalDescription(description);
207
286
 
208
- return this.iceGatheringState(
209
- peerConnection,
210
- cluster.isVideoMesh ? VIDEO_MESH_TIMEOUT : DEFAULT_TIMEOUT
211
- ).catch((iceGatheringStateError) => {
212
- LoggerProxy.logger.log(
213
- `Reachability:index#getLocalSDPForClusters --> Error in getLocalSDP : ${iceGatheringStateError}`
214
- );
215
- });
287
+ return this.iceGatheringState(peerConnection, cluster.isVideoMesh).catch(
288
+ (iceGatheringStateError) => {
289
+ LoggerProxy.logger.log(
290
+ `Reachability:index#getLocalSDPForClusters --> Error in getLocalSDP : ${iceGatheringStateError}`
291
+ );
292
+ }
293
+ );
216
294
  });
217
295
 
218
296
  return Promise.all(clusters)
219
- .then(this.parseIceResultsToReachabilityResults)
297
+ .then(this.parseIceResultsToInternalReachabilityResults)
220
298
  .then((reachabilityLatencyResults) => {
221
299
  this.logUnreachableClusters();
222
300
 
@@ -292,6 +370,8 @@ export default class Reachability {
292
370
  `Reachability:index#onIceCandidate --> Successfully pinged ${peerConnection.key}:`,
293
371
  elapsed
294
372
  );
373
+ // order is important
374
+ this.addPublicIP(peerConnection, e.candidate.address);
295
375
  this.setLatencyAndClose(peerConnection, elapsed);
296
376
  }
297
377
  };
@@ -303,14 +383,17 @@ export default class Reachability {
303
383
  * speed.
304
384
  * @private
305
385
  * @param {RTCPeerConnection} peerConnection
306
- * @param {number} timeout
386
+ * @param {boolean} isVideoMesh
307
387
  * @returns {Promise}
308
388
  */
309
- private iceGatheringState(peerConnection: RTCPeerConnection, timeout: number) {
389
+ private iceGatheringState(peerConnection: RTCPeerConnection, isVideoMesh: boolean) {
310
390
  const ELAPSED = 'elapsed';
311
391
 
312
- return new Promise((resolve) => {
392
+ const timeout = isVideoMesh ? VIDEO_MESH_TIMEOUT : DEFAULT_TIMEOUT;
393
+
394
+ return new Promise<ICECandidateResult>((resolve) => {
313
395
  const peerConnectionProxy = new window.Proxy(peerConnection, {
396
+ // eslint-disable-next-line require-jsdoc
314
397
  get(target, property) {
315
398
  const targetMember = target[property];
316
399
 
@@ -323,8 +406,14 @@ export default class Reachability {
323
406
  set: (target, property, value) => {
324
407
  // only intercept elapsed property
325
408
  if (property === ELAPSED) {
326
- // @ts-ignore
327
- resolve({clusterId: peerConnection.key, elapsed: value});
409
+ resolve({
410
+ // @ts-ignore
411
+ clusterId: peerConnection.key,
412
+ isVideoMesh,
413
+ // @ts-ignore
414
+ publicIPs: target.publicIPs,
415
+ elapsed: value,
416
+ });
328
417
 
329
418
  return true;
330
419
  }
@@ -345,6 +434,8 @@ export default class Reachability {
345
434
 
346
435
  // Close any open peerConnections
347
436
  if (peerConnectionProxy.connectionState !== CLOSED) {
437
+ // order is important
438
+ this.addPublicIP(peerConnectionProxy, null);
348
439
  this.setLatencyAndClose(peerConnectionProxy, null);
349
440
  }
350
441
  }, timeout);
@@ -369,29 +460,39 @@ export default class Reachability {
369
460
 
370
461
  /**
371
462
  * Calculates time to establish connection
372
- * @param {array} iceResults iceResults
463
+ * @param {Array<ICECandidateResult>} iceResults iceResults
373
464
  * @returns {object} reachabilityMap
374
- * @private
465
+ * @protected
375
466
  * @memberof Reachability
376
467
  */
377
- private parseIceResultsToReachabilityResults(iceResults: Array<any>) {
468
+ protected parseIceResultsToInternalReachabilityResults(
469
+ iceResults: Array<ICECandidateResult>
470
+ ): InternalReachabilityResults {
378
471
  const reachabilityMap = {};
379
472
 
380
- iceResults.forEach(({clusterId, elapsed}) => {
381
- let latencyResult;
473
+ iceResults.forEach(({clusterId, isVideoMesh, elapsed, publicIPs}) => {
474
+ const latencyResult = {};
382
475
 
383
- if (elapsed === null) {
384
- latencyResult = {reachable: 'false'};
476
+ if (!elapsed) {
477
+ Object.assign(latencyResult, {reachable: 'false'});
385
478
  } else {
386
- latencyResult = {
479
+ Object.assign(latencyResult, {
387
480
  reachable: 'true',
388
481
  latencyInMilliseconds: elapsed.toString(),
389
- };
482
+ });
483
+ }
484
+
485
+ if (publicIPs) {
486
+ Object.assign(latencyResult, {
487
+ clientMediaIPs: publicIPs,
488
+ });
390
489
  }
391
490
 
392
491
  reachabilityMap[clusterId] = {
393
492
  udp: latencyResult,
394
- tcp: latencyResult,
493
+ tcp: {untested: 'true'},
494
+ xtls: {untested: 'true'},
495
+ isVideoMesh,
395
496
  };
396
497
  });
397
498
 
@@ -401,11 +502,11 @@ export default class Reachability {
401
502
  /**
402
503
  * fetches reachability data
403
504
  * @param {object} clusterList
404
- * @returns {Promise<localSDPData>} reachability check results
505
+ * @returns {Promise<InternalReachabilityResults>} reachability check results
405
506
  * @private
406
507
  * @memberof Reachability
407
508
  */
408
- private performReachabilityCheck(clusterList: object) {
509
+ private performReachabilityCheck(clusterList: object): Promise<InternalReachabilityResults> {
409
510
  if (!clusterList || !Object.keys(clusterList).length) {
410
511
  return Promise.resolve({});
411
512
  }
@@ -432,6 +533,33 @@ export default class Reachability {
432
533
  });
433
534
  }
434
535
 
536
+ /**
537
+ * Adds public IP (client media IPs)
538
+ * @param {RTCPeerConnection} peerConnection
539
+ * @param {string} publicIP
540
+ * @returns {void}
541
+ */
542
+ protected addPublicIP(peerConnection: RTCPeerConnection, publicIP?: string | null) {
543
+ const modifiedPeerConnection: RTCPeerConnection & {publicIPs?: string[]} = peerConnection;
544
+ const {CLOSED} = CONNECTION_STATE;
545
+
546
+ if (modifiedPeerConnection.connectionState === CLOSED) {
547
+ LoggerProxy.logger.log(
548
+ `Reachability:index#addPublicIP --> Attempting to set publicIP of ${publicIP} on closed peerConnection.`
549
+ );
550
+ }
551
+
552
+ if (publicIP) {
553
+ if (modifiedPeerConnection.publicIPs) {
554
+ modifiedPeerConnection.publicIPs.push(publicIP);
555
+ } else {
556
+ modifiedPeerConnection.publicIPs = [publicIP];
557
+ }
558
+ } else {
559
+ modifiedPeerConnection.publicIPs = null;
560
+ }
561
+ }
562
+
435
563
  /**
436
564
  * Records latency and closes the peerConnection
437
565
  * @param {RTCPeerConnection} peerConnection
@@ -1,5 +1,5 @@
1
1
  import LoggerProxy from '../common/logs/logger-proxy';
2
- import {HTTP_VERBS, RESOURCE, API} from '../constants';
2
+ import {HTTP_VERBS, RESOURCE, API, IP_VERSION} from '../constants';
3
3
 
4
4
  export interface ClusterNode {
5
5
  isVideoMesh: boolean;
@@ -28,31 +28,40 @@ class ReachabilityRequest {
28
28
  }
29
29
 
30
30
  /**
31
- * gets the cluster information
31
+ * Gets the cluster information
32
32
  *
33
- * @param {boolean} includeVideoMesh whether to include the video mesh clusters in the result or not
33
+ * @param {IP_VERSION} ipVersion information about current ip network we're on
34
34
  * @returns {Promise}
35
35
  */
36
- getClusters = (): Promise<ClusterList> =>
36
+ getClusters = (ipVersion?: IP_VERSION): Promise<{clusters: ClusterList; joinCookie: any}> =>
37
37
  this.webex
38
38
  .request({
39
39
  method: HTTP_VERBS.GET,
40
40
  shouldRefreshAccessToken: false,
41
41
  api: API.CALLIOPEDISCOVERY,
42
42
  resource: RESOURCE.CLUSTERS,
43
+ qs: {
44
+ JCSupport: 1,
45
+ ipver: ipVersion,
46
+ },
43
47
  })
44
48
  .then((res) => {
45
- const {clusters} = res.body;
49
+ const {clusters, joinCookie} = res.body;
46
50
 
47
51
  Object.keys(clusters).forEach((key) => {
48
- clusters[key].isVideoMesh = res.body.clusterClasses?.hybridMedia?.includes(key);
52
+ clusters[key].isVideoMesh = !!res.body.clusterClasses?.hybridMedia?.includes(key);
49
53
  });
50
54
 
51
55
  LoggerProxy.logger.log(
52
- `Reachability:request#getClusters --> get clusters successful:${JSON.stringify(clusters)}`
56
+ `Reachability:request#getClusters --> get clusters (ipver=${ipVersion}) successful:${JSON.stringify(
57
+ clusters
58
+ )}`
53
59
  );
54
60
 
55
- return clusters;
61
+ return {
62
+ clusters,
63
+ joinCookie,
64
+ };
56
65
  });
57
66
 
58
67
  /**
@@ -18,10 +18,9 @@ import {
18
18
  import BEHAVIORAL_METRICS from '../metrics/constants';
19
19
  import ReconnectionError from '../common/errors/reconnection';
20
20
  import ReconnectInProgress from '../common/errors/reconnection-in-progress';
21
- import {eventType, reconnection, errorObjects} from '../metrics/config';
22
- import Media from '../media';
23
21
  import Metrics from '../metrics';
24
22
  import Meeting from '../meeting';
23
+ import {MediaRequestManager} from '../multistream/mediaRequestManager';
25
24
 
26
25
  /**
27
26
  * Used to indicate that the reconnect logic needs to be retried.
@@ -231,6 +230,32 @@ export default class ReconnectionManager {
231
230
  this.meeting = null;
232
231
  }
233
232
 
233
+ /**
234
+ * Stop the local share stream.
235
+ *
236
+ * @param {string} reason a {@link SHARE_STOPPED_REASON}
237
+ * @returns {undefined}
238
+ * @private
239
+ * @memberof ReconnectionManager
240
+ */
241
+ private async stopLocalShareStream(reason: string) {
242
+ await this.meeting.unpublishStreams([
243
+ this.meeting.mediaProperties.shareVideoStream,
244
+ this.meeting.mediaProperties.shareAudioStream,
245
+ ]);
246
+ Trigger.trigger(
247
+ this.meeting,
248
+ {
249
+ file: 'reconnection-manager/index',
250
+ function: 'stopLocalShareStream',
251
+ },
252
+ EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
253
+ {
254
+ reason,
255
+ }
256
+ );
257
+ }
258
+
234
259
  /**
235
260
  * @public
236
261
  * @memberof ReconnectionManager
@@ -302,9 +327,13 @@ export default class ReconnectionManager {
302
327
  LoggerProxy.logger.info(
303
328
  'ReconnectionManager:index#reconnect --> Sending reconnect start metric.'
304
329
  );
305
- Metrics.postEvent({
306
- event: eventType.MEDIA_RECONNECTING,
307
- meeting: this.meeting,
330
+
331
+ // @ts-ignore
332
+ this.webex.internal.newMetrics.submitClientEvent({
333
+ name: 'client.media.reconnecting',
334
+ options: {
335
+ meetingId: this.meeting.id,
336
+ },
308
337
  });
309
338
  }
310
339
 
@@ -314,10 +343,16 @@ export default class ReconnectionManager {
314
343
  LoggerProxy.logger.info(
315
344
  'ReconnectionManager:index#reconnect --> Sending reconnect success metric.'
316
345
  );
317
- Metrics.postEvent({
318
- event: eventType.MEDIA_RECOVERED,
319
- meeting: this.meeting,
320
- data: {recoveredBy: reconnection.RECOVERED_BY_NEW},
346
+
347
+ // @ts-ignore
348
+ this.webex.internal.newMetrics.submitClientEvent({
349
+ name: 'client.media.recovered',
350
+ payload: {
351
+ recoveredBy: 'new',
352
+ },
353
+ options: {
354
+ meetingId: this.meeting.id,
355
+ },
321
356
  });
322
357
  })
323
358
  .catch((reconnectError) => {
@@ -341,23 +376,24 @@ export default class ReconnectionManager {
341
376
  'ReconnectionManager:index#reconnect --> Sending reconnect abort metric.'
342
377
  );
343
378
 
344
- const reconnectMetric = {
345
- event: eventType.CALL_ABORTED,
346
- meeting: this.meeting,
347
- data: {
379
+ // @ts-ignore
380
+ this.webex.internal.newMetrics.submitClientEvent({
381
+ name: 'client.call.aborted',
382
+ payload: {
348
383
  errors: [
349
384
  {
350
- category: errorObjects.category.expected,
385
+ category: 'expected',
351
386
  errorCode: 2008,
352
387
  fatal: true,
353
- name: errorObjects.name.mediaEngine,
388
+ name: 'media-engine',
354
389
  shownToUser: false,
355
390
  },
356
391
  ],
357
392
  },
358
- };
359
-
360
- Metrics.postEvent(reconnectMetric);
393
+ options: {
394
+ meetingId: this.meeting.id,
395
+ },
396
+ });
361
397
  if (reconnectError instanceof NeedsRejoinError) {
362
398
  // send call aborded event with catogery as expected as we are trying to rejoin
363
399
 
@@ -385,6 +421,12 @@ export default class ReconnectionManager {
385
421
  'ReconnectionManager:index#executeReconnection --> Attempting to reconnect to meeting.'
386
422
  );
387
423
 
424
+ const wasSharing = this.meeting.shareStatus === SHARE_STATUS.LOCAL_SHARE_ACTIVE;
425
+
426
+ if (wasSharing) {
427
+ await this.stopLocalShareStream(SHARE_STOPPED_REASON.MEDIA_RECONNECTION);
428
+ }
429
+
388
430
  if (networkDisconnect) {
389
431
  try {
390
432
  await this.reconnectMercuryWebSocket();
@@ -401,29 +443,29 @@ export default class ReconnectionManager {
401
443
  }
402
444
  }
403
445
 
404
- const wasSharing = this.meeting.shareStatus === SHARE_STATUS.LOCAL_SHARE_ACTIVE;
405
-
406
- try {
407
- LoggerProxy.logger.info(
408
- 'ReconnectionManager:index#executeReconnection --> Updating meeting data from server.'
409
- );
410
- await this.webex.meetings.syncMeetings();
411
- } catch (syncError) {
412
- LoggerProxy.logger.info(
413
- 'ReconnectionManager:index#executeReconnection --> Unable to sync meetings, reconnecting.',
414
- syncError
415
- );
416
- throw new NeedsRetryError(syncError);
446
+ if (!this.webex.credentials.isUnverifiedGuest) {
447
+ try {
448
+ LoggerProxy.logger.info(
449
+ 'ReconnectionManager:index#executeReconnection --> Updating meeting data from server.'
450
+ );
451
+ await this.webex.meetings.syncMeetings();
452
+ } catch (syncError) {
453
+ LoggerProxy.logger.info(
454
+ 'ReconnectionManager:index#executeReconnection --> Unable to sync meetings, reconnecting.',
455
+ syncError
456
+ );
457
+ throw new NeedsRetryError(syncError);
458
+ }
417
459
  }
418
460
 
419
461
  // TODO: try to improve this logic as the reconnection manager saves the instance of deleted meeting object
420
462
  // So that on rejoin it known what parametrs it was using
421
463
  if (!this.meeting || !this.webex.meetings.getMeetingByType(_ID_, this.meeting.id)) {
422
464
  LoggerProxy.logger.info(
423
- 'ReconnectionManager:index#executeReconnection --> Meeting got deleted due to inactivity or ended remotely '
465
+ 'ReconnectionManager:index#executeReconnection --> Meeting got deleted due to inactivity or ended remotely.'
424
466
  );
425
467
 
426
- throw new Error('Unable to rejoin a meeting already ended or inactive .');
468
+ throw new Error('Unable to rejoin a meeting already ended or inactive.');
427
469
  }
428
470
 
429
471
  LoggerProxy.logger.info(
@@ -475,24 +517,7 @@ export default class ReconnectionManager {
475
517
  LoggerProxy.logger.info('ReconnectionManager:index#rejoinMeeting --> meeting rejoined');
476
518
 
477
519
  if (wasSharing) {
478
- // Stop the share streams if user tried to rejoin
479
- Media.stopTracks(this.meeting.mediaProperties.shareTrack);
480
- this.meeting.isSharing = false;
481
- if (this.shareStatus === SHARE_STATUS.LOCAL_SHARE_ACTIVE) {
482
- this.meeting.shareStatus = SHARE_STATUS.NO_SHARE;
483
- }
484
- this.meeting.mediaProperties.mediaDirection.sendShare = false;
485
- Trigger.trigger(
486
- this.meeting,
487
- {
488
- file: 'reconnection-manager/index',
489
- function: 'rejoinMeeting',
490
- },
491
- EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
492
- {
493
- reason: SHARE_STOPPED_REASON.MEETING_REJOIN,
494
- }
495
- );
520
+ await this.stopLocalShareStream(SHARE_STOPPED_REASON.MEETING_REJOIN);
496
521
  }
497
522
  } catch (joinError) {
498
523
  this.rejoinAttempts += 1;
@@ -555,9 +580,11 @@ export default class ReconnectionManager {
555
580
 
556
581
  // resend media requests
557
582
  if (this.meeting.isMultistream) {
558
- Object.values(this.meeting.mediaRequestManagers).forEach((mediaRequestManager) =>
559
- // @ts-ignore - Fix type
560
- mediaRequestManager.commit()
583
+ Object.values(this.meeting.mediaRequestManagers).forEach(
584
+ (mediaRequestManager: MediaRequestManager) => {
585
+ mediaRequestManager.clearPreviousRequests();
586
+ mediaRequestManager.commit();
587
+ }
561
588
  );
562
589
  }
563
590
  }
@@ -1,5 +1,5 @@
1
1
  import PermissionError from '../common/errors/permission';
2
- import {CONTROLS, HTTP_VERBS} from '../constants';
2
+ import {CONTROLS, HTTP_VERBS, SELF_POLICY} from '../constants';
3
3
  import MeetingRequest from '../meeting/request';
4
4
  import RecordingAction from './enums';
5
5
  import Util from './util';
@@ -28,6 +28,14 @@ export default class RecordingController {
28
28
  */
29
29
  private displayHints: Array<string> = [];
30
30
 
31
+ /**
32
+ * @instance
33
+ * @type {Object}
34
+ * @private
35
+ * @memberof RecordingInfo
36
+ */
37
+ private selfUserPolicies: Record<SELF_POLICY, boolean>;
38
+
31
39
  /**
32
40
  * @instance
33
41
  * @type {string}
@@ -81,7 +89,6 @@ export default class RecordingController {
81
89
 
82
90
  /**
83
91
  * @param {MeetingRequest} request
84
- * @param {LocusInfo} info
85
92
  * @returns {void}
86
93
  * @private
87
94
  * @memberof RecordingController
@@ -126,6 +133,16 @@ export default class RecordingController {
126
133
  this.displayHints = hints;
127
134
  }
128
135
 
136
+ /**
137
+ * @param {Object} selfUserPolicies
138
+ * @returns {void}
139
+ * @public
140
+ * @memberof RecordingController
141
+ */
142
+ public setUserPolicy(selfUserPolicies: Record<SELF_POLICY, boolean>) {
143
+ this.selfUserPolicies = selfUserPolicies;
144
+ }
145
+
129
146
  /**
130
147
  * @param {string} id
131
148
  * @returns {void}
@@ -264,7 +281,7 @@ export default class RecordingController {
264
281
  );
265
282
 
266
283
  // assumes action is proper cased (i.e., Example)
267
- if (Util?.[`canUser${action}`](this.displayHints)) {
284
+ if (Util?.[`canUser${action}`](this.displayHints, this.selfUserPolicies)) {
268
285
  if (this.serviceUrl) {
269
286
  return this.recordingService(action);
270
287
  }