@webex/plugin-meetings 3.6.0 → 3.7.0

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 (277) hide show
  1. package/README.md +2 -1
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/common/errors/webinar-registration-error.js +50 -0
  5. package/dist/common/errors/webinar-registration-error.js.map +1 -0
  6. package/dist/config.js +3 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/constants.js +31 -2
  9. package/dist/constants.js.map +1 -1
  10. package/dist/controls-options-manager/enums.js +1 -0
  11. package/dist/controls-options-manager/enums.js.map +1 -1
  12. package/dist/controls-options-manager/index.js +10 -3
  13. package/dist/controls-options-manager/index.js.map +1 -1
  14. package/dist/controls-options-manager/types.js.map +1 -1
  15. package/dist/controls-options-manager/util.js +12 -0
  16. package/dist/controls-options-manager/util.js.map +1 -1
  17. package/dist/index.js +7 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/interpretation/index.js +1 -1
  20. package/dist/interpretation/siLanguage.js +1 -1
  21. package/dist/locus-info/controlsUtils.js +28 -4
  22. package/dist/locus-info/controlsUtils.js.map +1 -1
  23. package/dist/locus-info/fullState.js +2 -1
  24. package/dist/locus-info/fullState.js.map +1 -1
  25. package/dist/locus-info/index.js +61 -3
  26. package/dist/locus-info/index.js.map +1 -1
  27. package/dist/locus-info/parser.js +5 -1
  28. package/dist/locus-info/parser.js.map +1 -1
  29. package/dist/meeting/in-meeting-actions.js +19 -1
  30. package/dist/meeting/in-meeting-actions.js.map +1 -1
  31. package/dist/meeting/index.js +664 -490
  32. package/dist/meeting/index.js.map +1 -1
  33. package/dist/meeting/muteState.js +5 -2
  34. package/dist/meeting/muteState.js.map +1 -1
  35. package/dist/meeting/util.js +3 -2
  36. package/dist/meeting/util.js.map +1 -1
  37. package/dist/meeting-info/meeting-info-v2.js +68 -17
  38. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  39. package/dist/meetings/index.js +25 -1
  40. package/dist/meetings/index.js.map +1 -1
  41. package/dist/members/index.js +3 -2
  42. package/dist/members/index.js.map +1 -1
  43. package/dist/members/util.js +9 -5
  44. package/dist/members/util.js.map +1 -1
  45. package/dist/metrics/constants.js +2 -1
  46. package/dist/metrics/constants.js.map +1 -1
  47. package/dist/multistream/remoteMedia.js +4 -0
  48. package/dist/multistream/remoteMedia.js.map +1 -1
  49. package/dist/networkQualityMonitor/index.js +19 -13
  50. package/dist/networkQualityMonitor/index.js.map +1 -1
  51. package/dist/reachability/index.js +3 -3
  52. package/dist/reachability/index.js.map +1 -1
  53. package/dist/reachability/request.js +2 -1
  54. package/dist/reachability/request.js.map +1 -1
  55. package/dist/roap/request.js +1 -1
  56. package/dist/roap/request.js.map +1 -1
  57. package/dist/{common/errors/parameter.d.ts → types/common/errors/webinar-registration-error.d.ts} +4 -5
  58. package/dist/types/config.d.ts +2 -0
  59. package/dist/types/constants.d.ts +25 -0
  60. package/dist/types/controls-options-manager/enums.d.ts +2 -1
  61. package/dist/types/controls-options-manager/index.d.ts +2 -1
  62. package/dist/types/controls-options-manager/types.d.ts +2 -0
  63. package/dist/types/index.d.ts +2 -1
  64. package/dist/types/locus-info/index.d.ts +9 -0
  65. package/dist/types/meeting/in-meeting-actions.d.ts +18 -0
  66. package/dist/types/meeting/index.d.ts +12 -1
  67. package/dist/types/meeting/muteState.d.ts +2 -1
  68. package/dist/types/meeting-info/meeting-info-v2.d.ts +23 -0
  69. package/dist/types/meetings/index.d.ts +9 -0
  70. package/dist/types/members/index.d.ts +2 -1
  71. package/dist/types/members/util.d.ts +3 -1
  72. package/dist/types/metrics/constants.d.ts +1 -0
  73. package/dist/types/multistream/remoteMedia.d.ts +1 -0
  74. package/dist/webinar/index.js +32 -19
  75. package/dist/webinar/index.js.map +1 -1
  76. package/package.json +22 -22
  77. package/src/common/errors/webinar-registration-error.ts +27 -0
  78. package/src/config.ts +2 -0
  79. package/src/constants.ts +31 -0
  80. package/src/controls-options-manager/enums.ts +1 -0
  81. package/src/controls-options-manager/index.ts +19 -2
  82. package/src/controls-options-manager/types.ts +2 -0
  83. package/src/controls-options-manager/util.ts +12 -0
  84. package/src/index.ts +2 -0
  85. package/src/locus-info/controlsUtils.ts +46 -2
  86. package/src/locus-info/fullState.ts +1 -0
  87. package/src/locus-info/index.ts +60 -0
  88. package/src/locus-info/parser.ts +8 -1
  89. package/src/meeting/in-meeting-actions.ts +37 -0
  90. package/src/meeting/index.ts +154 -20
  91. package/src/meeting/muteState.ts +6 -2
  92. package/src/meeting/util.ts +6 -2
  93. package/src/meeting-info/meeting-info-v2.ts +51 -0
  94. package/src/meetings/index.ts +68 -40
  95. package/src/members/index.ts +4 -2
  96. package/src/members/util.ts +3 -1
  97. package/src/metrics/constants.ts +1 -0
  98. package/src/multistream/remoteMedia.ts +5 -0
  99. package/src/reachability/index.ts +3 -3
  100. package/src/reachability/request.ts +1 -0
  101. package/src/roap/request.ts +3 -1
  102. package/src/webinar/index.ts +31 -17
  103. package/test/unit/spec/controls-options-manager/index.js +56 -32
  104. package/test/unit/spec/controls-options-manager/util.js +44 -0
  105. package/test/unit/spec/locus-info/controlsUtils.js +80 -4
  106. package/test/unit/spec/locus-info/index.js +88 -2
  107. package/test/unit/spec/meeting/in-meeting-actions.ts +18 -0
  108. package/test/unit/spec/meeting/index.js +263 -64
  109. package/test/unit/spec/meeting/muteState.js +8 -4
  110. package/test/unit/spec/meeting/utils.js +16 -1
  111. package/test/unit/spec/meeting-info/meetinginfov2.js +37 -0
  112. package/test/unit/spec/meetings/index.js +32 -1
  113. package/test/unit/spec/members/index.js +25 -2
  114. package/test/unit/spec/members/request.js +37 -3
  115. package/test/unit/spec/members/utils.js +15 -1
  116. package/test/unit/spec/multistream/remoteMedia.ts +16 -2
  117. package/test/unit/spec/reachability/index.ts +1 -1
  118. package/test/unit/spec/reachability/request.js +13 -8
  119. package/test/unit/spec/webinar/index.ts +82 -16
  120. package/dist/annotation/annotation.types.d.ts +0 -42
  121. package/dist/annotation/constants.d.ts +0 -31
  122. package/dist/annotation/index.d.ts +0 -117
  123. package/dist/breakouts/breakout.d.ts +0 -8
  124. package/dist/breakouts/collection.d.ts +0 -5
  125. package/dist/breakouts/edit-lock-error.d.ts +0 -15
  126. package/dist/breakouts/events.d.ts +0 -8
  127. package/dist/breakouts/index.d.ts +0 -5
  128. package/dist/breakouts/request.d.ts +0 -22
  129. package/dist/breakouts/utils.d.ts +0 -15
  130. package/dist/common/browser-detection.d.ts +0 -9
  131. package/dist/common/collection.d.ts +0 -48
  132. package/dist/common/config.d.ts +0 -2
  133. package/dist/common/errors/captcha-error.d.ts +0 -15
  134. package/dist/common/errors/intent-to-join.d.ts +0 -16
  135. package/dist/common/errors/join-meeting.d.ts +0 -17
  136. package/dist/common/errors/media.d.ts +0 -15
  137. package/dist/common/errors/no-meeting-info.d.ts +0 -14
  138. package/dist/common/errors/password-error.d.ts +0 -15
  139. package/dist/common/errors/permission.d.ts +0 -14
  140. package/dist/common/errors/reclaim-host-role-error.js +0 -149
  141. package/dist/common/errors/reclaim-host-role-error.js.map +0 -1
  142. package/dist/common/errors/reclaim-host-role-errors.d.ts +0 -60
  143. package/dist/common/errors/reconnection-in-progress.d.ts +0 -9
  144. package/dist/common/errors/reconnection-in-progress.js +0 -33
  145. package/dist/common/errors/reconnection-in-progress.js.map +0 -1
  146. package/dist/common/errors/reconnection.d.ts +0 -15
  147. package/dist/common/errors/stats.d.ts +0 -15
  148. package/dist/common/errors/webex-errors.d.ts +0 -93
  149. package/dist/common/errors/webex-meetings-error.d.ts +0 -20
  150. package/dist/common/events/events-scope.d.ts +0 -17
  151. package/dist/common/events/events.d.ts +0 -12
  152. package/dist/common/events/trigger-proxy.d.ts +0 -2
  153. package/dist/common/events/util.d.ts +0 -2
  154. package/dist/common/logs/logger-config.d.ts +0 -2
  155. package/dist/common/logs/logger-proxy.d.ts +0 -2
  156. package/dist/common/logs/request.d.ts +0 -36
  157. package/dist/common/queue.d.ts +0 -34
  158. package/dist/config.d.ts +0 -72
  159. package/dist/constants.d.ts +0 -1088
  160. package/dist/controls-options-manager/constants.d.ts +0 -4
  161. package/dist/controls-options-manager/enums.d.ts +0 -15
  162. package/dist/controls-options-manager/index.d.ts +0 -136
  163. package/dist/controls-options-manager/types.d.ts +0 -43
  164. package/dist/controls-options-manager/util.d.ts +0 -1
  165. package/dist/index.d.ts +0 -7
  166. package/dist/interceptors/index.d.ts +0 -2
  167. package/dist/interceptors/locusRetry.d.ts +0 -27
  168. package/dist/interpretation/collection.d.ts +0 -5
  169. package/dist/interpretation/index.d.ts +0 -5
  170. package/dist/interpretation/siLanguage.d.ts +0 -5
  171. package/dist/locus-info/controlsUtils.d.ts +0 -2
  172. package/dist/locus-info/embeddedAppsUtils.d.ts +0 -2
  173. package/dist/locus-info/fullState.d.ts +0 -2
  174. package/dist/locus-info/hostUtils.d.ts +0 -2
  175. package/dist/locus-info/index.d.ts +0 -322
  176. package/dist/locus-info/infoUtils.d.ts +0 -2
  177. package/dist/locus-info/mediaSharesUtils.d.ts +0 -2
  178. package/dist/locus-info/parser.d.ts +0 -272
  179. package/dist/locus-info/selfUtils.d.ts +0 -2
  180. package/dist/media/index.d.ts +0 -34
  181. package/dist/media/properties.d.ts +0 -93
  182. package/dist/media/util.d.ts +0 -2
  183. package/dist/mediaQualityMetrics/config.d.ts +0 -241
  184. package/dist/mediaQualityMetrics/config.js +0 -502
  185. package/dist/mediaQualityMetrics/config.js.map +0 -1
  186. package/dist/meeting/effectsState.js +0 -260
  187. package/dist/meeting/effectsState.js.map +0 -1
  188. package/dist/meeting/in-meeting-actions.d.ts +0 -167
  189. package/dist/meeting/index.d.ts +0 -1825
  190. package/dist/meeting/locusMediaRequest.d.ts +0 -74
  191. package/dist/meeting/muteState.d.ts +0 -178
  192. package/dist/meeting/request.d.ts +0 -295
  193. package/dist/meeting/request.type.d.ts +0 -11
  194. package/dist/meeting/state.d.ts +0 -9
  195. package/dist/meeting/util.d.ts +0 -119
  196. package/dist/meeting/voicea-meeting.d.ts +0 -16
  197. package/dist/meeting-info/collection.d.ts +0 -20
  198. package/dist/meeting-info/index.d.ts +0 -69
  199. package/dist/meeting-info/meeting-info-v2.d.ts +0 -123
  200. package/dist/meeting-info/request.d.ts +0 -22
  201. package/dist/meeting-info/util.d.ts +0 -2
  202. package/dist/meeting-info/utilv2.d.ts +0 -2
  203. package/dist/meetings/collection.d.ts +0 -40
  204. package/dist/meetings/index.d.ts +0 -390
  205. package/dist/meetings/meetings.types.d.ts +0 -4
  206. package/dist/meetings/request.d.ts +0 -27
  207. package/dist/meetings/util.d.ts +0 -18
  208. package/dist/member/index.d.ts +0 -160
  209. package/dist/member/member.types.js +0 -17
  210. package/dist/member/member.types.js.map +0 -1
  211. package/dist/member/types.d.ts +0 -32
  212. package/dist/member/util.d.ts +0 -2
  213. package/dist/members/collection.d.ts +0 -29
  214. package/dist/members/index.d.ts +0 -353
  215. package/dist/members/request.d.ts +0 -114
  216. package/dist/members/types.d.ts +0 -25
  217. package/dist/members/util.d.ts +0 -215
  218. package/dist/metrics/config.js +0 -276
  219. package/dist/metrics/config.js.map +0 -1
  220. package/dist/metrics/constants.d.ts +0 -70
  221. package/dist/metrics/index.d.ts +0 -45
  222. package/dist/multistream/mediaRequestManager.d.ts +0 -119
  223. package/dist/multistream/receiveSlot.d.ts +0 -68
  224. package/dist/multistream/receiveSlotManager.d.ts +0 -56
  225. package/dist/multistream/remoteMedia.d.ts +0 -72
  226. package/dist/multistream/remoteMediaGroup.d.ts +0 -49
  227. package/dist/multistream/remoteMediaManager.d.ts +0 -300
  228. package/dist/multistream/sendSlotManager.d.ts +0 -69
  229. package/dist/networkQualityMonitor/index.d.ts +0 -70
  230. package/dist/peer-connection-manager/index.js +0 -671
  231. package/dist/peer-connection-manager/index.js.map +0 -1
  232. package/dist/peer-connection-manager/util.js +0 -109
  233. package/dist/peer-connection-manager/util.js.map +0 -1
  234. package/dist/personal-meeting-room/index.d.ts +0 -47
  235. package/dist/personal-meeting-room/request.d.ts +0 -14
  236. package/dist/personal-meeting-room/util.d.ts +0 -2
  237. package/dist/reachability/clusterReachability.d.ts +0 -109
  238. package/dist/reachability/index.d.ts +0 -105
  239. package/dist/reachability/request.d.ts +0 -39
  240. package/dist/reachability/util.d.ts +0 -8
  241. package/dist/reactions/constants.d.ts +0 -3
  242. package/dist/reactions/reactions.d.ts +0 -4
  243. package/dist/reactions/reactions.type.d.ts +0 -52
  244. package/dist/reconnection-manager/index.d.ts +0 -136
  245. package/dist/recording-controller/enums.d.ts +0 -7
  246. package/dist/recording-controller/index.d.ts +0 -207
  247. package/dist/recording-controller/util.d.ts +0 -14
  248. package/dist/roap/collection.js +0 -62
  249. package/dist/roap/collection.js.map +0 -1
  250. package/dist/roap/handler.js +0 -275
  251. package/dist/roap/handler.js.map +0 -1
  252. package/dist/roap/index.d.ts +0 -86
  253. package/dist/roap/request.d.ts +0 -39
  254. package/dist/roap/state.js +0 -126
  255. package/dist/roap/state.js.map +0 -1
  256. package/dist/roap/turnDiscovery.d.ts +0 -155
  257. package/dist/roap/util.js +0 -75
  258. package/dist/roap/util.js.map +0 -1
  259. package/dist/rtcMetrics/constants.d.ts +0 -4
  260. package/dist/rtcMetrics/index.d.ts +0 -61
  261. package/dist/statsAnalyzer/global.d.ts +0 -36
  262. package/dist/statsAnalyzer/global.js +0 -126
  263. package/dist/statsAnalyzer/global.js.map +0 -1
  264. package/dist/statsAnalyzer/index.d.ts +0 -217
  265. package/dist/statsAnalyzer/index.js +0 -1013
  266. package/dist/statsAnalyzer/index.js.map +0 -1
  267. package/dist/statsAnalyzer/mqaUtil.d.ts +0 -48
  268. package/dist/statsAnalyzer/mqaUtil.js +0 -179
  269. package/dist/statsAnalyzer/mqaUtil.js.map +0 -1
  270. package/dist/transcription/index.d.ts +0 -64
  271. package/dist/types/common/errors/reconnection-in-progress.d.ts +0 -9
  272. package/dist/types/mediaQualityMetrics/config.d.ts +0 -241
  273. package/dist/types/statsAnalyzer/global.d.ts +0 -36
  274. package/dist/types/statsAnalyzer/index.d.ts +0 -217
  275. package/dist/types/statsAnalyzer/mqaUtil.d.ts +0 -48
  276. package/dist/webinar/collection.d.ts +0 -16
  277. package/dist/webinar/index.d.ts +0 -5
