@webex/plugin-meetings 3.0.0-beta.31 → 3.0.0-beta.310

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 (378) 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 +94 -15
  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 +709 -35
  15. package/dist/breakouts/index.js.map +1 -1
  16. package/dist/breakouts/utils.js +45 -1
  17. package/dist/breakouts/utils.js.map +1 -1
  18. package/dist/common/errors/no-meeting-info.js +51 -0
  19. package/dist/common/errors/no-meeting-info.js.map +1 -0
  20. package/dist/common/errors/reclaim-host-role-errors.js +158 -0
  21. package/dist/common/errors/reclaim-host-role-errors.js.map +1 -0
  22. package/dist/common/errors/webex-errors.js +48 -7
  23. package/dist/common/errors/webex-errors.js.map +1 -1
  24. package/dist/common/logs/logger-proxy.js +1 -1
  25. package/dist/common/logs/logger-proxy.js.map +1 -1
  26. package/dist/common/logs/request.js +5 -1
  27. package/dist/common/logs/request.js.map +1 -1
  28. package/dist/common/queue.js +24 -9
  29. package/dist/common/queue.js.map +1 -1
  30. package/dist/config.js +5 -11
  31. package/dist/config.js.map +1 -1
  32. package/dist/constants.js +233 -29
  33. package/dist/constants.js.map +1 -1
  34. package/dist/controls-options-manager/enums.js +14 -2
  35. package/dist/controls-options-manager/enums.js.map +1 -1
  36. package/dist/controls-options-manager/index.js +109 -15
  37. package/dist/controls-options-manager/index.js.map +1 -1
  38. package/dist/controls-options-manager/types.js +7 -0
  39. package/dist/controls-options-manager/types.js.map +1 -0
  40. package/dist/controls-options-manager/util.js +309 -18
  41. package/dist/controls-options-manager/util.js.map +1 -1
  42. package/dist/index.js +112 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/interpretation/collection.js +23 -0
  45. package/dist/interpretation/collection.js.map +1 -0
  46. package/dist/interpretation/index.js +366 -0
  47. package/dist/interpretation/index.js.map +1 -0
  48. package/dist/interpretation/siLanguage.js +25 -0
  49. package/dist/interpretation/siLanguage.js.map +1 -0
  50. package/dist/locus-info/controlsUtils.js +91 -2
  51. package/dist/locus-info/controlsUtils.js.map +1 -1
  52. package/dist/locus-info/index.js +383 -62
  53. package/dist/locus-info/index.js.map +1 -1
  54. package/dist/locus-info/infoUtils.js +7 -1
  55. package/dist/locus-info/infoUtils.js.map +1 -1
  56. package/dist/locus-info/mediaSharesUtils.js +57 -1
  57. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  58. package/dist/locus-info/parser.js +249 -72
  59. package/dist/locus-info/parser.js.map +1 -1
  60. package/dist/locus-info/selfUtils.js +89 -14
  61. package/dist/locus-info/selfUtils.js.map +1 -1
  62. package/dist/media/index.js +61 -116
  63. package/dist/media/index.js.map +1 -1
  64. package/dist/media/properties.js +73 -124
  65. package/dist/media/properties.js.map +1 -1
  66. package/dist/meeting/in-meeting-actions.js +82 -2
  67. package/dist/meeting/in-meeting-actions.js.map +1 -1
  68. package/dist/meeting/index.js +3777 -2929
  69. package/dist/meeting/index.js.map +1 -1
  70. package/dist/meeting/locusMediaRequest.js +292 -0
  71. package/dist/meeting/locusMediaRequest.js.map +1 -0
  72. package/dist/meeting/muteState.js +230 -124
  73. package/dist/meeting/muteState.js.map +1 -1
  74. package/dist/meeting/request.js +260 -196
  75. package/dist/meeting/request.js.map +1 -1
  76. package/dist/meeting/util.js +601 -417
  77. package/dist/meeting/util.js.map +1 -1
  78. package/dist/meeting-info/index.js +73 -7
  79. package/dist/meeting-info/index.js.map +1 -1
  80. package/dist/meeting-info/meeting-info-v2.js +192 -51
  81. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  82. package/dist/meeting-info/util.js +1 -1
  83. package/dist/meeting-info/util.js.map +1 -1
  84. package/dist/meeting-info/utilv2.js +36 -36
  85. package/dist/meeting-info/utilv2.js.map +1 -1
  86. package/dist/meetings/collection.js +39 -0
  87. package/dist/meetings/collection.js.map +1 -1
  88. package/dist/meetings/index.js +415 -115
  89. package/dist/meetings/index.js.map +1 -1
  90. package/dist/meetings/meetings.types.js +7 -0
  91. package/dist/meetings/meetings.types.js.map +1 -0
  92. package/dist/meetings/request.js +2 -0
  93. package/dist/meetings/request.js.map +1 -1
  94. package/dist/meetings/util.js +72 -6
  95. package/dist/meetings/util.js.map +1 -1
  96. package/dist/member/index.js +58 -0
  97. package/dist/member/index.js.map +1 -1
  98. package/dist/member/types.js +25 -0
  99. package/dist/member/types.js.map +1 -0
  100. package/dist/member/util.js +132 -25
  101. package/dist/member/util.js.map +1 -1
  102. package/dist/members/collection.js +10 -0
  103. package/dist/members/collection.js.map +1 -1
  104. package/dist/members/index.js +102 -6
  105. package/dist/members/index.js.map +1 -1
  106. package/dist/members/request.js +106 -38
  107. package/dist/members/request.js.map +1 -1
  108. package/dist/members/types.js +15 -0
  109. package/dist/members/types.js.map +1 -0
  110. package/dist/members/util.js +326 -232
  111. package/dist/members/util.js.map +1 -1
  112. package/dist/metrics/constants.js +13 -5
  113. package/dist/metrics/constants.js.map +1 -1
  114. package/dist/metrics/index.js +1 -468
  115. package/dist/metrics/index.js.map +1 -1
  116. package/dist/multistream/mediaRequestManager.js +238 -49
  117. package/dist/multistream/mediaRequestManager.js.map +1 -1
  118. package/dist/multistream/receiveSlot.js +29 -16
  119. package/dist/multistream/receiveSlot.js.map +1 -1
  120. package/dist/multistream/receiveSlotManager.js +39 -36
  121. package/dist/multistream/receiveSlotManager.js.map +1 -1
  122. package/dist/multistream/remoteMedia.js +44 -18
  123. package/dist/multistream/remoteMedia.js.map +1 -1
  124. package/dist/multistream/remoteMediaGroup.js +60 -3
  125. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  126. package/dist/multistream/remoteMediaManager.js +209 -59
  127. package/dist/multistream/remoteMediaManager.js.map +1 -1
  128. package/dist/multistream/sendSlotManager.js +233 -0
  129. package/dist/multistream/sendSlotManager.js.map +1 -0
  130. package/dist/reachability/index.js +225 -59
  131. package/dist/reachability/index.js.map +1 -1
  132. package/dist/reachability/request.js +17 -8
  133. package/dist/reachability/request.js.map +1 -1
  134. package/dist/reconnection-manager/index.js +201 -156
  135. package/dist/reconnection-manager/index.js.map +1 -1
  136. package/dist/recording-controller/index.js +21 -2
  137. package/dist/recording-controller/index.js.map +1 -1
  138. package/dist/recording-controller/util.js +9 -8
  139. package/dist/recording-controller/util.js.map +1 -1
  140. package/dist/roap/index.js +62 -32
  141. package/dist/roap/index.js.map +1 -1
  142. package/dist/roap/request.js +112 -97
  143. package/dist/roap/request.js.map +1 -1
  144. package/dist/roap/turnDiscovery.js +95 -36
  145. package/dist/roap/turnDiscovery.js.map +1 -1
  146. package/dist/rtcMetrics/constants.js +12 -0
  147. package/dist/rtcMetrics/constants.js.map +1 -0
  148. package/dist/rtcMetrics/index.js +117 -0
  149. package/dist/rtcMetrics/index.js.map +1 -0
  150. package/dist/statsAnalyzer/index.js +86 -78
  151. package/dist/statsAnalyzer/index.js.map +1 -1
  152. package/dist/statsAnalyzer/mqaUtil.js +11 -10
  153. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  154. package/dist/types/annotation/annotation.types.d.ts +42 -0
  155. package/dist/types/annotation/constants.d.ts +31 -0
  156. package/dist/types/annotation/index.d.ts +117 -0
  157. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  158. package/dist/types/breakouts/events.d.ts +8 -0
  159. package/dist/types/breakouts/utils.d.ts +14 -0
  160. package/dist/types/common/errors/no-meeting-info.d.ts +14 -0
  161. package/dist/types/common/errors/reclaim-host-role-errors.d.ts +60 -0
  162. package/dist/types/common/errors/webex-errors.d.ts +25 -1
  163. package/dist/types/common/logs/request.d.ts +2 -0
  164. package/dist/types/common/queue.d.ts +9 -7
  165. package/dist/types/config.d.ts +1 -7
  166. package/dist/types/constants.d.ts +194 -24
  167. package/dist/types/controls-options-manager/enums.d.ts +11 -1
  168. package/dist/types/controls-options-manager/index.d.ts +17 -1
  169. package/dist/types/controls-options-manager/types.d.ts +43 -0
  170. package/dist/types/controls-options-manager/util.d.ts +1 -7
  171. package/dist/types/index.d.ts +6 -4
  172. package/dist/types/interpretation/collection.d.ts +5 -0
  173. package/dist/types/interpretation/index.d.ts +5 -0
  174. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  175. package/dist/types/locus-info/index.d.ts +57 -4
  176. package/dist/types/locus-info/parser.d.ts +67 -6
  177. package/dist/types/media/index.d.ts +2 -0
  178. package/dist/types/media/properties.d.ts +34 -48
  179. package/dist/types/meeting/in-meeting-actions.d.ts +82 -2
  180. package/dist/types/meeting/index.d.ts +463 -510
  181. package/dist/types/meeting/locusMediaRequest.d.ts +74 -0
  182. package/dist/types/meeting/muteState.d.ts +99 -23
  183. package/dist/types/meeting/request.d.ts +72 -43
  184. package/dist/types/meeting/util.d.ts +101 -1
  185. package/dist/types/meeting-info/index.d.ts +13 -1
  186. package/dist/types/meeting-info/meeting-info-v2.d.ts +31 -1
  187. package/dist/types/meetings/collection.d.ts +17 -0
  188. package/dist/types/meetings/index.d.ts +98 -20
  189. package/dist/types/meetings/meetings.types.d.ts +4 -0
  190. package/dist/types/member/index.d.ts +14 -0
  191. package/dist/types/member/types.d.ts +32 -0
  192. package/dist/types/members/collection.d.ts +5 -0
  193. package/dist/types/members/index.d.ts +35 -2
  194. package/dist/types/members/request.d.ts +73 -9
  195. package/dist/types/members/types.d.ts +25 -0
  196. package/dist/types/members/util.d.ts +214 -1
  197. package/dist/types/metrics/constants.d.ts +12 -4
  198. package/dist/types/metrics/index.d.ts +4 -119
  199. package/dist/types/multistream/mediaRequestManager.d.ts +73 -5
  200. package/dist/types/multistream/receiveSlot.d.ts +13 -11
  201. package/dist/types/multistream/receiveSlotManager.d.ts +14 -4
  202. package/dist/types/multistream/remoteMedia.d.ts +8 -29
  203. package/dist/types/multistream/remoteMediaGroup.d.ts +0 -9
  204. package/dist/types/multistream/remoteMediaManager.d.ts +46 -2
  205. package/dist/types/multistream/sendSlotManager.d.ts +61 -0
  206. package/dist/types/reachability/index.d.ts +61 -7
  207. package/dist/types/reachability/request.d.ts +7 -3
  208. package/dist/types/reconnection-manager/index.d.ts +9 -0
  209. package/dist/types/recording-controller/index.d.ts +15 -1
  210. package/dist/types/recording-controller/util.d.ts +5 -4
  211. package/dist/types/roap/index.d.ts +2 -1
  212. package/dist/types/roap/request.d.ts +15 -11
  213. package/dist/types/roap/turnDiscovery.d.ts +21 -3
  214. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  215. package/dist/types/rtcMetrics/index.d.ts +47 -0
  216. package/dist/types/statsAnalyzer/index.d.ts +7 -1
  217. package/dist/types/webinar/collection.d.ts +16 -0
  218. package/dist/types/webinar/index.d.ts +5 -0
  219. package/dist/webinar/collection.js +44 -0
  220. package/dist/webinar/collection.js.map +1 -0
  221. package/dist/webinar/index.js +69 -0
  222. package/dist/webinar/index.js.map +1 -0
  223. package/package.json +23 -20
  224. package/src/annotation/annotation.types.ts +50 -0
  225. package/src/annotation/constants.ts +36 -0
  226. package/src/annotation/index.ts +328 -0
  227. package/src/breakouts/README.md +42 -12
  228. package/src/breakouts/breakout.ts +67 -9
  229. package/src/breakouts/edit-lock-error.ts +25 -0
  230. package/src/breakouts/events.ts +56 -0
  231. package/src/breakouts/index.ts +592 -20
  232. package/src/breakouts/utils.ts +42 -0
  233. package/src/common/errors/no-meeting-info.ts +24 -0
  234. package/src/common/errors/reclaim-host-role-errors.ts +134 -0
  235. package/src/common/errors/webex-errors.ts +44 -2
  236. package/src/common/logs/logger-proxy.ts +1 -1
  237. package/src/common/logs/request.ts +5 -1
  238. package/src/common/queue.ts +22 -8
  239. package/src/config.ts +4 -10
  240. package/src/constants.ts +221 -19
  241. package/src/controls-options-manager/enums.ts +12 -0
  242. package/src/controls-options-manager/index.ts +116 -21
  243. package/src/controls-options-manager/types.ts +59 -0
  244. package/src/controls-options-manager/util.ts +294 -14
  245. package/src/index.ts +40 -0
  246. package/src/interpretation/README.md +60 -0
  247. package/src/interpretation/collection.ts +19 -0
  248. package/src/interpretation/index.ts +332 -0
  249. package/src/interpretation/siLanguage.ts +18 -0
  250. package/src/locus-info/controlsUtils.ts +108 -0
  251. package/src/locus-info/index.ts +413 -59
  252. package/src/locus-info/infoUtils.ts +10 -2
  253. package/src/locus-info/mediaSharesUtils.ts +64 -0
  254. package/src/locus-info/parser.ts +258 -47
  255. package/src/locus-info/selfUtils.ts +81 -5
  256. package/src/media/index.ts +102 -122
  257. package/src/media/properties.ts +87 -110
  258. package/src/meeting/in-meeting-actions.ts +163 -3
  259. package/src/meeting/index.ts +3132 -2541
  260. package/src/meeting/locusMediaRequest.ts +313 -0
  261. package/src/meeting/muteState.ts +229 -131
  262. package/src/meeting/request.ts +177 -121
  263. package/src/meeting/util.ts +588 -394
  264. package/src/meeting-info/index.ts +81 -8
  265. package/src/meeting-info/meeting-info-v2.ts +170 -14
  266. package/src/meeting-info/util.ts +1 -1
  267. package/src/meeting-info/utilv2.ts +23 -23
  268. package/src/meetings/collection.ts +33 -0
  269. package/src/meetings/index.ts +445 -123
  270. package/src/meetings/meetings.types.ts +12 -0
  271. package/src/meetings/request.ts +2 -0
  272. package/src/meetings/util.ts +80 -11
  273. package/src/member/index.ts +58 -0
  274. package/src/member/types.ts +38 -0
  275. package/src/member/util.ts +141 -25
  276. package/src/members/collection.ts +8 -0
  277. package/src/members/index.ts +134 -8
  278. package/src/members/request.ts +97 -17
  279. package/src/members/types.ts +29 -0
  280. package/src/members/util.ts +333 -240
  281. package/src/metrics/constants.ts +12 -4
  282. package/src/metrics/index.ts +1 -490
  283. package/src/multistream/mediaRequestManager.ts +289 -79
  284. package/src/multistream/receiveSlot.ts +31 -17
  285. package/src/multistream/receiveSlotManager.ts +34 -24
  286. package/src/multistream/remoteMedia.ts +27 -2
  287. package/src/multistream/remoteMediaGroup.ts +59 -0
  288. package/src/multistream/remoteMediaManager.ts +148 -30
  289. package/src/multistream/sendSlotManager.ts +170 -0
  290. package/src/reachability/index.ts +228 -37
  291. package/src/reachability/request.ts +17 -8
  292. package/src/reconnection-manager/index.ts +83 -56
  293. package/src/recording-controller/index.ts +20 -3
  294. package/src/recording-controller/util.ts +26 -9
  295. package/src/roap/index.ts +63 -32
  296. package/src/roap/request.ts +100 -104
  297. package/src/roap/turnDiscovery.ts +48 -26
  298. package/src/rtcMetrics/constants.ts +3 -0
  299. package/src/rtcMetrics/index.ts +100 -0
  300. package/src/statsAnalyzer/index.ts +105 -91
  301. package/src/statsAnalyzer/mqaUtil.ts +13 -14
  302. package/src/webinar/collection.ts +31 -0
  303. package/src/webinar/index.ts +62 -0
  304. package/test/integration/spec/converged-space-meetings.js +60 -3
  305. package/test/integration/spec/journey.js +320 -261
  306. package/test/integration/spec/space-meeting.js +76 -3
  307. package/test/unit/spec/annotation/index.ts +418 -0
  308. package/test/unit/spec/breakouts/breakout.ts +118 -28
  309. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  310. package/test/unit/spec/breakouts/events.ts +89 -0
  311. package/test/unit/spec/breakouts/index.ts +1395 -69
  312. package/test/unit/spec/breakouts/utils.js +52 -1
  313. package/test/unit/spec/common/queue.js +31 -2
  314. package/test/unit/spec/controls-options-manager/index.js +163 -0
  315. package/test/unit/spec/controls-options-manager/util.js +576 -60
  316. package/test/unit/spec/fixture/locus.js +1 -0
  317. package/test/unit/spec/interpretation/collection.ts +15 -0
  318. package/test/unit/spec/interpretation/index.ts +589 -0
  319. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  320. package/test/unit/spec/locus-info/controlsUtils.js +316 -43
  321. package/test/unit/spec/locus-info/index.js +1304 -33
  322. package/test/unit/spec/locus-info/infoUtils.js +37 -15
  323. package/test/unit/spec/locus-info/lib/SeqCmp.json +16 -0
  324. package/test/unit/spec/locus-info/mediaSharesUtils.ts +32 -0
  325. package/test/unit/spec/locus-info/parser.js +116 -35
  326. package/test/unit/spec/locus-info/selfConstant.js +27 -4
  327. package/test/unit/spec/locus-info/selfUtils.js +208 -17
  328. package/test/unit/spec/media/index.ts +104 -37
  329. package/test/unit/spec/media/properties.ts +2 -2
  330. package/test/unit/spec/meeting/in-meeting-actions.ts +81 -3
  331. package/test/unit/spec/meeting/index.js +5216 -1956
  332. package/test/unit/spec/meeting/locusMediaRequest.ts +442 -0
  333. package/test/unit/spec/meeting/muteState.js +408 -208
  334. package/test/unit/spec/meeting/request.js +483 -49
  335. package/test/unit/spec/meeting/utils.js +679 -64
  336. package/test/unit/spec/meeting-info/index.js +300 -0
  337. package/test/unit/spec/meeting-info/meetinginfov2.js +526 -5
  338. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  339. package/test/unit/spec/meetings/collection.js +26 -0
  340. package/test/unit/spec/meetings/index.js +1011 -205
  341. package/test/unit/spec/meetings/utils.js +202 -2
  342. package/test/unit/spec/member/index.js +61 -6
  343. package/test/unit/spec/member/util.js +510 -34
  344. package/test/unit/spec/members/index.js +432 -1
  345. package/test/unit/spec/members/request.js +206 -27
  346. package/test/unit/spec/members/utils.js +210 -0
  347. package/test/unit/spec/metrics/index.js +1 -50
  348. package/test/unit/spec/multistream/mediaRequestManager.ts +803 -162
  349. package/test/unit/spec/multistream/receiveSlot.ts +28 -20
  350. package/test/unit/spec/multistream/receiveSlotManager.ts +32 -30
  351. package/test/unit/spec/multistream/remoteMedia.ts +30 -0
  352. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  353. package/test/unit/spec/multistream/remoteMediaManager.ts +326 -0
  354. package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
  355. package/test/unit/spec/reachability/index.ts +549 -9
  356. package/test/unit/spec/reachability/request.js +68 -0
  357. package/test/unit/spec/reconnection-manager/index.js +85 -9
  358. package/test/unit/spec/recording-controller/index.js +294 -218
  359. package/test/unit/spec/recording-controller/util.js +223 -96
  360. package/test/unit/spec/roap/index.ts +178 -64
  361. package/test/unit/spec/roap/request.ts +203 -85
  362. package/test/unit/spec/roap/turnDiscovery.ts +82 -36
  363. package/test/unit/spec/rtcMetrics/index.ts +73 -0
  364. package/test/unit/spec/stats-analyzer/index.js +136 -2
  365. package/test/unit/spec/webinar/collection.ts +13 -0
  366. package/test/unit/spec/webinar/index.ts +60 -0
  367. package/test/utils/integrationTestUtils.js +46 -0
  368. package/test/utils/testUtils.js +0 -52
  369. package/dist/meeting/effectsState.js +0 -262
  370. package/dist/meeting/effectsState.js.map +0 -1
  371. package/dist/metrics/config.js +0 -299
  372. package/dist/metrics/config.js.map +0 -1
  373. package/dist/types/meeting/effectsState.d.ts +0 -42
  374. package/dist/types/metrics/config.d.ts +0 -178
  375. package/src/index.js +0 -16
  376. package/src/meeting/effectsState.ts +0 -211
  377. package/src/metrics/config.ts +0 -495
  378. package/test/unit/spec/meeting/effectsState.js +0 -285