@@ -128,6 +128,7 @@ import {
128
128
  MeetingInfoV2PasswordError,
129
129
  MeetingInfoV2CaptchaError,
130
130
  MeetingInfoV2PolicyError,
131
+ MeetingInfoV2WebinarRegistrationError,
131
132
  } from '../meeting-info/meeting-info-v2';
132
133
  import {CSI, ReceiveSlotManager} from '../multistream/receiveSlotManager';
133
134
  import SendSlotManager from '../multistream/sendSlotManager';
@@ -156,6 +157,7 @@ import ControlsOptionsManager from '../controls-options-manager';
156
157
  import PermissionError from '../common/errors/permission';
157
158
  import {LocusMediaRequest} from './locusMediaRequest';
158
159
  import {ConnectionStateHandler, ConnectionStateEvent} from './connectionStateHandler';
160
+ import WebinarRegistrationError from '../common/errors/webinar-registration-error';
159
161
 
160
162
  // default callback so we don't call an undefined function, but in practice it should never be used
161
163
  const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
@@ -1759,8 +1761,16 @@ export default class Meeting extends StatelessWebexPlugin {
1759
1761
  if (err.meetingInfo) {
1760
1762
  this.meetingInfo = err.meetingInfo;
1761
1763
  }
1762
-
1763
1764
  throw new PermissionError();
1765
+ } else if (err instanceof MeetingInfoV2WebinarRegistrationError) {
1766
+ this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WEBINAR_REGISTRATION;
1767
+ this.meetingInfoFailureCode = err.wbxAppApiCode;
1768
+
1769
+ if (err.meetingInfo) {
1770
+ this.meetingInfo = err.meetingInfo;
1771
+ }
1772
+
1773
+ throw new WebinarRegistrationError();
1764
1774
  } else if (err instanceof MeetingInfoV2PasswordError) {
1765
1775
  LoggerProxy.logger.info(
1766
1776
  // @ts-ignore
@@ -2004,6 +2014,7 @@ export default class Meeting extends StatelessWebexPlugin {
2004
2014
  this.setUpLocusInfoSelfListener();
2005
2015
  this.setUpLocusInfoMeetingListener();
2006
2016
  this.setUpLocusServicesListener();
2017
+ this.setUpLocusResourcesListener();
2007
2018
  // members update listeners
2008
2019
  this.setUpLocusFullStateListener();
2009
2020
  this.setUpLocusUrlListener();
@@ -2625,6 +2636,42 @@ export default class Meeting extends StatelessWebexPlugin {
2625
2636
  );
2626
2637
  });
2627
2638
 
2639
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_WEBCAST_CHANGED, ({state}) => {
2640
+ Trigger.trigger(
2641
+ this,
2642
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2643
+ EVENT_TRIGGERS.MEETING_CONTROLS_WEBCAST_UPDATED,
2644
+ {state}
2645
+ );
2646
+ });
2647
+
2648
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_FULL_CHANGED, ({state}) => {
2649
+ Trigger.trigger(
2650
+ this,
2651
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2652
+ EVENT_TRIGGERS.MEETING_CONTROLS_MEETING_FULL_UPDATED,
2653
+ {state}
2654
+ );
2655
+ });
2656
+
2657
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_PRACTICE_SESSION_STATUS_UPDATED, ({state}) => {
2658
+ Trigger.trigger(
2659
+ this,
2660
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2661
+ EVENT_TRIGGERS.MEETING_CONTROLS_PRACTICE_SESSION_STATUS_UPDATED,
2662
+ {state}
2663
+ );
2664
+ });
2665
+
2666
+ this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_STAGE_VIEW_UPDATED, ({state}) => {
2667
+ Trigger.trigger(
2668
+ this,
2669
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
2670
+ EVENT_TRIGGERS.MEETING_CONTROLS_STAGE_VIEW_UPDATED,
2671
+ {state}
2672
+ );
2673
+ });
2674
+
2628
2675
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_VIDEO_CHANGED, ({state}) => {
2629
2676
  Trigger.trigger(
2630
2677
  this,
@@ -2739,6 +2786,9 @@ export default class Meeting extends StatelessWebexPlugin {
2739
2786
  newShareStatus = SHARE_STATUS.NO_SHARE;
2740
2787
  }
2741
2788
 
2789
+ LoggerProxy.logger.info(
2790
+ `Meeting:index#setUpLocusInfoMediaInactiveListener --> this.shareStatus=${this.shareStatus} newShareStatus=${newShareStatus}`
2791
+ );
2742
2792
  if (newShareStatus !== this.shareStatus) {
2743
2793
  const oldShareStatus = this.shareStatus;
2744
2794
 
@@ -2983,10 +3033,20 @@ export default class Meeting extends StatelessWebexPlugin {
2983
3033
  this.breakouts.breakoutServiceUrlUpdate(payload?.services?.breakout?.url);
2984
3034
  this.annotation.approvalUrlUpdate(payload?.services?.approval?.url);
2985
3035
  this.simultaneousInterpretation.approvalUrlUpdate(payload?.services?.approval?.url);
2986
- this.webinar.webcastUrlUpdate(payload?.services?.webcast?.url);
2987
- this.webinar.webinarAttendeesSearchingUrlUpdate(
2988
- payload?.services?.webinarAttendeesSearching?.url
2989
- );
3036
+ });
3037
+ }
3038
+
3039
+ /**
3040
+ * Set up the locus info resources link listener
3041
+ * update the locusInfo for webcast instance url
3042
+ * @param {Object} payload - The event payload
3043
+ * @returns {undefined}
3044
+ * @private
3045
+ * @memberof Meeting
3046
+ */
3047
+ private setUpLocusResourcesListener() {
3048
+ this.locusInfo.on(LOCUSINFO.EVENTS.LINKS_RESOURCES, (payload) => {
3049
+ this.webinar.updateWebcastUrl(payload);
2990
3050
  });
2991
3051
  }
2992
3052
 
@@ -3091,7 +3151,7 @@ export default class Meeting extends StatelessWebexPlugin {
3091
3151
  private setUpLocusInfoSelfListener() {
3092
3152
  this.locusInfo.on(LOCUSINFO.EVENTS.LOCAL_UNMUTE_REQUIRED, (payload) => {
3093
3153
  if (this.audio) {
3094
- this.audio.handleServerLocalUnmuteRequired(this);
3154
+ this.audio.handleServerLocalUnmuteRequired(this, payload.unmuteAllowed);
3095
3155
  Trigger.trigger(
3096
3156
  this,
3097
3157
  {
@@ -3298,7 +3358,7 @@ export default class Meeting extends StatelessWebexPlugin {
3298
3358
  this.simultaneousInterpretation.updateCanManageInterpreters(
3299
3359
  payload.newRoles?.includes(SELF_ROLES.MODERATOR)
3300
3360
  );
3301
- this.webinar.updateCanManageWebcast(payload.newRoles?.includes(SELF_ROLES.MODERATOR));
3361
+ this.webinar.updateRoleChanged(payload);
3302
3362
  Trigger.trigger(
3303
3363
  this,
3304
3364
  {
@@ -3792,6 +3852,22 @@ export default class Meeting extends StatelessWebexPlugin {
3792
3852
  requiredHints: [DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST],
3793
3853
  displayHints: this.userDisplayHints,
3794
3854
  }),
3855
+ canEnableViewTheParticipantsListPanelist: ControlsOptionsUtil.hasHints({
3856
+ requiredHints: [DISPLAY_HINTS.ENABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST],
3857
+ displayHints: this.userDisplayHints,
3858
+ }),
3859
+ canDisableViewTheParticipantsListPanelist: ControlsOptionsUtil.hasHints({
3860
+ requiredHints: [DISPLAY_HINTS.DISABLE_VIEW_THE_PARTICIPANT_LIST_PANELIST],
3861
+ displayHints: this.userDisplayHints,
3862
+ }),
3863
+ canEnableShowAttendeeCount: ControlsOptionsUtil.hasHints({
3864
+ requiredHints: [DISPLAY_HINTS.ENABLE_SHOW_ATTENDEE_COUNT],
3865
+ displayHints: this.userDisplayHints,
3866
+ }),
3867
+ canDisableShowAttendeeCount: ControlsOptionsUtil.hasHints({
3868
+ requiredHints: [DISPLAY_HINTS.DISABLE_SHOW_ATTENDEE_COUNT],
3869
+ displayHints: this.userDisplayHints,
3870
+ }),
3795
3871
  canEnableRaiseHand: ControlsOptionsUtil.hasHints({
3796
3872
  requiredHints: [DISPLAY_HINTS.ENABLE_RAISE_HAND],
3797
3873
  displayHints: this.userDisplayHints,
@@ -3808,6 +3884,26 @@ export default class Meeting extends StatelessWebexPlugin {
3808
3884
  requiredHints: [DISPLAY_HINTS.DISABLE_VIDEO],
3809
3885
  displayHints: this.userDisplayHints,
3810
3886
  }),
3887
+ canStartWebcast: ControlsOptionsUtil.hasHints({
3888
+ requiredHints: [DISPLAY_HINTS.WEBCAST_CONTROL_START],
3889
+ displayHints: this.userDisplayHints,
3890
+ }),
3891
+ canStopWebcast: ControlsOptionsUtil.hasHints({
3892
+ requiredHints: [DISPLAY_HINTS.WEBCAST_CONTROL_STOP],
3893
+ displayHints: this.userDisplayHints,
3894
+ }),
3895
+ canShowStageView: ControlsOptionsUtil.hasHints({
3896
+ requiredHints: [DISPLAY_HINTS.STAGE_VIEW_ACTIVE],
3897
+ displayHints: this.userDisplayHints,
3898
+ }),
3899
+ canEnableStageView: ControlsOptionsUtil.hasHints({
3900
+ requiredHints: [DISPLAY_HINTS.ENABLE_STAGE_VIEW],
3901
+ displayHints: this.userDisplayHints,
3902
+ }),
3903
+ canDisableStageView: ControlsOptionsUtil.hasHints({
3904
+ requiredHints: [DISPLAY_HINTS.DISABLE_STAGE_VIEW],
3905
+ displayHints: this.userDisplayHints,
3906
+ }),
3811
3907
  canShareFile:
3812
3908
  (ControlsOptionsUtil.hasHints({
3813
3909
  requiredHints: [DISPLAY_HINTS.SHARE_FILE],
@@ -4808,6 +4904,8 @@ export default class Meeting extends StatelessWebexPlugin {
4808
4904
  );
4809
4905
  }
4810
4906
 
4907
+ this.cleanUpBeforeReconnection();
4908
+
4811
4909
  return this.reconnectionManager
4812
4910
  .reconnect(options, async () => {
4813
4911
  await this.waitForRemoteSDPAnswer();
@@ -6225,7 +6323,7 @@ export default class Meeting extends StatelessWebexPlugin {
6225
6323
  this.mediaProperties.webrtcMediaConnection.on(
6226
6324
  MediaConnectionEventNames.ICE_CANDIDATE,
6227
6325
  (event) => {
6228
- if (event.candidate) {
6326
+ if (event.candidate && event.candidate.candidate && event.candidate.candidate.length > 0) {
6229
6327
  this.iceCandidatesCount += 1;
6230
6328
  }
6231
6329
  }
@@ -6936,6 +7034,23 @@ export default class Meeting extends StatelessWebexPlugin {
6936
7034
  }
6937
7035
  }
6938
7036
 
7037
+ private async cleanUpBeforeReconnection(): Promise<void> {
7038
+ try {
7039
+ // when media fails, we want to upload a webrtc dump to see whats going on
7040
+ // this function is async, but returns once the stats have been gathered
7041
+ await this.forceSendStatsReport({callFrom: 'cleanUpBeforeReconnection'});
7042
+
7043
+ if (this.statsAnalyzer) {
7044
+ await this.statsAnalyzer.stopAnalyzer();
7045
+ }
7046
+ } catch (error) {
7047
+ LoggerProxy.logger.error(
7048
+ 'Meeting:index#cleanUpBeforeReconnection --> Error during cleanup: ',
7049
+ error
7050
+ );
7051
+ }
7052
+ }
7053
+
6939
7054
  /**
6940
7055
  * Creates an instance of LocusMediaRequest for this meeting - it is needed for doing any calls
6941
7056
  * to Locus /media API (these are used for sending Roap messages and updating audio/video mute status).
@@ -7027,7 +7142,7 @@ export default class Meeting extends StatelessWebexPlugin {
7027
7142
  shareAudioEnabled = true,
7028
7143
  shareVideoEnabled = true,
7029
7144
  remoteMediaManagerConfig,
7030
- bundlePolicy,
7145
+ bundlePolicy = 'max-bundle',
7031
7146
  } = options;
7032
7147
 
7033
7148
  this.allowMediaInLobby = options?.allowMediaInLobby;
@@ -7914,18 +8029,21 @@ export default class Meeting extends StatelessWebexPlugin {
7914
8029
  * @param {boolean} mutedEnabled
7915
8030
  * @param {boolean} disallowUnmuteEnabled
7916
8031
  * @param {boolean} muteOnEntryEnabled
8032
+ * @param {array} roles
7917
8033
  * @public
7918
8034
  * @memberof Meeting
7919
8035
  */
7920
8036
  public setMuteAll(
7921
8037
  mutedEnabled: boolean,
7922
8038
  disallowUnmuteEnabled: boolean,
7923
- muteOnEntryEnabled: boolean
8039
+ muteOnEntryEnabled: boolean,
8040
+ roles: Array<string>
7924
8041
  ) {
7925
8042
  return this.controlsOptionsManager.setMuteAll(
7926
8043
  mutedEnabled,
7927
8044
  disallowUnmuteEnabled,
7928
- muteOnEntryEnabled
8045
+ muteOnEntryEnabled,
8046
+ roles
7929
8047
  );
7930
8048
  }
7931
8049
 
@@ -8182,6 +8300,9 @@ export default class Meeting extends StatelessWebexPlugin {
8182
8300
  * @returns {undefined}
8183
8301
  */
8184
8302
  private handleShareAudioStreamEnded = async () => {
8303
+ LoggerProxy.logger.info(
8304
+ `Meeting:index#handleShareAudioStreamEnded --> audio share stream ended`
8305
+ );
8185
8306
  // current share audio stream has ended, but there might be an active
8186
8307
  // share video stream. we only leave from wireless share if share has
8187
8308
  // completely ended, which means no share audio or video streams active
@@ -8224,6 +8345,9 @@ export default class Meeting extends StatelessWebexPlugin {
8224
8345
  * @returns {undefined}
8225
8346
  */
8226
8347
  private handleShareVideoStreamEnded = async () => {
8348
+ LoggerProxy.logger.info(
8349
+ `Meeting:index#handleShareVideoStreamEnded --> video share stream ended`
8350
+ );
8227
8351
  // current share video stream has ended, but there might be an active
8228
8352
  // share audio stream. we only leave from wireless share if share has
8229
8353
  // completely ended, which means no share audio or video streams active
@@ -8712,6 +8836,9 @@ export default class Meeting extends StatelessWebexPlugin {
8712
8836
  * @returns {Promise}
8713
8837
  */
8714
8838
  async publishStreams(streams: LocalStreams): Promise<void> {
8839
+ LoggerProxy.logger.info(
8840
+ `Meeting:index#publishStreams --> called with: ${JSON.stringify(streams)}`
8841
+ );
8715
8842
  this.checkMediaConnection();
8716
8843
  if (
8717
8844
  !streams.microphone &&
@@ -8723,15 +8850,19 @@ export default class Meeting extends StatelessWebexPlugin {
8723
8850
  return;
8724
8851
  }
8725
8852
 
8726
- if (
8727
- streams?.microphone?.readyState === 'ended' ||
8728
- streams?.camera?.readyState === 'ended' ||
8729
- streams?.screenShare?.audio?.readyState === 'ended' ||
8730
- streams?.screenShare?.video?.readyState === 'ended'
8731
- ) {
8732
- throw new Error(
8733
- `Attempted to publish stream with ended readyState, correlationId=${this.correlationId}`
8734
- );
8853
+ const streamChecks = [
8854
+ {stream: streams?.microphone, name: 'microphone'},
8855
+ {stream: streams?.camera, name: 'camera'},
8856
+ {stream: streams?.screenShare?.audio, name: 'screenShare audio'},
8857
+ {stream: streams?.screenShare?.video, name: 'screenShare video'},
8858
+ ];
8859
+
8860
+ for (const {stream, name} of streamChecks) {
8861
+ if (stream?.readyState === 'ended') {
8862
+ throw new Error(
8863
+ `Attempted to publish ${name} stream with ended readyState, correlationId=${this.correlationId}`
8864
+ );
8865
+ }
8735
8866
  }
8736
8867
 
8737
8868
  let floorRequestNeeded = false;
@@ -8793,6 +8924,9 @@ export default class Meeting extends StatelessWebexPlugin {
8793
8924
  * @returns {Promise}
8794
8925
  */
8795
8926
  async unpublishStreams(streams: LocalStream[]): Promise<void> {
8927
+ LoggerProxy.logger.info(
8928
+ `Meeting:index#unpublishStreams --> called with: ${JSON.stringify(streams)}`
8929
+ );
8796
8930
  this.checkMediaConnection();
8797
8931
 
8798
8932
  const promises = [];
@@ -394,21 +394,25 @@ export class MuteState {
394
394
  * @public
395
395
  * @memberof MuteState
396
396
  * @param {Object} [meeting] the meeting object
397
+ * @param {Boolean} [unmuteAllowed] whether the user is allowed to unmute self
397
398
  * @returns {undefined}
398
399
  */
399
- public handleServerLocalUnmuteRequired(meeting?: any) {
400
+ public handleServerLocalUnmuteRequired(meeting: any, unmuteAllowed: boolean) {
400
401
  if (!this.state.client.enabled) {
401
402
  LoggerProxy.logger.warn(
402
403
  `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received while ${this.type} is disabled -> local unmute will not result in ${this.type} being sent`
403
404
  );
404
405
  } else {
405
406
  LoggerProxy.logger.info(
406
- `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received -> doing local unmute`
407
+ `Meeting:muteState#handleServerLocalUnmuteRequired --> ${this.type}: localAudioUnmuteRequired received -> doing local unmute (unmuteAllowed=${unmuteAllowed})`
407
408
  );
408
409
  }
409
410
 
410
411
  // 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
411
412
  this.state.server.remoteMute = false;
413
+ this.state.server.unmuteAllowed = unmuteAllowed;
414
+
415
+ this.applyUnmuteAllowedToStream(meeting);
412
416
 
413
417
  // change user mute state to false, but keep localMute true if overall mute state is still true
414
418
  this.muteLocalStream(meeting, false, 'localUnmuteRequired');
@@ -89,8 +89,12 @@ const MeetingUtil = {
89
89
  getIpVersion(webex: any): IP_VERSION | undefined {
90
90
  const {supportsIpV4, supportsIpV6} = webex.internal.device.ipNetworkDetector;
91
91
 
92
- if (BrowserDetection().isBrowser('firefox')) {
93
- // our ipv6 solution relies on FQDN ICE candidates, but Firefox doesn't support them,
92
+ if (
93
+ !webex.config.meetings.backendIpv6NativeSupport &&
94
+ BrowserDetection().isBrowser('firefox')
95
+ ) {
96
+ // when backend doesn't support native ipv6,
97
+ // then our NAT64/DNS64 based solution relies on FQDN ICE candidates, but Firefox doesn't support them,
94
98
  // see https://bugzilla.mozilla.org/show_bug.cgi?id=1713128
95
99
  // so for Firefox we don't want the backend to activate the "ipv6 feature"
96
100
  return undefined;
@@ -18,6 +18,7 @@ const ADHOC_MEETING_DEFAULT_ERROR =
18
18
  'Failed starting the adhoc meeting, Please contact support team ';
19
19
  const CAPTCHA_ERROR_REQUIRES_PASSWORD_CODES = [423005, 423006];
20
20
  const POLICY_ERROR_CODES = [403049, 403104, 403103, 403048, 403102, 403101];
21
+ const WEBINAR_REGISTRATION_ERROR_CODES = [403021, 403022, 403024];
21
22
  /**
22
23
  * Error to indicate that wbxappapi requires a password
23
24
  */
@@ -124,6 +125,31 @@ export class MeetingInfoV2CaptchaError extends Error {
124
125
  }
125
126
  }
126
127
 
128
+ /**
129
+ * Error preventing join because of a webinar registration error
130
+ */
131
+ export class MeetingInfoV2WebinarRegistrationError extends Error {
132
+ meetingInfo: any;
133
+ sdkMessage: any;
134
+ wbxAppApiCode: any;
135
+ body: any;
136
+ /**
137
+ *
138
+ * @constructor
139
+ * @param {Number} [wbxAppApiErrorCode]
140
+ * @param {Object} [meetingInfo]
141
+ * @param {String} [message]
142
+ */
143
+ constructor(wbxAppApiErrorCode?: number, meetingInfo?: object, message?: string) {
144
+ super(`${message}, code=${wbxAppApiErrorCode}`);
145
+ this.name = 'MeetingInfoV2WebinarRegistrationError';
146
+ this.sdkMessage = message;
147
+ this.stack = new Error().stack;
148
+ this.wbxAppApiCode = wbxAppApiErrorCode;
149
+ this.meetingInfo = meetingInfo;
150
+ }
151
+ }
152
+
127
153
  /**
128
154
  * @class MeetingInfo
129
155
  */
@@ -177,6 +203,29 @@ export default class MeetingInfoV2 {
177
203
  }
178
204
  };
179
205
 
206
+ /**
207
+ * Raises a handleWebinarRegistrationError for webinar registration error codes
208
+ * @param {any} err the error from the request
209
+ * @returns {void}
210
+ */
211
+ handleWebinarRegistrationError = (err) => {
212
+ if (!err.body) {
213
+ return;
214
+ }
215
+
216
+ if (WEBINAR_REGISTRATION_ERROR_CODES.includes(err.body?.code)) {
217
+ Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.WEBINAR_REGISTRATION_ERROR, {
218
+ code: err.body?.code,
219
+ });
220
+
221
+ throw new MeetingInfoV2WebinarRegistrationError(
222
+ err.body?.code,
223
+ err.body?.data?.meetingInfo,
224
+ err.body?.message
225
+ );
226
+ }
227
+ };
228
+
180
229
  /**
181
230
  * Creates adhoc space meetings for a space by fetching the conversation infomation
182
231
  * @param {String} conversationUrl conversationUrl to start adhoc meeting on
@@ -237,6 +286,7 @@ export default class MeetingInfoV2 {
237
286
  })
238
287
  .catch((err) => {
239
288
  this.handlePolicyError(err);
289
+ this.handleWebinarRegistrationError(err);
240
290
 
241
291
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADHOC_MEETING_FAILURE, {
242
292
  reason: err.message,
@@ -391,6 +441,7 @@ export default class MeetingInfoV2 {
391
441
 
392
442
  if (err?.statusCode === 403) {
393
443
  this.handlePolicyError(err);
444
+ this.handleWebinarRegistrationError(err);
394
445
 
395
446
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.VERIFY_PASSWORD_ERROR, {
396
447
  reason: err.message,
@@ -56,6 +56,7 @@ import MeetingCollection from './collection';
56
56
  import {MEETING_KEY, INoiseReductionEffect, IVirtualBackgroundEffect} from './meetings.types';
57
57
  import MeetingsUtil from './util';
58
58
  import PermissionError from '../common/errors/permission';
59
+ import WebinarRegistrationError from '../common/errors/webinar-registration-error';
59
60
  import {SpaceIDDeprecatedError} from '../common/errors/webex-errors';
60
61
  import NoMeetingInfoError from '../common/errors/no-meeting-info';
61
62
 
@@ -762,6 +763,25 @@ export default class Meetings extends WebexPlugin {
762
763
  }
763
764
  }
764
765
 
766
+ /**
767
+ * API to toggle backend ipv6 native support config, needs to be called before webex.meetings.register()
768
+ *
769
+ * @param {Boolean} newValue
770
+ * @private
771
+ * @memberof Meetings
772
+ * @returns {undefined}
773
+ */
774
+ private _toggleIpv6BackendNativeSupport(newValue: boolean) {
775
+ if (typeof newValue !== 'boolean') {
776
+ return;
777
+ }
778
+ // @ts-ignore
779
+ if (this.config.backendIpv6NativeSupport !== newValue) {
780
+ // @ts-ignore
781
+ this.config.backendIpv6NativeSupport = newValue;
782
+ }
783
+ }
784
+
765
785
  /**
766
786
  * Explicitly sets up the meetings plugin by registering
767
787
  * the device, connecting to mercury, and listening for locus events.
@@ -1024,48 +1044,55 @@ export default class Meetings extends WebexPlugin {
1024
1044
  */
1025
1045
  fetchUserPreferredWebexSite() {
1026
1046
  // @ts-ignore
1027
- return this.webex.people._getMe().then((me) => {
1028
- const isGuestUser = me.type === 'appuser';
1029
- if (!isGuestUser) {
1030
- return this.request.getMeetingPreferences().then((res) => {
1031
- if (res) {
1032
- const preferredWebexSite = MeetingsUtil.parseDefaultSiteFromMeetingPreferences(res);
1033
- this.preferredWebexSite = preferredWebexSite;
1034
- // @ts-ignore
1035
- this.webex.internal.services._getCatalog().addAllowedDomains([preferredWebexSite]);
1036
- }
1047
+ return this.webex.people
1048
+ ._getMe()
1049
+ .then((me) => {
1050
+ const isGuestUser = me.type === 'appuser';
1051
+ if (!isGuestUser) {
1052
+ return this.request.getMeetingPreferences().then((res) => {
1053
+ if (res) {
1054
+ const preferredWebexSite = MeetingsUtil.parseDefaultSiteFromMeetingPreferences(res);
1055
+ this.preferredWebexSite = preferredWebexSite;
1056
+ // @ts-ignore
1057
+ this.webex.internal.services._getCatalog().addAllowedDomains([preferredWebexSite]);
1058
+ }
1037
1059
 
1038
- // fall back to getting the preferred site from the user information
1039
- if (!this.preferredWebexSite) {
1040
- // @ts-ignore
1041
- return this.webex.internal.user
1042
- .get()
1043
- .then((user) => {
1044
- const preferredWebexSite =
1045
- user?.userPreferences?.userPreferencesItems?.preferredWebExSite;
1046
- if (preferredWebexSite) {
1047
- this.preferredWebexSite = preferredWebexSite;
1048
- // @ts-ignore
1049
- this.webex.internal.services
1050
- ._getCatalog()
1051
- .addAllowedDomains([preferredWebexSite]);
1052
- } else {
1053
- throw new Error('site not found');
1054
- }
1055
- })
1056
- .catch(() => {
1057
- LoggerProxy.logger.error(
1058
- 'Failed to fetch preferred site from user - no site will be set'
1059
- );
1060
- });
1061
- }
1060
+ // fall back to getting the preferred site from the user information
1061
+ if (!this.preferredWebexSite) {
1062
+ // @ts-ignore
1063
+ return this.webex.internal.user
1064
+ .get()
1065
+ .then((user) => {
1066
+ const preferredWebexSite =
1067
+ user?.userPreferences?.userPreferencesItems?.preferredWebExSite;
1068
+ if (preferredWebexSite) {
1069
+ this.preferredWebexSite = preferredWebexSite;
1070
+ // @ts-ignore
1071
+ this.webex.internal.services
1072
+ ._getCatalog()
1073
+ .addAllowedDomains([preferredWebexSite]);
1074
+ } else {
1075
+ throw new Error('site not found');
1076
+ }
1077
+ })
1078
+ .catch(() => {
1079
+ LoggerProxy.logger.error(
1080
+ 'Failed to fetch preferred site from user - no site will be set'
1081
+ );
1082
+ });
1083
+ }
1062
1084
 
1063
- return Promise.resolve();
1064
- });
1065
- }
1085
+ return Promise.resolve();
1086
+ });
1087
+ }
1066
1088
 
1067
- return Promise.resolve();
1068
- });
1089
+ return Promise.resolve();
1090
+ })
1091
+ .catch(() => {
1092
+ LoggerProxy.logger.error(
1093
+ 'Failed to retrieve user information. No preferredWebexSite will be set'
1094
+ );
1095
+ });
1069
1096
  }
1070
1097
 
1071
1098
  /**
@@ -1378,7 +1405,8 @@ export default class Meetings extends WebexPlugin {
1378
1405
  if (
1379
1406
  !(err instanceof CaptchaError) &&
1380
1407
  !(err instanceof PasswordError) &&
1381
- !(err instanceof PermissionError)
1408
+ !(err instanceof PermissionError) &&
1409
+ !(err instanceof WebinarRegistrationError)
1382
1410
  ) {
1383
1411
  LoggerProxy.logger.info(
1384
1412
  `Meetings:index#createMeeting --> Info Unable to fetch meeting info for ${destination}.`
@@ -915,11 +915,12 @@ export default class Members extends StatelessWebexPlugin {
915
915
  /**
916
916
  * Lower all hands of members in a meeting
917
917
  * @param {String} requestingMemberId - id of the participant which requested the lower all hands
918
+ * @param {array} roles which should be lowered
918
919
  * @returns {Promise}
919
920
  * @public
920
921
  * @memberof Members
921
922
  */
922
- public lowerAllHands(requestingMemberId: string) {
923
+ public lowerAllHands(requestingMemberId: string, roles: Array<string>) {
923
924
  if (!this.locusUrl) {
924
925
  return Promise.reject(
925
926
  new ParameterError(
@@ -936,7 +937,8 @@ export default class Members extends StatelessWebexPlugin {
936
937
  }
937
938
  const options = MembersUtil.generateLowerAllHandsMemberOptions(
938
939
  requestingMemberId,
939
- this.locusUrl
940
+ this.locusUrl,
941
+ roles
940
942
  );
941
943
 
942
944
  return this.membersRequest.lowerAllHandsMember(options);
@@ -166,9 +166,10 @@ const MembersUtil = {
166
166
  locusUrl,
167
167
  }),
168
168
 
169
- generateLowerAllHandsMemberOptions: (requestingParticipantId, locusUrl) => ({
169
+ generateLowerAllHandsMemberOptions: (requestingParticipantId, locusUrl, roles) => ({
170
170
  requestingParticipantId,
171
171
  locusUrl,
172
+ ...(roles !== undefined && {roles}),
172
173
  }),
173
174
 
174
175
  /**
@@ -253,6 +254,7 @@ const MembersUtil = {
253
254
  const body = {
254
255
  hand: {
255
256
  raised: false,
257
+ ...(options.roles !== undefined && {roles: options.roles}),
256
258
  },
257
259
  requestingParticipantId: options.requestingParticipantId,
258
260
  };
@@ -70,6 +70,7 @@ const BEHAVIORAL_METRICS = {
70
70
  ROAP_HTTP_RESPONSE_MISSING: 'js_sdk_roap_http_response_missing',
71
71
  TURN_DISCOVERY_REQUIRES_OK: 'js_sdk_turn_discovery_requires_ok',
72
72
  REACHABILITY_COMPLETED: 'js_sdk_reachability_completed',
73
+ WEBINAR_REGISTRATION_ERROR: 'js_sdk_webinar_registration_error',
73
74
  };
74
75
 
75
76
  export {BEHAVIORAL_METRICS as default};
@@ -107,11 +107,16 @@ export class RemoteMedia extends EventsScope {
107
107
  * to restrict the requested resolution to this size
108
108
  * @param width width of the video element
109
109
  * @param height height of the video element
110
+ * @note width/height of 0 will be ignored
110
111
  */
111
112
  public setSizeHint(width, height) {
112
113
  // only base on height for now
113
114
  let fs: number;
114
115
 
116
+ if (width === 0 || height === 0) {
117
+ return;
118
+ }
119
+
115
120
  if (height < 135) {
116
121
  fs = 60;
117
122
  } else if (height < 270) {