@@ -1,123 +1,188 @@
1
+ import {ServerMuteReason} from '@webex/media-helpers';
1
2
  import LoggerProxy from '../common/logs/logger-proxy';
2
3
  import ParameterError from '../common/errors/parameter';
3
- import PermissionError from '../common/errors/permission';
4
- import Media from '../media';
5
4
  import MeetingUtil from './util';
6
5
  import {AUDIO, VIDEO} from '../constants';
7
6
 
8
- /* Certain aspects of server interaction for video muting are not implemented as we currently don't support remote muting of video.
9
- If we ever need to support it, search for REMOTE_MUTE_VIDEO_MISSING_IMPLEMENTATION string to find the places that need updating
10
- */
11
-
12
7
  // eslint-disable-next-line import/prefer-default-export
13
- export const createMuteState = (type, meeting, mediaDirection) => {
14
- if (type === AUDIO && !mediaDirection.sendAudio) {
15
- return null;
16
- }
17
- if (type === VIDEO && !mediaDirection.sendVideo) {
18
- return null;
19
- }
8
+ export const createMuteState = (type, meeting, enabled: boolean) => {
9
+ // todo: remove the meeting argument (SPARK-399695)
20
10
 
21
11
  LoggerProxy.logger.info(
22
12
  `Meeting:muteState#createMuteState --> ${type}: creating MuteState for meeting id ${meeting?.id}`
23
13
  );
24
14
 
25
- return new MuteState(type, meeting);
15
+ const muteState = new MuteState(type, meeting, enabled);
16
+
17
+ return muteState;
26
18
  };
27
19
 
28
20
  /** The purpose of this class is to manage the local and remote mute state and make sure that the server state always matches
29
21
  the last requested state by the client.
30
22
 
31
23
  More info about Locus muting API: https://sqbu-github.cisco.com/pages/WebExSquared/locus/guides/mute.html#
24
+
25
+ This class is exported only for unit tests. It should never be instantiated directly with new MuteState(), instead createMuteState() should be called
32
26
  */
33
- class MuteState {
34
- pendingPromiseReject: any;
35
- pendingPromiseResolve: any;
36
- state: any;
27
+ export class MuteState {
28
+ state: {
29
+ client: {
30
+ enabled: boolean; // indicates if audio/video is enabled at all or not
31
+ localMute: boolean;
32
+ };
33
+ server: {localMute: boolean; remoteMute: boolean; unmuteAllowed: boolean};
34
+ syncToServerInProgress: boolean;
35
+ };
36
+
37
37
  type: any;
38
+ ignoreMuteStateChange: boolean;
38
39
 
39
40
  /**
40
41
  * Constructor
41
42
  *
42
43
  * @param {String} type - audio or video
43
44
  * @param {Object} meeting - the meeting object (used for reading current remote mute status)
45
+ * @param {boolean} enabled - whether the client audio/video is enabled at all
44
46
  */
45
- constructor(type: string, meeting: any) {
47
+ constructor(type: string, meeting: any, enabled: boolean) {
46
48
  if (type !== AUDIO && type !== VIDEO) {
47
49
  throw new ParameterError('Mute state is designed for handling audio or video only');
48
50
  }
49
51
  this.type = type;
52
+ this.ignoreMuteStateChange = false;
50
53
  this.state = {
51
54
  client: {
52
- localMute: false,
55
+ enabled,
56
+ localMute: true,
53
57
  },
54
58
  server: {
55
- localMute: false,
56
- // initial values available only for audio (REMOTE_MUTE_VIDEO_MISSING_IMPLEMENTATION)
57
- remoteMute: type === AUDIO ? meeting.remoteMuted : false,
58
- unmuteAllowed: type === AUDIO ? meeting.unmuteAllowed : true,
59
+ localMute: true,
60
+ // because remoteVideoMuted and unmuteVideoAllowed are updated seperately, they might be undefined
61
+ remoteMute: type === AUDIO ? meeting.remoteMuted : meeting.remoteVideoMuted ?? false,
62
+ unmuteAllowed: type === AUDIO ? meeting.unmuteAllowed : meeting.unmuteVideoAllowed ?? true,
59
63
  },
60
64
  syncToServerInProgress: false,
61
65
  };
62
- // these 2 hold the resolve, reject methods for the promise we returned to the client in last handleClientRequest() call
63
- this.pendingPromiseResolve = null;
64
- this.pendingPromiseReject = null;
65
66
  }
66
67
 
67
68
  /**
68
- * Handles mute/unmute request from the client/user. Returns a promise that's resolved once the server update is completed or
69
- * at the point that this request becomese superseded by another client request.
69
+ * Starts the mute state machine. Needs to be called after a new MuteState instance is created.
70
70
  *
71
- * The client doesn't have to wait for the returned promise to resolve before calling handleClientRequest() again. If
72
- * handleClientRequest() is called again before the previous one resolved, the MuteState class will make sure that eventually
73
- * the server state will match the last requested state from the client.
71
+ * @param {Object} meeting - the meeting object
72
+ * @returns {void}
73
+ */
74
+ public init(meeting: any) {
75
+ this.applyUnmuteAllowedToStream(meeting);
76
+
77
+ // if we are remotely muted, we need to apply that to the local stream now (mute on-entry)
78
+ if (this.state.server.remoteMute) {
79
+ this.muteLocalStream(meeting, this.state.server.remoteMute, 'remotelyMuted');
80
+ }
81
+
82
+ const initialMute =
83
+ this.type === AUDIO
84
+ ? meeting.mediaProperties.audioStream?.muted
85
+ : meeting.mediaProperties.videoStream?.muted;
86
+
87
+ LoggerProxy.logger.info(
88
+ `Meeting:muteState#init --> ${this.type}: local stream initial mute state: ${initialMute}`
89
+ );
90
+
91
+ if (initialMute !== undefined) {
92
+ this.state.client.localMute = initialMute;
93
+ } else {
94
+ // there is no stream, so it's like we are locally muted
95
+ // (this is important especially for transcoded meetings, in which the SDP m-line direction always stays "sendrecv")
96
+ this.state.client.localMute = true;
97
+ }
98
+ this.applyClientStateToServer(meeting);
99
+ }
100
+
101
+ /**
102
+ * This method needs to be called whenever the local audio/video stream has changed.
103
+ * It reapplies the remote mute state onto the new stream and also reads the current
104
+ * local mute state from the stream and updates the internal state machine and sends
105
+ * any required requests to the server.
74
106
  *
107
+ * @param {Object} meeting - the meeting object
108
+ * @returns {void}
109
+ */
110
+ public handleLocalStreamChange(meeting: any) {
111
+ return this.init(meeting);
112
+ }
113
+
114
+ /**
115
+ * Enables/disables audio/video
116
+ *
117
+ * @param {Object} meeting - the meeting object
118
+ * @param {boolean} enable
119
+ * @returns {void}
120
+ */
121
+ public enable(meeting: any, enable: boolean) {
122
+ this.state.client.enabled = enable;
123
+
124
+ this.applyClientStateToServer(meeting);
125
+ }
126
+
127
+ /**
128
+ * Mutes/unmutes local stream
129
+ *
130
+ * @param {Object} meeting - the meeting object
131
+ * @param {Boolean} mute - true to mute the stream, false to unmute it
132
+ * @param {ServerMuteReason} reason - reason for muting/unmuting
133
+ * @returns {void}
134
+ */
135
+ private muteLocalStream(meeting: any, mute: boolean, reason: ServerMuteReason) {
136
+ this.ignoreMuteStateChange = true;
137
+ if (this.type === AUDIO) {
138
+ meeting.mediaProperties.audioStream?.setServerMuted(mute, reason);
139
+ } else {
140
+ meeting.mediaProperties.videoStream?.setServerMuted(mute, reason);
141
+ }
142
+ this.ignoreMuteStateChange = false;
143
+ }
144
+
145
+ /**
146
+ * This method should be called when the local stream mute state is changed
75
147
  * @public
76
148
  * @memberof MuteState
77
149
  * @param {Object} [meeting] the meeting object
78
150
  * @param {Boolean} [mute] true for muting, false for unmuting request
79
- * @returns {Promise}
151
+ * @returns {void}
80
152
  */
81
- public handleClientRequest(meeting?: object, mute?: boolean) {
153
+ public handleLocalStreamMuteStateChange(meeting?: object, mute?: boolean) {
154
+ if (this.ignoreMuteStateChange) {
155
+ return;
156
+ }
82
157
  LoggerProxy.logger.info(
83
- `Meeting:muteState#handleClientRequest --> ${this.type}: user requesting new mute state: ${mute}`
158
+ `Meeting:muteState#handleLocalStreamMuteStateChange --> ${this.type}: local stream new mute state: ${mute}`
84
159
  );
85
160
 
86
- if (!mute && !this.state.server.unmuteAllowed) {
87
- return Promise.reject(
88
- new PermissionError('User is not allowed to unmute self (hard mute feature is being used)')
89
- );
90
- }
91
-
92
- // we don't check if we're already in the same state, because even if we were, we would still have to apply the mute state locally,
93
- // because the client may have changed the audio/vidoe tracks
94
161
  this.state.client.localMute = mute;
95
- this.applyClientStateLocally(meeting);
96
-
97
- return new Promise((resolve, reject) => {
98
- if (this.pendingPromiseResolve) {
99
- // resolve the last promise we returned to the client as the client has issued a new request that has superseded the previous one
100
- this.pendingPromiseResolve();
101
- }
102
- this.pendingPromiseResolve = resolve;
103
- this.pendingPromiseReject = reject;
104
- this.applyClientStateToServer(meeting);
105
- });
162
+
163
+ this.applyClientStateToServer(meeting);
106
164
  }
107
165
 
108
166
  /**
109
- * Applies the current mute state to the local track (by enabling or disabling it accordingly)
167
+ * Applies the current mute state to the local stream (by enabling or disabling it accordingly)
110
168
  *
111
169
  * @public
112
170
  * @param {Object} [meeting] the meeting object
171
+ * @param {ServerMuteReason} reason - reason why we're applying our client state to the local stream
113
172
  * @memberof MuteState
114
173
  * @returns {void}
115
174
  */
116
- public applyClientStateLocally(meeting?: any) {
117
- Media.setLocalTrack(
118
- !this.state.client.localMute,
119
- this.type === AUDIO ? meeting.mediaProperties.audioTrack : meeting.mediaProperties.videoTrack
120
- );
175
+ public applyClientStateLocally(meeting?: any, reason?: ServerMuteReason) {
176
+ this.muteLocalStream(meeting, this.state.client.localMute, reason);
177
+ }
178
+
179
+ /** Returns true if client is locally muted - it takes into account not just the client local mute state,
180
+ * but also whether audio/video is enabled at all
181
+ *
182
+ * @returns {boolean}
183
+ */
184
+ private getClientLocalMuteState() {
185
+ return this.state.client.enabled ? this.state.client.localMute : true;
121
186
  }
122
187
 
123
188
  /**
@@ -128,7 +193,7 @@ class MuteState {
128
193
  * @memberof MuteState
129
194
  * @returns {void}
130
195
  */
131
- private applyClientStateToServer(meeting?: object) {
196
+ private applyClientStateToServer(meeting?: any) {
132
197
  if (this.state.syncToServerInProgress) {
133
198
  LoggerProxy.logger.info(
134
199
  `Meeting:muteState#applyClientStateToServer --> ${this.type}: request to server in progress, we need to wait for it to complete`
@@ -137,11 +202,12 @@ class MuteState {
137
202
  return;
138
203
  }
139
204
 
140
- const localMuteRequiresSync = this.state.client.localMute !== this.state.server.localMute;
141
- const remoteMuteRequiresSync = !this.state.client.localMute && this.state.server.remoteMute;
205
+ const localMuteState = this.getClientLocalMuteState();
206
+ const localMuteRequiresSync = localMuteState !== this.state.server.localMute;
207
+ const remoteMuteRequiresSync = !localMuteState && this.state.server.remoteMute;
142
208
 
143
209
  LoggerProxy.logger.info(
144
- `Meeting:muteState#applyClientStateToServer --> ${this.type}: localMuteRequiresSync: ${localMuteRequiresSync} (${this.state.client.localMute} ?= ${this.state.server.localMute})`
210
+ `Meeting:muteState#applyClientStateToServer --> ${this.type}: localMuteRequiresSync: ${localMuteRequiresSync} (${localMuteState} ?= ${this.state.server.localMute})`
145
211
  );
146
212
  LoggerProxy.logger.info(
147
213
  `Meeting:muteState#applyClientStateToServer --> ${this.type}: remoteMuteRequiresSync: ${remoteMuteRequiresSync}`
@@ -152,12 +218,6 @@ class MuteState {
152
218
  `Meeting:muteState#applyClientStateToServer --> ${this.type}: client state already matching server state, nothing to do`
153
219
  );
154
220
 
155
- if (this.pendingPromiseResolve) {
156
- this.pendingPromiseResolve();
157
- }
158
- this.pendingPromiseResolve = null;
159
- this.pendingPromiseReject = null;
160
-
161
221
  return;
162
222
  }
163
223
 
@@ -185,11 +245,11 @@ class MuteState {
185
245
  .catch((e) => {
186
246
  this.state.syncToServerInProgress = false;
187
247
 
188
- if (this.pendingPromiseReject) {
189
- this.pendingPromiseReject(e);
190
- }
191
- this.pendingPromiseResolve = null;
192
- this.pendingPromiseReject = null;
248
+ LoggerProxy.logger.warn(
249
+ `Meeting:muteState#applyClientStateToServer --> ${this.type}: error: ${e}`
250
+ );
251
+
252
+ this.applyServerMuteToLocalStream(meeting, 'clientRequestFailed');
193
253
  });
194
254
  }
195
255
 
@@ -202,16 +262,14 @@ class MuteState {
202
262
  * @returns {Promise}
203
263
  */
204
264
  private sendLocalMuteRequestToServer(meeting?: any) {
205
- const audioMuted =
206
- this.type === AUDIO ? this.state.client.localMute : meeting.audio?.state.client.localMute;
207
- const videoMuted =
208
- this.type === VIDEO ? this.state.client.localMute : meeting.video?.state.client.localMute;
265
+ const audioMuted = this.type === AUDIO ? this.getClientLocalMuteState() : undefined;
266
+ const videoMuted = this.type === VIDEO ? this.getClientLocalMuteState() : undefined;
209
267
 
210
268
  LoggerProxy.logger.info(
211
269
  `Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: sending local mute (audio=${audioMuted}, video=${videoMuted}) to server`
212
270
  );
213
271
 
214
- return MeetingUtil.remoteUpdateAudioVideo(audioMuted, videoMuted, meeting)
272
+ return MeetingUtil.remoteUpdateAudioVideo(meeting, audioMuted, videoMuted)
215
273
  .then((locus) => {
216
274
  LoggerProxy.logger.info(
217
275
  `Meeting:muteState#sendLocalMuteRequestToServer --> ${this.type}: local mute (audio=${audioMuted}, video=${videoMuted}) applied to server`
@@ -219,7 +277,9 @@ class MuteState {
219
277
 
220
278
  this.state.server.localMute = this.type === AUDIO ? audioMuted : videoMuted;
221
279
 
222
- meeting.locusInfo.onFullLocus(locus);
280
+ if (locus) {
281
+ meeting.locusInfo.handleLocusDelta(locus, meeting);
282
+ }
223
283
 
224
284
  return locus;
225
285
  })
@@ -241,35 +301,54 @@ class MuteState {
241
301
  * @returns {Promise}
242
302
  */
243
303
  private sendRemoteMuteRequestToServer(meeting?: any) {
244
- if (this.type === AUDIO) {
245
- const remoteMute = this.state.client.localMute;
304
+ const remoteMute = this.getClientLocalMuteState();
246
305
 
247
- LoggerProxy.logger.info(
248
- `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: sending remote mute:${remoteMute} to server`
249
- );
306
+ LoggerProxy.logger.info(
307
+ `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: sending remote mute:${remoteMute} to server`
308
+ );
250
309
 
251
- return meeting.members
252
- .muteMember(meeting.members.selfId, remoteMute)
253
- .then(() => {
254
- LoggerProxy.logger.info(
255
- `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: remote mute:${remoteMute} applied to server`
256
- );
257
-
258
- this.state.server.remoteMute = remoteMute;
259
- })
260
- .catch((remoteUpdateError) => {
261
- LoggerProxy.logger.warn(
262
- `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: failed to apply remote mute ${remoteMute} to server: ${remoteUpdateError}`
263
- );
264
-
265
- return Promise.reject(remoteUpdateError);
266
- });
267
- }
310
+ return meeting.members
311
+ .muteMember(meeting.members.selfId, remoteMute, this.type === AUDIO)
312
+ .then(() => {
313
+ LoggerProxy.logger.info(
314
+ `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: remote mute:${remoteMute} applied to server`
315
+ );
316
+
317
+ this.state.server.remoteMute = remoteMute;
318
+ })
319
+ .catch((remoteUpdateError) => {
320
+ LoggerProxy.logger.warn(
321
+ `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: failed to apply remote mute ${remoteMute} to server: ${remoteUpdateError}`
322
+ );
323
+
324
+ return Promise.reject(remoteUpdateError);
325
+ });
326
+ }
268
327
 
269
- // for now we don't need to support remote muting of video (REMOTE_MUTE_VIDEO_MISSING_IMPLEMENTATION)
270
- this.state.server.remoteMute = this.state.client.localMute;
328
+ /** Sets the mute state of the local stream according to what server thinks is our state
329
+ * @param {Object} meeting - the meeting object
330
+ * @param {ServerMuteReason} serverMuteReason - reason why we're applying server mute to the local stream
331
+ * @returns {void}
332
+ */
333
+ private applyServerMuteToLocalStream(meeting: any, serverMuteReason: ServerMuteReason) {
334
+ const muted = this.state.server.localMute || this.state.server.remoteMute;
335
+
336
+ // update the local stream mute state, but not this.state.client.localMute
337
+ this.muteLocalStream(meeting, muted, serverMuteReason);
338
+ }
271
339
 
272
- return Promise.resolve();
340
+ /** Applies the current value for unmute allowed to the underlying stream
341
+ *
342
+ * @param {Meeting} meeting
343
+ * @returns {void}
344
+ */
345
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
346
+ private applyUnmuteAllowedToStream(meeting: any) {
347
+ if (this.type === AUDIO) {
348
+ meeting.mediaProperties.audioStream?.setUnmuteAllowed(this.state.server.unmuteAllowed);
349
+ } else {
350
+ meeting.mediaProperties.videoStream?.setUnmuteAllowed(this.state.server.unmuteAllowed);
351
+ }
273
352
  }
274
353
 
275
354
  /**
@@ -277,16 +356,23 @@ class MuteState {
277
356
  *
278
357
  * @public
279
358
  * @memberof MuteState
359
+ * @param {Meeting} meeting
280
360
  * @param {Boolean} [muted] true if user is remotely muted, false otherwise
281
361
  * @param {Boolean} [unmuteAllowed] indicates if user is allowed to unmute self (false when "hard mute" feature is used)
282
362
  * @returns {undefined}
283
363
  */
284
- public handleServerRemoteMuteUpdate(muted?: boolean, unmuteAllowed?: boolean) {
364
+ public handleServerRemoteMuteUpdate(meeting: any, muted?: boolean, unmuteAllowed?: boolean) {
285
365
  LoggerProxy.logger.info(
286
366
  `Meeting:muteState#handleServerRemoteMuteUpdate --> ${this.type}: updating server remoteMute to (${muted})`
287
367
  );
288
- this.state.server.remoteMute = muted;
289
- this.state.server.unmuteAllowed = unmuteAllowed;
368
+ if (unmuteAllowed !== undefined) {
369
+ this.state.server.unmuteAllowed = unmuteAllowed;
370
+ this.applyUnmuteAllowedToStream(meeting);
371
+ }
372
+ if (muted !== undefined) {
373
+ this.state.server.remoteMute = muted;
374
+ this.applyServerMuteToLocalStream(meeting, 'remotelyMuted');
375
+ }
290
376
  }
291
377
 
292
378
  /**
@@ -298,27 +384,27 @@ class MuteState {
298
384
  * @returns {undefined}
299
385
  */
300
386
  public handleServerLocalUnmuteRequired(meeting?: object) {
301
- LoggerProxy.logger.info(
302
- `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received -> doing local unmute`
303
- );
387
+ if (!this.state.client.enabled) {
388
+ LoggerProxy.logger.warn(
389
+ `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received while ${this.type} is disabled -> local unmute will not result in ${this.type} being sent`
390
+ );
391
+ } else {
392
+ LoggerProxy.logger.info(
393
+ `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received -> doing local unmute`
394
+ );
395
+ }
304
396
 
397
+ // todo: I'm seeing "you can now unmute yourself " popup when this happens - but same thing happens on web.w.c so we can ignore for now
305
398
  this.state.server.remoteMute = false;
306
399
  this.state.client.localMute = false;
307
400
 
308
- if (this.pendingPromiseReject) {
309
- this.pendingPromiseReject(
310
- new Error('Server requested local unmute - this overrides any client request in progress')
311
- );
312
- this.pendingPromiseResolve = null;
313
- this.pendingPromiseReject = null;
314
- }
315
-
316
- this.applyClientStateLocally(meeting);
401
+ this.applyClientStateLocally(meeting, 'localUnmuteRequired');
317
402
  this.applyClientStateToServer(meeting);
318
403
  }
319
404
 
320
405
  /**
321
- * Returns true if the user is locally or remotely muted
406
+ * Returns true if the user is locally or remotely muted.
407
+ * It only checks the mute status, ignoring the fact whether audio/video is enabled.
322
408
  *
323
409
  * @public
324
410
  * @memberof MuteState
@@ -331,23 +417,35 @@ class MuteState {
331
417
  }
332
418
 
333
419
  /**
334
- * Returns true if the user is muted as a result of the client request (and not remotely muted)
420
+ * Returns true if the user is remotely muted
335
421
  *
336
422
  * @public
337
423
  * @memberof MuteState
338
424
  * @returns {Boolean}
339
425
  */
340
- public isSelf() {
341
- return this.state.client.localMute && !this.state.server.remoteMute;
426
+ public isRemotelyMuted() {
427
+ return this.state.server.remoteMute;
342
428
  }
343
429
 
344
- // defined for backwards compatibility with the old AudioStateMachine/VideoStateMachine classes
345
- get muted() {
346
- return this.isMuted();
430
+ /**
431
+ * Returns true if unmute is allowed
432
+ *
433
+ * @public
434
+ * @memberof MuteState
435
+ * @returns {Boolean}
436
+ */
437
+ public isUnmuteAllowed() {
438
+ return this.state.server.unmuteAllowed;
347
439
  }
348
440
 
349
- // defined for backwards compatibility with the old AudioStateMachine/VideoStateMachine classes
350
- get self() {
351
- return this.isSelf();
441
+ /**
442
+ * Returns true if the user is locally muted or audio/video is disabled
443
+ *
444
+ * @public
445
+ * @memberof MuteState
446
+ * @returns {Boolean}
447
+ */
448
+ public isLocallyMuted() {
449
+ return this.getClientLocalMuteState();
352
450
  }
353
451
  }