@webex/plugin-meetings 3.7.0 → 3.8.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.
- package/dist/annotation/annotation.types.d.ts +42 -0
- package/dist/annotation/constants.d.ts +31 -0
- package/dist/annotation/index.d.ts +117 -0
- package/dist/annotation/index.js +17 -0
- package/dist/annotation/index.js.map +1 -1
- package/dist/breakouts/breakout.d.ts +8 -0
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/collection.d.ts +5 -0
- package/dist/breakouts/edit-lock-error.d.ts +15 -0
- package/dist/breakouts/events.d.ts +8 -0
- package/dist/breakouts/index.d.ts +5 -0
- package/dist/breakouts/index.js +1 -1
- package/dist/breakouts/request.d.ts +22 -0
- package/dist/breakouts/utils.d.ts +15 -0
- package/dist/common/browser-detection.d.ts +9 -0
- package/dist/common/collection.d.ts +48 -0
- package/dist/common/config.d.ts +2 -0
- package/dist/common/errors/captcha-error.d.ts +15 -0
- package/dist/common/errors/intent-to-join.d.ts +16 -0
- package/dist/common/errors/join-forbidden-error.js +52 -0
- package/dist/common/errors/join-forbidden-error.js.map +1 -0
- package/dist/common/errors/join-meeting.d.ts +17 -0
- package/dist/common/errors/{webinar-registration-error.js → join-webinar-error.js} +12 -12
- package/dist/common/errors/join-webinar-error.js.map +1 -0
- package/dist/common/errors/media.d.ts +15 -0
- package/dist/common/errors/multistream-not-supported-error.js +53 -0
- package/dist/common/errors/multistream-not-supported-error.js.map +1 -0
- package/dist/common/errors/no-meeting-info.d.ts +14 -0
- package/dist/common/errors/parameter.d.ts +15 -0
- package/dist/common/errors/password-error.d.ts +15 -0
- package/dist/common/errors/permission.d.ts +14 -0
- package/dist/common/errors/reclaim-host-role-error.js +149 -0
- package/dist/common/errors/reclaim-host-role-error.js.map +1 -0
- package/dist/common/errors/reclaim-host-role-errors.d.ts +60 -0
- package/dist/common/errors/reconnection-in-progress.d.ts +9 -0
- package/dist/common/errors/reconnection-in-progress.js +33 -0
- package/dist/common/errors/reconnection-in-progress.js.map +1 -0
- package/dist/common/errors/reconnection.d.ts +15 -0
- package/dist/common/errors/stats.d.ts +15 -0
- package/dist/common/errors/webex-errors.d.ts +93 -0
- package/dist/common/errors/webex-meetings-error.d.ts +20 -0
- package/dist/common/events/events-scope.d.ts +17 -0
- package/dist/common/events/events.d.ts +12 -0
- package/dist/common/events/trigger-proxy.d.ts +2 -0
- package/dist/common/events/util.d.ts +2 -0
- package/dist/common/logs/logger-config.d.ts +2 -0
- package/dist/common/logs/logger-proxy.d.ts +2 -0
- package/dist/common/logs/request.d.ts +36 -0
- package/dist/common/queue.d.ts +34 -0
- package/dist/config.d.ts +72 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +1088 -0
- package/dist/constants.js +68 -6
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.d.ts +4 -0
- package/dist/controls-options-manager/enums.d.ts +15 -0
- package/dist/controls-options-manager/index.d.ts +136 -0
- package/dist/controls-options-manager/types.d.ts +43 -0
- package/dist/controls-options-manager/util.d.ts +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +16 -11
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.d.ts +2 -0
- package/dist/interceptors/locusRetry.d.ts +27 -0
- package/dist/interpretation/collection.d.ts +5 -0
- package/dist/interpretation/index.d.ts +5 -0
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.d.ts +5 -0
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.d.ts +2 -0
- package/dist/locus-info/embeddedAppsUtils.d.ts +2 -0
- package/dist/locus-info/fullState.d.ts +2 -0
- package/dist/locus-info/hostUtils.d.ts +2 -0
- package/dist/locus-info/index.d.ts +322 -0
- package/dist/locus-info/index.js +14 -3
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.d.ts +2 -0
- package/dist/locus-info/mediaSharesUtils.d.ts +2 -0
- package/dist/locus-info/parser.d.ts +272 -0
- package/dist/locus-info/selfUtils.d.ts +2 -0
- package/dist/locus-info/selfUtils.js +35 -17
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/MediaConnectionAwaiter.js +1 -0
- package/dist/media/MediaConnectionAwaiter.js.map +1 -1
- package/dist/media/index.d.ts +34 -0
- package/dist/media/properties.d.ts +93 -0
- package/dist/media/properties.js +30 -16
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.d.ts +2 -0
- package/dist/mediaQualityMetrics/config.d.ts +241 -0
- package/dist/mediaQualityMetrics/config.js +502 -0
- package/dist/mediaQualityMetrics/config.js.map +1 -0
- package/dist/meeting/brbState.js +167 -0
- package/dist/meeting/brbState.js.map +1 -0
- package/dist/meeting/effectsState.js +260 -0
- package/dist/meeting/effectsState.js.map +1 -0
- package/dist/meeting/in-meeting-actions.d.ts +167 -0
- package/dist/meeting/in-meeting-actions.js +13 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.d.ts +1825 -0
- package/dist/meeting/index.js +1331 -1051
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.d.ts +74 -0
- package/dist/meeting/locusMediaRequest.js +11 -6
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/muteState.d.ts +178 -0
- package/dist/meeting/muteState.js +1 -6
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.d.ts +295 -0
- package/dist/meeting/request.js +51 -29
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.d.ts +11 -0
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/state.d.ts +9 -0
- package/dist/meeting/util.d.ts +119 -0
- package/dist/meeting/util.js +103 -67
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting/voicea-meeting.d.ts +16 -0
- package/dist/meeting-info/collection.d.ts +20 -0
- package/dist/meeting-info/index.d.ts +69 -0
- package/dist/meeting-info/meeting-info-v2.d.ts +123 -0
- package/dist/meeting-info/meeting-info-v2.js +115 -45
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/request.d.ts +22 -0
- package/dist/meeting-info/util.d.ts +2 -0
- package/dist/meeting-info/utilv2.d.ts +2 -0
- package/dist/meeting-info/utilv2.js +6 -2
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.d.ts +40 -0
- package/dist/meetings/index.d.ts +390 -0
- package/dist/meetings/index.js +107 -55
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.d.ts +4 -0
- package/dist/meetings/meetings.types.js +2 -0
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/request.d.ts +27 -0
- package/dist/meetings/util.d.ts +18 -0
- package/dist/meetings/util.js +1 -1
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.d.ts +160 -0
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/member.types.js +17 -0
- package/dist/member/member.types.js.map +1 -0
- package/dist/member/types.d.ts +32 -0
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.d.ts +2 -0
- package/dist/member/util.js +39 -28
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.d.ts +29 -0
- package/dist/members/index.d.ts +353 -0
- package/dist/members/request.d.ts +114 -0
- package/dist/members/types.d.ts +25 -0
- package/dist/members/util.d.ts +215 -0
- package/dist/members/util.js +4 -2
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/config.js +276 -0
- package/dist/metrics/config.js.map +1 -0
- package/dist/metrics/constants.d.ts +70 -0
- package/dist/metrics/constants.js +6 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.d.ts +45 -0
- package/dist/multistream/mediaRequestManager.d.ts +119 -0
- package/dist/multistream/receiveSlot.d.ts +68 -0
- package/dist/multistream/receiveSlotManager.d.ts +56 -0
- package/dist/multistream/remoteMedia.d.ts +72 -0
- package/dist/multistream/remoteMedia.js +30 -15
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.d.ts +49 -0
- package/dist/multistream/remoteMediaManager.d.ts +300 -0
- package/dist/multistream/sendSlotManager.d.ts +69 -0
- package/dist/multistream/sendSlotManager.js +24 -0
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/networkQualityMonitor/index.d.ts +70 -0
- package/dist/networkQualityMonitor/index.js +13 -19
- package/dist/networkQualityMonitor/index.js.map +1 -1
- package/dist/peer-connection-manager/index.js +671 -0
- package/dist/peer-connection-manager/index.js.map +1 -0
- package/dist/peer-connection-manager/util.js +109 -0
- package/dist/peer-connection-manager/util.js.map +1 -0
- package/dist/personal-meeting-room/index.d.ts +47 -0
- package/dist/personal-meeting-room/request.d.ts +14 -0
- package/dist/personal-meeting-room/util.d.ts +2 -0
- package/dist/reachability/clusterReachability.d.ts +109 -0
- package/dist/reachability/clusterReachability.js +12 -15
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.d.ts +105 -0
- package/dist/reachability/index.js +461 -136
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/reachability.types.js +7 -0
- package/dist/reachability/reachability.types.js.map +1 -0
- package/dist/reachability/request.d.ts +39 -0
- package/dist/reachability/request.js +21 -8
- package/dist/reachability/request.js.map +1 -1
- package/dist/reachability/util.d.ts +8 -0
- package/dist/reactions/constants.d.ts +3 -0
- package/dist/reactions/reactions.d.ts +4 -0
- package/dist/reactions/reactions.type.d.ts +52 -0
- package/dist/reconnection-manager/index.d.ts +136 -0
- package/dist/recording-controller/enums.d.ts +7 -0
- package/dist/recording-controller/enums.js +8 -4
- package/dist/recording-controller/enums.js.map +1 -1
- package/dist/recording-controller/index.d.ts +207 -0
- package/dist/recording-controller/index.js +18 -9
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.d.ts +14 -0
- package/dist/recording-controller/util.js +13 -9
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/collection.js +62 -0
- package/dist/roap/collection.js.map +1 -0
- package/dist/roap/handler.js +275 -0
- package/dist/roap/handler.js.map +1 -0
- package/dist/roap/index.d.ts +86 -0
- package/dist/roap/index.js +15 -15
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.d.ts +39 -0
- package/dist/roap/request.js +45 -79
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/state.js +126 -0
- package/dist/roap/state.js.map +1 -0
- package/dist/roap/turnDiscovery.d.ts +155 -0
- package/dist/roap/turnDiscovery.js +3 -6
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/roap/util.js +75 -0
- package/dist/roap/util.js.map +1 -0
- package/dist/rtcMetrics/constants.d.ts +4 -0
- package/dist/rtcMetrics/index.d.ts +61 -0
- package/dist/statsAnalyzer/global.d.ts +36 -0
- package/dist/statsAnalyzer/global.js +126 -0
- package/dist/statsAnalyzer/global.js.map +1 -0
- package/dist/statsAnalyzer/index.d.ts +217 -0
- package/dist/statsAnalyzer/index.js +1013 -0
- package/dist/statsAnalyzer/index.js.map +1 -0
- package/dist/statsAnalyzer/mqaUtil.d.ts +48 -0
- package/dist/statsAnalyzer/mqaUtil.js +179 -0
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -0
- package/dist/transcription/index.d.ts +64 -0
- package/dist/types/annotation/index.d.ts +5 -0
- package/dist/types/common/errors/join-forbidden-error.d.ts +15 -0
- package/dist/types/common/errors/{webinar-registration-error.d.ts → join-webinar-error.d.ts} +2 -2
- package/dist/types/common/errors/multistream-not-supported-error.d.ts +17 -0
- package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
- package/dist/types/config.d.ts +1 -0
- package/dist/types/constants.d.ts +53 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/locus-info/index.d.ts +2 -1
- package/dist/types/mediaQualityMetrics/config.d.ts +241 -0
- package/dist/types/meeting/brbState.d.ts +54 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +12 -0
- package/dist/types/meeting/index.d.ts +64 -14
- package/dist/types/meeting/locusMediaRequest.d.ts +6 -3
- package/dist/types/meeting/request.d.ts +14 -3
- package/dist/types/meeting/request.type.d.ts +6 -0
- package/dist/types/meeting/util.d.ts +3 -3
- package/dist/types/meeting-info/meeting-info-v2.d.ts +30 -5
- package/dist/types/meetings/index.d.ts +20 -2
- package/dist/types/meetings/meetings.types.d.ts +8 -0
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/types.d.ts +7 -0
- package/dist/types/members/util.d.ts +2 -0
- package/dist/types/metrics/constants.d.ts +6 -1
- package/dist/types/multistream/sendSlotManager.d.ts +8 -1
- package/dist/types/reachability/clusterReachability.d.ts +1 -10
- package/dist/types/reachability/index.d.ts +83 -36
- package/dist/types/reachability/reachability.types.d.ts +64 -0
- package/dist/types/reachability/request.d.ts +5 -1
- package/dist/types/recording-controller/enums.d.ts +5 -2
- package/dist/types/recording-controller/index.d.ts +1 -0
- package/dist/types/recording-controller/util.d.ts +2 -1
- package/dist/types/roap/request.d.ts +1 -13
- package/dist/types/statsAnalyzer/global.d.ts +36 -0
- package/dist/types/statsAnalyzer/index.d.ts +217 -0
- package/dist/types/statsAnalyzer/mqaUtil.d.ts +48 -0
- package/dist/webinar/collection.d.ts +16 -0
- package/dist/webinar/index.d.ts +5 -0
- package/dist/webinar/index.js +390 -7
- package/dist/webinar/index.js.map +1 -1
- package/package.json +23 -22
- package/src/annotation/index.ts +16 -0
- package/src/common/errors/join-forbidden-error.ts +26 -0
- package/src/common/errors/join-webinar-error.ts +24 -0
- package/src/common/errors/multistream-not-supported-error.ts +30 -0
- package/src/config.ts +1 -0
- package/src/constants.ts +61 -3
- package/src/index.ts +5 -3
- package/src/locus-info/index.ts +20 -3
- package/src/locus-info/selfUtils.ts +24 -6
- package/src/media/MediaConnectionAwaiter.ts +2 -0
- package/src/media/properties.ts +34 -13
- package/src/meeting/brbState.ts +169 -0
- package/src/meeting/in-meeting-actions.ts +25 -0
- package/src/meeting/index.ts +443 -87
- package/src/meeting/locusMediaRequest.ts +11 -8
- package/src/meeting/muteState.ts +1 -6
- package/src/meeting/request.ts +30 -12
- package/src/meeting/request.type.ts +7 -0
- package/src/meeting/util.ts +32 -13
- package/src/meeting-info/meeting-info-v2.ts +83 -12
- package/src/meeting-info/utilv2.ts +17 -3
- package/src/meetings/index.ts +79 -20
- package/src/meetings/meetings.types.ts +10 -0
- package/src/meetings/util.ts +2 -1
- package/src/member/index.ts +9 -0
- package/src/member/types.ts +8 -0
- package/src/member/util.ts +34 -24
- package/src/members/util.ts +1 -0
- package/src/metrics/constants.ts +6 -1
- package/src/multistream/remoteMedia.ts +28 -15
- package/src/multistream/sendSlotManager.ts +31 -0
- package/src/reachability/clusterReachability.ts +5 -15
- package/src/reachability/index.ts +311 -75
- package/src/reachability/reachability.types.ts +85 -0
- package/src/reachability/request.ts +55 -31
- package/src/recording-controller/enums.ts +5 -2
- package/src/recording-controller/index.ts +17 -4
- package/src/recording-controller/util.ts +20 -5
- package/src/roap/index.ts +14 -13
- package/src/roap/request.ts +30 -44
- package/src/roap/turnDiscovery.ts +2 -4
- package/src/webinar/index.ts +235 -9
- package/test/unit/spec/annotation/index.ts +46 -1
- package/test/unit/spec/locus-info/index.js +292 -60
- package/test/unit/spec/locus-info/selfConstant.js +7 -0
- package/test/unit/spec/locus-info/selfUtils.js +101 -1
- package/test/unit/spec/media/properties.ts +15 -0
- package/test/unit/spec/meeting/brbState.ts +114 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +15 -1
- package/test/unit/spec/meeting/index.js +851 -107
- package/test/unit/spec/meeting/locusMediaRequest.ts +18 -11
- package/test/unit/spec/meeting/muteState.js +0 -24
- package/test/unit/spec/meeting/request.js +3 -26
- package/test/unit/spec/meeting/utils.js +73 -28
- package/test/unit/spec/meeting-info/meetinginfov2.js +46 -4
- package/test/unit/spec/meeting-info/utilv2.js +26 -0
- package/test/unit/spec/meetings/index.js +159 -18
- package/test/unit/spec/meetings/utils.js +10 -0
- package/test/unit/spec/member/util.js +52 -11
- package/test/unit/spec/members/utils.js +95 -0
- package/test/unit/spec/multistream/remoteMedia.ts +11 -7
- package/test/unit/spec/reachability/clusterReachability.ts +7 -0
- package/test/unit/spec/reachability/index.ts +383 -9
- package/test/unit/spec/reachability/request.js +48 -12
- package/test/unit/spec/recording-controller/index.js +61 -5
- package/test/unit/spec/recording-controller/util.js +39 -3
- package/test/unit/spec/roap/index.ts +48 -1
- package/test/unit/spec/roap/request.ts +51 -109
- package/test/unit/spec/roap/turnDiscovery.ts +202 -147
- package/test/unit/spec/webinar/index.ts +504 -0
- package/dist/common/errors/webinar-registration-error.js.map +0 -1
- package/src/common/errors/webinar-registration-error.ts +0 -27
package/src/meeting/index.ts
CHANGED
@@ -5,6 +5,7 @@ import jwtDecode from 'jwt-decode';
|
|
5
5
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
6
6
|
// @ts-ignore - Types not available for @webex/common
|
7
7
|
import {Defer} from '@webex/common';
|
8
|
+
import {safeSetTimeout, safeSetInterval} from '@webex/common-timers';
|
8
9
|
import {
|
9
10
|
ClientEvent,
|
10
11
|
ClientEventLeaveReason,
|
@@ -30,7 +31,6 @@ import {
|
|
30
31
|
} from '@webex/internal-media-core';
|
31
32
|
|
32
33
|
import {
|
33
|
-
getDevices,
|
34
34
|
LocalStream,
|
35
35
|
LocalCameraStream,
|
36
36
|
LocalDisplayStream,
|
@@ -121,6 +121,10 @@ import {
|
|
121
121
|
MEETING_PERMISSION_TOKEN_REFRESH_REASON,
|
122
122
|
ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT,
|
123
123
|
NAMED_MEDIA_GROUP_TYPE_AUDIO,
|
124
|
+
WEBINAR_ERROR_WEBCAST,
|
125
|
+
WEBINAR_ERROR_REGISTRATION_ID,
|
126
|
+
JOIN_BEFORE_HOST,
|
127
|
+
REGISTRATION_ID_STATUS,
|
124
128
|
} from '../constants';
|
125
129
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
126
130
|
import ParameterError from '../common/errors/parameter';
|
@@ -128,7 +132,8 @@ import {
|
|
128
132
|
MeetingInfoV2PasswordError,
|
129
133
|
MeetingInfoV2CaptchaError,
|
130
134
|
MeetingInfoV2PolicyError,
|
131
|
-
|
135
|
+
MeetingInfoV2JoinWebinarError,
|
136
|
+
MeetingInfoV2JoinForbiddenError,
|
132
137
|
} from '../meeting-info/meeting-info-v2';
|
133
138
|
import {CSI, ReceiveSlotManager} from '../multistream/receiveSlotManager';
|
134
139
|
import SendSlotManager from '../multistream/sendSlotManager';
|
@@ -157,7 +162,11 @@ import ControlsOptionsManager from '../controls-options-manager';
|
|
157
162
|
import PermissionError from '../common/errors/permission';
|
158
163
|
import {LocusMediaRequest} from './locusMediaRequest';
|
159
164
|
import {ConnectionStateHandler, ConnectionStateEvent} from './connectionStateHandler';
|
160
|
-
import
|
165
|
+
import JoinWebinarError from '../common/errors/join-webinar-error';
|
166
|
+
import Member from '../member';
|
167
|
+
import {BrbState, createBrbState} from './brbState';
|
168
|
+
import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error';
|
169
|
+
import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
161
170
|
|
162
171
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
163
172
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
@@ -248,6 +257,7 @@ export enum ScreenShareFloorStatus {
|
|
248
257
|
|
249
258
|
type FetchMeetingInfoParams = {
|
250
259
|
password?: string;
|
260
|
+
registrationId?: string;
|
251
261
|
captchaCode?: string;
|
252
262
|
extraParams?: Record<string, any>;
|
253
263
|
sendCAevents?: boolean;
|
@@ -642,6 +652,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
642
652
|
turnServerUsed: boolean;
|
643
653
|
areVoiceaEventsSetup = false;
|
644
654
|
isMoveToInProgress = false;
|
655
|
+
registrationIdStatus: string;
|
656
|
+
brbState: BrbState;
|
645
657
|
|
646
658
|
voiceaListenerCallbacks: object = {
|
647
659
|
[VOICEAEVENTS.VOICEA_ANNOUNCEMENT]: (payload: Transcription['languageOptions']) => {
|
@@ -702,6 +714,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
702
714
|
private iceCandidateErrors: Map<string, number>;
|
703
715
|
private iceCandidatesCount: number;
|
704
716
|
private rtcMetrics?: RtcMetrics;
|
717
|
+
private uploadLogsTimer?: ReturnType<typeof setTimeout>;
|
718
|
+
private logUploadIntervalIndex: number;
|
705
719
|
|
706
720
|
/**
|
707
721
|
* @param {Object} attrs
|
@@ -770,6 +784,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
770
784
|
);
|
771
785
|
this.callStateForMetrics.correlationId = this.id;
|
772
786
|
}
|
787
|
+
this.logUploadIntervalIndex = 0;
|
788
|
+
|
773
789
|
/**
|
774
790
|
* @instance
|
775
791
|
* @type {String}
|
@@ -843,7 +859,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
843
859
|
* @memberof Meeting
|
844
860
|
*/
|
845
861
|
// @ts-ignore
|
846
|
-
this.webinar = new Webinar({}, {parent: this.webex});
|
862
|
+
this.webinar = new Webinar({meetingId: this.id}, {parent: this.webex});
|
847
863
|
/**
|
848
864
|
* helper class for managing receive slots (for multistream media connections)
|
849
865
|
*/
|
@@ -1334,6 +1350,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1334
1350
|
*/
|
1335
1351
|
this.passwordStatus = PASSWORD_STATUS.UNKNOWN;
|
1336
1352
|
|
1353
|
+
/**
|
1354
|
+
* registrationId status. If it's REGISTRATIONID_STATUS.REQUIRED then verifyRegistrationId() needs to be called
|
1355
|
+
* with the correct registrationId before calling join()
|
1356
|
+
* @instance
|
1357
|
+
* @type {REGISTRATION_ID_STATUS}
|
1358
|
+
* @public
|
1359
|
+
* @memberof Meeting
|
1360
|
+
*/
|
1361
|
+
this.registrationIdStatus = REGISTRATION_ID_STATUS.UNKNOWN;
|
1362
|
+
|
1337
1363
|
/**
|
1338
1364
|
* Information about required captcha. If null, then no captcha is required. status. If it's PASSWORD_STATUS.REQUIRED then verifyPassword() needs to be called
|
1339
1365
|
* with the correct password before calling join()
|
@@ -1646,6 +1672,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1646
1672
|
this.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
|
1647
1673
|
}
|
1648
1674
|
|
1675
|
+
if (
|
1676
|
+
this.registrationIdStatus === REGISTRATION_ID_STATUS.REQUIRED ||
|
1677
|
+
this.registrationIdStatus === REGISTRATION_ID_STATUS.VERIFIED
|
1678
|
+
) {
|
1679
|
+
this.registrationIdStatus = REGISTRATION_ID_STATUS.VERIFIED;
|
1680
|
+
} else {
|
1681
|
+
this.registrationIdStatus = REGISTRATION_ID_STATUS.NOT_REQUIRED;
|
1682
|
+
}
|
1683
|
+
|
1649
1684
|
Trigger.trigger(
|
1650
1685
|
this,
|
1651
1686
|
{
|
@@ -1689,7 +1724,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1689
1724
|
* @private
|
1690
1725
|
*/
|
1691
1726
|
private prepForFetchMeetingInfo(
|
1692
|
-
{
|
1727
|
+
{
|
1728
|
+
password = null,
|
1729
|
+
registrationId = null,
|
1730
|
+
captchaCode = null,
|
1731
|
+
extraParams = {},
|
1732
|
+
}: FetchMeetingInfoParams,
|
1693
1733
|
caller: string
|
1694
1734
|
): Promise<void> {
|
1695
1735
|
// when fetch meeting info is called directly by the client, we want to clear out the random timer for sdk to do it
|
@@ -1729,6 +1769,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1729
1769
|
captchaCode = null,
|
1730
1770
|
extraParams = {},
|
1731
1771
|
sendCAevents = false,
|
1772
|
+
registrationId = null,
|
1732
1773
|
}): Promise<void> {
|
1733
1774
|
try {
|
1734
1775
|
const captchaInfo = captchaCode
|
@@ -1744,7 +1785,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1744
1785
|
this.config.installedOrgID,
|
1745
1786
|
this.locusId,
|
1746
1787
|
extraParams,
|
1747
|
-
{meetingId: this.id, sendCAevents}
|
1788
|
+
{meetingId: this.id, sendCAevents},
|
1789
|
+
registrationId
|
1748
1790
|
);
|
1749
1791
|
|
1750
1792
|
this.parseMeetingInfo(info?.body, this.destination, info?.errors);
|
@@ -1762,15 +1804,35 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1762
1804
|
this.meetingInfo = err.meetingInfo;
|
1763
1805
|
}
|
1764
1806
|
throw new PermissionError();
|
1765
|
-
} else if (err instanceof
|
1807
|
+
} else if (err instanceof MeetingInfoV2JoinWebinarError) {
|
1766
1808
|
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WEBINAR_REGISTRATION;
|
1809
|
+
if (WEBINAR_ERROR_WEBCAST.includes(err.wbxAppApiCode)) {
|
1810
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NEED_JOIN_WITH_WEBCAST;
|
1811
|
+
} else if (WEBINAR_ERROR_REGISTRATION_ID.includes(err.wbxAppApiCode)) {
|
1812
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WEBINAR_NEED_REGISTRATION_ID;
|
1813
|
+
}
|
1814
|
+
this.meetingInfoFailureCode = err.wbxAppApiCode;
|
1815
|
+
|
1816
|
+
if (err.meetingInfo) {
|
1817
|
+
this.meetingInfo = err.meetingInfo;
|
1818
|
+
}
|
1819
|
+
this.requiredCaptcha = null;
|
1820
|
+
|
1821
|
+
throw new JoinWebinarError();
|
1822
|
+
} else if (err instanceof MeetingInfoV2JoinForbiddenError) {
|
1823
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.JOIN_FORBIDDEN;
|
1767
1824
|
this.meetingInfoFailureCode = err.wbxAppApiCode;
|
1768
1825
|
|
1769
1826
|
if (err.meetingInfo) {
|
1770
1827
|
this.meetingInfo = err.meetingInfo;
|
1771
1828
|
}
|
1772
1829
|
|
1773
|
-
|
1830
|
+
// Handle the case where user hasn't reached Join Before Host (JBH) time (error code 403003)
|
1831
|
+
if (JOIN_BEFORE_HOST === err.wbxAppApiCode) {
|
1832
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH;
|
1833
|
+
}
|
1834
|
+
|
1835
|
+
throw new JoinForbiddenError(this.meetingInfoFailureReason, err);
|
1774
1836
|
} else if (err instanceof MeetingInfoV2PasswordError) {
|
1775
1837
|
LoggerProxy.logger.info(
|
1776
1838
|
// @ts-ignore
|
@@ -1799,9 +1861,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1799
1861
|
`Meeting:index#fetchMeetingInfo --> Info Unable to fetch meeting info for ${this.destination} - captcha required (code=${err?.body?.code}).`
|
1800
1862
|
);
|
1801
1863
|
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1864
|
+
if (this.requiredCaptcha) {
|
1865
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WRONG_CAPTCHA;
|
1866
|
+
} else if (err.isRegistrationIdRequired) {
|
1867
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WRONG_REGISTRATION_ID;
|
1868
|
+
} else {
|
1869
|
+
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD;
|
1870
|
+
}
|
1805
1871
|
|
1806
1872
|
this.meetingInfoFailureCode = err.wbxAppApiCode;
|
1807
1873
|
|
@@ -1809,6 +1875,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1809
1875
|
this.passwordStatus = PASSWORD_STATUS.REQUIRED;
|
1810
1876
|
}
|
1811
1877
|
|
1878
|
+
if (err.isRegistrationIdRequired) {
|
1879
|
+
this.registrationIdStatus = REGISTRATION_ID_STATUS.REQUIRED;
|
1880
|
+
}
|
1881
|
+
|
1812
1882
|
this.requiredCaptcha = err.captchaInfo;
|
1813
1883
|
throw new CaptchaError();
|
1814
1884
|
} else {
|
@@ -1949,6 +2019,48 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1949
2019
|
});
|
1950
2020
|
}
|
1951
2021
|
|
2022
|
+
/**
|
2023
|
+
* Checks if the supplied registrationId is correct. It returns a promise with information whether the
|
2024
|
+
* registrationId and captcha code were correct or not.
|
2025
|
+
* @param {String | undefined} registrationId - can be undefined if only captcha was required
|
2026
|
+
* @param {String | undefined} captchaCode - can be undefined if captcha was not required by the server
|
2027
|
+
* @param {Boolean} sendCAevents - whether Call Analyzer events should be sent when fetching meeting information
|
2028
|
+
* @public
|
2029
|
+
* @memberof Meeting
|
2030
|
+
* @returns {Promise<{isRegistrationIdValid: boolean, requiredCaptcha: boolean, failureReason: MEETING_INFO_FAILURE_REASON}>}
|
2031
|
+
*/
|
2032
|
+
public verifyRegistrationId(registrationId: string, captchaCode: string, sendCAevents = false) {
|
2033
|
+
return this.fetchMeetingInfo({
|
2034
|
+
registrationId,
|
2035
|
+
captchaCode,
|
2036
|
+
sendCAevents,
|
2037
|
+
})
|
2038
|
+
.then(() => {
|
2039
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.VERIFY_REGISTRATION_ID_SUCCESS);
|
2040
|
+
|
2041
|
+
return {
|
2042
|
+
isRegistrationIdValid: true,
|
2043
|
+
requiredCaptcha: null,
|
2044
|
+
failureReason: MEETING_INFO_FAILURE_REASON.NONE,
|
2045
|
+
};
|
2046
|
+
})
|
2047
|
+
.catch((error) => {
|
2048
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.VERIFY_REGISTRATION_ID_ERROR);
|
2049
|
+
|
2050
|
+
if (error instanceof JoinWebinarError || error instanceof CaptchaError) {
|
2051
|
+
return {
|
2052
|
+
isRegistrationIdValid: this.registrationIdStatus === REGISTRATION_ID_STATUS.VERIFIED,
|
2053
|
+
requiredCaptcha: this.requiredCaptcha,
|
2054
|
+
failureReason:
|
2055
|
+
error instanceof JoinWebinarError
|
2056
|
+
? MEETING_INFO_FAILURE_REASON.WRONG_REGISTRATION_ID
|
2057
|
+
: this.meetingInfoFailureReason,
|
2058
|
+
};
|
2059
|
+
}
|
2060
|
+
throw error;
|
2061
|
+
});
|
2062
|
+
}
|
2063
|
+
|
1952
2064
|
/**
|
1953
2065
|
* Refreshes the captcha. As a result the meeting will have new captcha id, image and audio.
|
1954
2066
|
* If the refresh operation fails, meeting remains with the old captcha properties.
|
@@ -2655,6 +2767,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
2655
2767
|
});
|
2656
2768
|
|
2657
2769
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_PRACTICE_SESSION_STATUS_UPDATED, ({state}) => {
|
2770
|
+
this.webinar.updatePracticeSessionStatus(state);
|
2658
2771
|
Trigger.trigger(
|
2659
2772
|
this,
|
2660
2773
|
{file: 'meeting/index', function: 'setupLocusControlsListener'},
|
@@ -2728,6 +2841,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
2728
2841
|
this.triggerAnnotationInfoEvent(contentShare, previousContentShare);
|
2729
2842
|
|
2730
2843
|
if (
|
2844
|
+
!payload.forceUpdate &&
|
2731
2845
|
contentShare.beneficiaryId === previousContentShare?.beneficiaryId &&
|
2732
2846
|
contentShare.disposition === previousContentShare?.disposition &&
|
2733
2847
|
contentShare.deviceUrlSharing === previousContentShare.deviceUrlSharing &&
|
@@ -2774,7 +2888,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
2774
2888
|
// It does not matter who requested to share the whiteboard, everyone gets the same view
|
2775
2889
|
else if (whiteboardShare.disposition === FLOOR_ACTION.GRANTED) {
|
2776
2890
|
// WHITEBOARD - sharing whiteboard
|
2777
|
-
|
2891
|
+
// Webinar attendee should receive whiteboard as remote share
|
2892
|
+
newShareStatus =
|
2893
|
+
this.locusInfo?.info?.isWebinar && this.webinar?.selfIsAttendee
|
2894
|
+
? SHARE_STATUS.REMOTE_SHARE_ACTIVE
|
2895
|
+
: SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
|
2778
2896
|
}
|
2779
2897
|
// or if content share is either released or null and whiteboard share is either released or null, no one is sharing
|
2780
2898
|
else if (
|
@@ -2789,6 +2907,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
2789
2907
|
LoggerProxy.logger.info(
|
2790
2908
|
`Meeting:index#setUpLocusInfoMediaInactiveListener --> this.shareStatus=${this.shareStatus} newShareStatus=${newShareStatus}`
|
2791
2909
|
);
|
2910
|
+
|
2792
2911
|
if (newShareStatus !== this.shareStatus) {
|
2793
2912
|
const oldShareStatus = this.shareStatus;
|
2794
2913
|
|
@@ -3046,7 +3165,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3046
3165
|
*/
|
3047
3166
|
private setUpLocusResourcesListener() {
|
3048
3167
|
this.locusInfo.on(LOCUSINFO.EVENTS.LINKS_RESOURCES, (payload) => {
|
3049
|
-
|
3168
|
+
if (payload) {
|
3169
|
+
this.webinar.updateWebcastUrl(payload);
|
3170
|
+
Trigger.trigger(
|
3171
|
+
this,
|
3172
|
+
{
|
3173
|
+
file: 'meeting/index',
|
3174
|
+
function: 'setUpLocusInfoMeetingInfoListener',
|
3175
|
+
},
|
3176
|
+
EVENT_TRIGGERS.MEETING_RESOURCE_LINKS_UPDATE,
|
3177
|
+
{
|
3178
|
+
payload,
|
3179
|
+
}
|
3180
|
+
);
|
3181
|
+
}
|
3050
3182
|
});
|
3051
3183
|
}
|
3052
3184
|
|
@@ -3249,6 +3381,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3249
3381
|
options: {meetingId: this.id},
|
3250
3382
|
});
|
3251
3383
|
}
|
3384
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.GUEST_ENTERED_LOBBY, {
|
3385
|
+
correlation_id: this.correlationId,
|
3386
|
+
});
|
3252
3387
|
this.updateLLMConnection();
|
3253
3388
|
});
|
3254
3389
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ADMITTED_GUEST, async (payload) => {
|
@@ -3272,6 +3407,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3272
3407
|
name: 'client.lobby.exited',
|
3273
3408
|
options: {meetingId: this.id},
|
3274
3409
|
});
|
3410
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.GUEST_EXITED_LOBBY, {
|
3411
|
+
correlation_id: this.correlationId,
|
3412
|
+
});
|
3275
3413
|
}
|
3276
3414
|
this.rtcMetrics?.sendNextMetrics();
|
3277
3415
|
this.updateLLMConnection();
|
@@ -3293,6 +3431,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3293
3431
|
// The second on is if the audio is muted, we need to tell the statsAnalyzer when
|
3294
3432
|
// the audio is muted or the user is not willing to send media
|
3295
3433
|
this.locusInfo.on(LOCUSINFO.EVENTS.MEDIA_STATUS_CHANGE, (status) => {
|
3434
|
+
LoggerProxy.logger.info(
|
3435
|
+
'Meeting:index#setUpLocusInfoSelfListener --> MEDIA_STATUS_CHANGE received, processing...'
|
3436
|
+
);
|
3437
|
+
|
3296
3438
|
if (this.statsAnalyzer) {
|
3297
3439
|
this.statsAnalyzer.updateMediaStatus({
|
3298
3440
|
actual: status,
|
@@ -3306,6 +3448,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3306
3448
|
receiveShare: this.mediaProperties.mediaDirection?.receiveShare,
|
3307
3449
|
},
|
3308
3450
|
});
|
3451
|
+
} else {
|
3452
|
+
LoggerProxy.logger.warn(
|
3453
|
+
'Meeting:index#setUpLocusInfoSelfListener --> MEDIA_STATUS_CHANGE, statsAnalyzer is not available.'
|
3454
|
+
);
|
3309
3455
|
}
|
3310
3456
|
});
|
3311
3457
|
|
@@ -3350,6 +3496,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3350
3496
|
}
|
3351
3497
|
});
|
3352
3498
|
|
3499
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED, (payload) => {
|
3500
|
+
this.brbState?.handleServerBrbUpdate(payload?.brb?.enabled);
|
3501
|
+
Trigger.trigger(
|
3502
|
+
this,
|
3503
|
+
{
|
3504
|
+
file: 'meeting/index',
|
3505
|
+
function: 'setUpLocusInfoSelfListener',
|
3506
|
+
},
|
3507
|
+
EVENT_TRIGGERS.MEETING_SELF_BRB_UPDATE,
|
3508
|
+
{
|
3509
|
+
payload,
|
3510
|
+
}
|
3511
|
+
);
|
3512
|
+
});
|
3513
|
+
|
3353
3514
|
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ROLES_CHANGED, (payload) => {
|
3354
3515
|
const isModeratorOrCohost =
|
3355
3516
|
payload.newRoles?.includes(SELF_ROLES.MODERATOR) ||
|
@@ -3359,6 +3520,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3359
3520
|
payload.newRoles?.includes(SELF_ROLES.MODERATOR)
|
3360
3521
|
);
|
3361
3522
|
this.webinar.updateRoleChanged(payload);
|
3523
|
+
|
3362
3524
|
Trigger.trigger(
|
3363
3525
|
this,
|
3364
3526
|
{
|
@@ -3505,6 +3667,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3505
3667
|
emailAddress: string;
|
3506
3668
|
email: string;
|
3507
3669
|
phoneNumber: string;
|
3670
|
+
roles: Array<string>;
|
3508
3671
|
},
|
3509
3672
|
alertIfActive = true
|
3510
3673
|
) {
|
@@ -3552,6 +3715,35 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3552
3715
|
return this.members.admitMembers(memberIds, locusUrls);
|
3553
3716
|
}
|
3554
3717
|
|
3718
|
+
/**
|
3719
|
+
* Manages be right back status updates for the current participant.
|
3720
|
+
*
|
3721
|
+
* @param {boolean} enabled - Indicates whether the user enabled brb or not.
|
3722
|
+
* @returns {Promise<void>} resolves when the brb status is updated or does nothing if not in a multistream meeting.
|
3723
|
+
* @throws {Error} - Throws an error if the request fails.
|
3724
|
+
*/
|
3725
|
+
public async beRightBack(enabled: boolean): Promise<void> {
|
3726
|
+
if (!this.isMultistream) {
|
3727
|
+
const errorMessage = 'Meeting:index#beRightBack --> Not a multistream meeting';
|
3728
|
+
const error = new Error(errorMessage);
|
3729
|
+
|
3730
|
+
LoggerProxy.logger.error(error);
|
3731
|
+
|
3732
|
+
return Promise.reject(error);
|
3733
|
+
}
|
3734
|
+
|
3735
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
3736
|
+
const errorMessage = 'Meeting:index#beRightBack --> WebRTC media connection is not defined';
|
3737
|
+
const error = new Error(errorMessage);
|
3738
|
+
|
3739
|
+
LoggerProxy.logger.error(error);
|
3740
|
+
|
3741
|
+
return Promise.reject(error);
|
3742
|
+
}
|
3743
|
+
|
3744
|
+
return this.brbState.enable(enabled, this.sendSlotManager);
|
3745
|
+
}
|
3746
|
+
|
3555
3747
|
/**
|
3556
3748
|
* Remove the member from the meeting, boot them
|
3557
3749
|
* @param {String} memberId
|
@@ -3761,6 +3953,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3761
3953
|
this.userDisplayHints,
|
3762
3954
|
this.selfUserPolicies
|
3763
3955
|
),
|
3956
|
+
isPremiseRecordingEnabled: RecordingUtil.isPremiseRecordingEnabled(
|
3957
|
+
this.userDisplayHints,
|
3958
|
+
this.selfUserPolicies
|
3959
|
+
),
|
3764
3960
|
canRaiseHand: MeetingUtil.canUserRaiseHand(this.userDisplayHints),
|
3765
3961
|
canLowerAllHands: MeetingUtil.canUserLowerAllHands(this.userDisplayHints),
|
3766
3962
|
canLowerSomeoneElsesHand: MeetingUtil.canUserLowerSomeoneElsesHand(this.userDisplayHints),
|
@@ -3787,6 +3983,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3787
3983
|
this.userDisplayHints
|
3788
3984
|
),
|
3789
3985
|
canManageBreakout: MeetingUtil.canManageBreakout(this.userDisplayHints),
|
3986
|
+
canStartBreakout: MeetingUtil.canStartBreakout(this.userDisplayHints),
|
3790
3987
|
canBroadcastMessageToBreakout: MeetingUtil.canBroadcastMessageToBreakout(
|
3791
3988
|
this.userDisplayHints,
|
3792
3989
|
this.selfUserPolicies
|
@@ -3904,6 +4101,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
3904
4101
|
requiredHints: [DISPLAY_HINTS.DISABLE_STAGE_VIEW],
|
3905
4102
|
displayHints: this.userDisplayHints,
|
3906
4103
|
}),
|
4104
|
+
isPracticeSessionOn: ControlsOptionsUtil.hasHints({
|
4105
|
+
requiredHints: [DISPLAY_HINTS.PRACTICE_SESSION_ON],
|
4106
|
+
displayHints: this.userDisplayHints,
|
4107
|
+
}),
|
4108
|
+
isPracticeSessionOff: ControlsOptionsUtil.hasHints({
|
4109
|
+
requiredHints: [DISPLAY_HINTS.PRACTICE_SESSION_OFF],
|
4110
|
+
displayHints: this.userDisplayHints,
|
4111
|
+
}),
|
4112
|
+
canStartPracticeSession: ControlsOptionsUtil.hasHints({
|
4113
|
+
requiredHints: [DISPLAY_HINTS.SHOW_PRACTICE_SESSION_START],
|
4114
|
+
displayHints: this.userDisplayHints,
|
4115
|
+
}),
|
4116
|
+
canStopPracticeSession: ControlsOptionsUtil.hasHints({
|
4117
|
+
requiredHints: [DISPLAY_HINTS.SHOW_PRACTICE_SESSION_STOP],
|
4118
|
+
displayHints: this.userDisplayHints,
|
4119
|
+
}),
|
3907
4120
|
canShareFile:
|
3908
4121
|
(ControlsOptionsUtil.hasHints({
|
3909
4122
|
requiredHints: [DISPLAY_HINTS.SHARE_FILE],
|
@@ -4060,6 +4273,66 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4060
4273
|
Trigger.trigger(this, options, EVENTS.REQUEST_UPLOAD_LOGS, this);
|
4061
4274
|
}
|
4062
4275
|
|
4276
|
+
/**
|
4277
|
+
* sets the timer for periodic log upload
|
4278
|
+
* @returns {void}
|
4279
|
+
*/
|
4280
|
+
private setLogUploadTimer() {
|
4281
|
+
// start with short timeouts and increase them later on so in case users have very long multi-hour meetings we don't get too fragmented logs
|
4282
|
+
const LOG_UPLOAD_INTERVALS = [0.1, 15, 30, 60]; // in minutes
|
4283
|
+
|
4284
|
+
const delay =
|
4285
|
+
1000 *
|
4286
|
+
60 *
|
4287
|
+
// @ts-ignore - config coming from registerPlugin
|
4288
|
+
this.config.logUploadIntervalMultiplicationFactor *
|
4289
|
+
LOG_UPLOAD_INTERVALS[this.logUploadIntervalIndex];
|
4290
|
+
|
4291
|
+
if (this.logUploadIntervalIndex < LOG_UPLOAD_INTERVALS.length - 1) {
|
4292
|
+
this.logUploadIntervalIndex += 1;
|
4293
|
+
}
|
4294
|
+
|
4295
|
+
this.uploadLogsTimer = safeSetTimeout(() => {
|
4296
|
+
this.uploadLogsTimer = undefined;
|
4297
|
+
|
4298
|
+
this.uploadLogs();
|
4299
|
+
|
4300
|
+
// just as an extra precaution, to avoid uploading logs forever in case something goes wrong
|
4301
|
+
// and the page remains opened, we stop it if there is no media connection
|
4302
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
4303
|
+
return;
|
4304
|
+
}
|
4305
|
+
|
4306
|
+
this.setLogUploadTimer();
|
4307
|
+
}, delay);
|
4308
|
+
}
|
4309
|
+
|
4310
|
+
/**
|
4311
|
+
* Starts a periodic upload of logs
|
4312
|
+
*
|
4313
|
+
* @returns {undefined}
|
4314
|
+
*/
|
4315
|
+
public startPeriodicLogUpload() {
|
4316
|
+
// @ts-ignore - config coming from registerPlugin
|
4317
|
+
if (this.config.logUploadIntervalMultiplicationFactor && !this.uploadLogsTimer) {
|
4318
|
+
this.logUploadIntervalIndex = 0;
|
4319
|
+
|
4320
|
+
this.setLogUploadTimer();
|
4321
|
+
}
|
4322
|
+
}
|
4323
|
+
|
4324
|
+
/**
|
4325
|
+
* Stops the periodic upload of logs
|
4326
|
+
*
|
4327
|
+
* @returns {undefined}
|
4328
|
+
*/
|
4329
|
+
public stopPeriodicLogUpload() {
|
4330
|
+
if (this.uploadLogsTimer) {
|
4331
|
+
clearTimeout(this.uploadLogsTimer);
|
4332
|
+
this.uploadLogsTimer = undefined;
|
4333
|
+
}
|
4334
|
+
}
|
4335
|
+
|
4063
4336
|
/**
|
4064
4337
|
* Removes remote audio, video and share streams from class instance's mediaProperties
|
4065
4338
|
* @returns {undefined}
|
@@ -4449,11 +4722,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4449
4722
|
* Close the peer connections and remove them from the class.
|
4450
4723
|
* Cleanup any media connection related things.
|
4451
4724
|
*
|
4725
|
+
* @param {boolean} resetMuteStates whether to also reset the audio/video mute state information
|
4452
4726
|
* @returns {Promise}
|
4453
4727
|
* @public
|
4454
4728
|
* @memberof Meeting
|
4455
4729
|
*/
|
4456
|
-
public closePeerConnections() {
|
4730
|
+
public closePeerConnections(resetMuteStates = true) {
|
4457
4731
|
if (this.mediaProperties.webrtcMediaConnection) {
|
4458
4732
|
if (this.remoteMediaManager) {
|
4459
4733
|
this.remoteMediaManager.stop();
|
@@ -4466,12 +4740,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4466
4740
|
|
4467
4741
|
this.receiveSlotManager.reset();
|
4468
4742
|
this.mediaProperties.webrtcMediaConnection.close();
|
4743
|
+
this.mediaProperties.unsetPeerConnection();
|
4469
4744
|
this.sendSlotManager.reset();
|
4470
4745
|
this.setNetworkStatus(undefined);
|
4471
4746
|
}
|
4472
4747
|
|
4473
|
-
|
4474
|
-
|
4748
|
+
if (resetMuteStates) {
|
4749
|
+
this.audio = null;
|
4750
|
+
this.video = null;
|
4751
|
+
}
|
4475
4752
|
|
4476
4753
|
return Promise.resolve();
|
4477
4754
|
}
|
@@ -4731,7 +5008,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4731
5008
|
* @param {Object} options - options to join with media
|
4732
5009
|
* @param {JoinOptions} [options.joinOptions] - see #join()
|
4733
5010
|
* @param {AddMediaOptions} [options.mediaOptions] - see #addMedia()
|
4734
|
-
* @returns {Promise} -- {join: see join(), media: see addMedia()}
|
5011
|
+
* @returns {Promise} -- {join: see join(), media: see addMedia(), multistreamEnabled: flag to indicate if we managed to join in multistream mode}
|
4735
5012
|
* @public
|
4736
5013
|
* @memberof Meeting
|
4737
5014
|
* @example
|
@@ -4771,8 +5048,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4771
5048
|
if (!joinResponse) {
|
4772
5049
|
// This is the 1st attempt or a retry after join request failed -> we need to do a join with TURN discovery
|
4773
5050
|
|
4774
|
-
// @ts-ignore
|
4775
|
-
joinOptions.reachability = await this.webex.meetings.reachability.getReachabilityResults();
|
4776
5051
|
const turnDiscoveryRequest = await this.roap.generateTurnDiscoveryRequestMessage(
|
4777
5052
|
this,
|
4778
5053
|
true
|
@@ -4823,6 +5098,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4823
5098
|
return {
|
4824
5099
|
join: joinResponse,
|
4825
5100
|
media: mediaResponse,
|
5101
|
+
multistreamEnabled: this.isMultistream,
|
4826
5102
|
};
|
4827
5103
|
} catch (error) {
|
4828
5104
|
LoggerProxy.logger.error('Meeting:index#joinWithMedia --> ', error);
|
@@ -4831,7 +5107,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4831
5107
|
|
4832
5108
|
this.roap.abortTurnDiscovery();
|
4833
5109
|
|
4834
|
-
if
|
5110
|
+
// if this was the first attempt, let's do a retry
|
5111
|
+
let shouldRetry = !isRetry;
|
5112
|
+
|
5113
|
+
if (CallDiagnosticUtils.isSdpOfferCreationError(error)) {
|
5114
|
+
// errors related to offer creation (for example missing H264 codec) will happen again no matter how many times we try,
|
5115
|
+
// so there is no point doing a retry
|
5116
|
+
shouldRetry = false;
|
5117
|
+
}
|
5118
|
+
|
5119
|
+
// we only want to call leave if join was successful and this was a retry or we won't be doing any more retries
|
5120
|
+
if (joined && (isRetry || !shouldRetry)) {
|
4835
5121
|
try {
|
4836
5122
|
await this.leave({resourceId: joinOptions?.resourceId, reason: 'joinWithMedia failure'});
|
4837
5123
|
} catch (e) {
|
@@ -4855,15 +5141,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
4855
5141
|
}
|
4856
5142
|
);
|
4857
5143
|
|
4858
|
-
// if this was the first attempt, let's do a retry
|
4859
|
-
let shouldRetry = !isRetry;
|
4860
|
-
|
4861
|
-
if (CallDiagnosticUtils.isSdpOfferCreationError(error)) {
|
4862
|
-
// errors related to offer creation (for example missing H264 codec) will happen again no matter how many times we try,
|
4863
|
-
// so there is no point doing a retry
|
4864
|
-
shouldRetry = false;
|
4865
|
-
}
|
4866
|
-
|
4867
5144
|
if (shouldRetry) {
|
4868
5145
|
LoggerProxy.logger.warn('Meeting:index#joinWithMedia --> retrying call to joinWithMedia');
|
4869
5146
|
this.joinWithMediaRetryInfo.isRetry = true;
|
@@ -5119,7 +5396,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
5119
5396
|
(this.config.receiveReactions || options.receiveReactions) &&
|
5120
5397
|
this.isReactionsSupported()
|
5121
5398
|
) {
|
5122
|
-
const
|
5399
|
+
const member = this.members.membersCollection.get(e.data.sender.participantId);
|
5400
|
+
if (!member) {
|
5401
|
+
// @ts-ignore -- fix type
|
5402
|
+
LoggerProxy.logger.warn(
|
5403
|
+
`Meeting:index#processRelayEvent --> Skipping handling of ${REACTION_RELAY_TYPES.REACTION} for ${this.id}. participantId ${e.data.sender.participantId} does not exist in membersCollection.`
|
5404
|
+
);
|
5405
|
+
break;
|
5406
|
+
}
|
5407
|
+
|
5408
|
+
const {name} = member;
|
5123
5409
|
const processedReaction: ProcessedReaction = {
|
5124
5410
|
reaction: e.data.reaction,
|
5125
5411
|
sender: {
|
@@ -5173,6 +5459,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
5173
5459
|
this.voiceaListenerCallbacks[VOICEAEVENTS.NEW_CAPTION]
|
5174
5460
|
);
|
5175
5461
|
|
5462
|
+
// @ts-ignore
|
5463
|
+
this.webex.internal.voicea.deregisterEvents();
|
5464
|
+
|
5176
5465
|
this.areVoiceaEventsSetup = false;
|
5177
5466
|
this.triggerStopReceivingTranscriptionEvent();
|
5178
5467
|
}
|
@@ -5283,16 +5572,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
5283
5572
|
this.meetingFiniteStateMachine.reset();
|
5284
5573
|
}
|
5285
5574
|
|
5286
|
-
//
|
5287
|
-
|
5288
|
-
|
5289
|
-
|
5290
|
-
|
5291
|
-
|
5292
|
-
|
5293
|
-
|
5294
|
-
|
5295
|
-
|
5575
|
+
// send client.call.initiated unless told not to
|
5576
|
+
if (options.sendCallInitiated !== false) {
|
5577
|
+
// @ts-ignore
|
5578
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
5579
|
+
name: 'client.call.initiated',
|
5580
|
+
payload: {
|
5581
|
+
trigger: this.callStateForMetrics.joinTrigger || 'user-interaction',
|
5582
|
+
isRoapCallEnabled: true,
|
5583
|
+
pstnAudioType: options?.pstnAudioType,
|
5584
|
+
},
|
5585
|
+
options: {meetingId: this.id},
|
5586
|
+
});
|
5587
|
+
}
|
5296
5588
|
|
5297
5589
|
LoggerProxy.logger.log('Meeting:index#join --> Joining a meeting');
|
5298
5590
|
|
@@ -5480,17 +5772,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
5480
5772
|
*/
|
5481
5773
|
async updateLLMConnection() {
|
5482
5774
|
// @ts-ignore - Fix type
|
5483
|
-
const {url, info: {datachannelUrl} = {}} = this.locusInfo;
|
5775
|
+
const {url, info: {datachannelUrl, practiceSessionDatachannelUrl} = {}} = this.locusInfo;
|
5484
5776
|
|
5485
5777
|
const isJoined = this.isJoined();
|
5486
5778
|
|
5779
|
+
// webinar panelist should use new data channel in practice session
|
5780
|
+
const dataChannelUrl =
|
5781
|
+
this.webinar.isJoinPracticeSessionDataChannel() && practiceSessionDatachannelUrl
|
5782
|
+
? practiceSessionDatachannelUrl
|
5783
|
+
: datachannelUrl;
|
5784
|
+
|
5487
5785
|
// @ts-ignore - Fix type
|
5488
5786
|
if (this.webex.internal.llm.isConnected()) {
|
5489
5787
|
if (
|
5490
5788
|
// @ts-ignore - Fix type
|
5491
5789
|
url === this.webex.internal.llm.getLocusUrl() &&
|
5492
5790
|
// @ts-ignore - Fix type
|
5493
|
-
|
5791
|
+
dataChannelUrl === this.webex.internal.llm.getDatachannelUrl() &&
|
5494
5792
|
isJoined
|
5495
5793
|
) {
|
5496
5794
|
return undefined;
|
@@ -5507,7 +5805,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
5507
5805
|
|
5508
5806
|
// @ts-ignore - Fix type
|
5509
5807
|
return this.webex.internal.llm
|
5510
|
-
.registerAndConnect(url,
|
5808
|
+
.registerAndConnect(url, dataChannelUrl)
|
5511
5809
|
.then((registerAndConnectResult) => {
|
5512
5810
|
// @ts-ignore - Fix type
|
5513
5811
|
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
@@ -5877,8 +6175,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
5877
6175
|
* @returns {undefined}
|
5878
6176
|
*/
|
5879
6177
|
public roapMessageReceived = (roapMessage: RoapMessage) => {
|
5880
|
-
const mediaServer =
|
5881
|
-
|
6178
|
+
const mediaServer =
|
6179
|
+
roapMessage.messageType === 'ANSWER'
|
6180
|
+
? MeetingsUtil.getMediaServer(roapMessage.sdp)
|
6181
|
+
: undefined;
|
6182
|
+
|
6183
|
+
if (this.isMultistream && mediaServer && mediaServer !== 'homer') {
|
6184
|
+
throw new MultistreamNotSupportedError(
|
6185
|
+
`Client asked for multistream backend (Homer), but got ${mediaServer} instead`
|
6186
|
+
);
|
6187
|
+
}
|
5882
6188
|
this.mediaProperties.webrtcMediaConnection.roapMessageReceived(roapMessage);
|
5883
6189
|
|
5884
6190
|
if (mediaServer) {
|
@@ -6001,16 +6307,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6001
6307
|
logText: `${LOG_HEADER} Roap Offer`,
|
6002
6308
|
}
|
6003
6309
|
).catch((error) => {
|
6310
|
+
const multistreamNotSupported = error instanceof MultistreamNotSupportedError;
|
6311
|
+
|
6004
6312
|
// @ts-ignore
|
6005
6313
|
this.webex.internal.newMetrics.submitClientEvent({
|
6006
6314
|
name: 'client.media-engine.remote-sdp-received',
|
6007
6315
|
payload: {
|
6008
|
-
canProceed:
|
6316
|
+
canProceed: multistreamNotSupported,
|
6009
6317
|
errors: [
|
6010
6318
|
// @ts-ignore
|
6011
6319
|
this.webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode(
|
6012
6320
|
{
|
6013
|
-
clientErrorCode:
|
6321
|
+
clientErrorCode: multistreamNotSupported
|
6322
|
+
? CALL_DIAGNOSTIC_CONFIG.MULTISTREAM_NOT_AVAILABLE_CLIENT_CODE
|
6323
|
+
: CALL_DIAGNOSTIC_CONFIG.MISSING_ROAP_ANSWER_CLIENT_CODE,
|
6014
6324
|
}
|
6015
6325
|
),
|
6016
6326
|
],
|
@@ -6018,7 +6328,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6018
6328
|
options: {meetingId: this.id, rawError: error},
|
6019
6329
|
});
|
6020
6330
|
|
6021
|
-
this.deferSDPAnswer.reject(
|
6331
|
+
this.deferSDPAnswer.reject(error);
|
6022
6332
|
clearTimeout(this.sdpResponseTimer);
|
6023
6333
|
this.sdpResponseTimer = undefined;
|
6024
6334
|
});
|
@@ -6346,6 +6656,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6346
6656
|
this.webex.meetings.geoHintInfo?.clientAddress ||
|
6347
6657
|
options.data.intervalMetadata.peerReflexiveIP ||
|
6348
6658
|
MQA_STATS.DEFAULT_IP;
|
6659
|
+
|
6660
|
+
const {members} = this.getMembers().membersCollection;
|
6661
|
+
|
6662
|
+
// Count members that are in the meeting
|
6663
|
+
options.data.intervalMetadata.meetingUserCount = Object.values(members).filter(
|
6664
|
+
(member: Member) => member.isInMeeting
|
6665
|
+
).length;
|
6666
|
+
|
6349
6667
|
// @ts-ignore
|
6350
6668
|
this.webex.internal.newMetrics.submitMQE({
|
6351
6669
|
name: 'client.mediaquality.event',
|
@@ -6477,6 +6795,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6477
6795
|
new RtcMetrics(this.webex, {meetingId: this.id}, this.correlationId)
|
6478
6796
|
: undefined;
|
6479
6797
|
|
6798
|
+
// ongoing reachability checks slow down new media connections especially on Firefox, so we stop them
|
6799
|
+
this.getWebexObject().meetings.reachability.stopReachability();
|
6800
|
+
|
6480
6801
|
const mc = Media.createMediaConnection(
|
6481
6802
|
this.isMultistream,
|
6482
6803
|
this.getMediaConnectionDebugId(),
|
@@ -6677,32 +6998,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6677
6998
|
}
|
6678
6999
|
}
|
6679
7000
|
|
6680
|
-
/**
|
6681
|
-
* Handles device logging
|
6682
|
-
*
|
6683
|
-
* @private
|
6684
|
-
* @static
|
6685
|
-
* @param {boolean} isAudioEnabled
|
6686
|
-
* @param {boolean} isVideoEnabled
|
6687
|
-
* @returns {Promise<void>}
|
6688
|
-
*/
|
6689
|
-
|
6690
|
-
private static async handleDeviceLogging(isAudioEnabled, isVideoEnabled): Promise<void> {
|
6691
|
-
try {
|
6692
|
-
let devices = [];
|
6693
|
-
if (isVideoEnabled && isAudioEnabled) {
|
6694
|
-
devices = await getDevices();
|
6695
|
-
} else if (isVideoEnabled) {
|
6696
|
-
devices = await getDevices(Media.DeviceKind.VIDEO_INPUT);
|
6697
|
-
} else if (isAudioEnabled) {
|
6698
|
-
devices = await getDevices(Media.DeviceKind.AUDIO_INPUT);
|
6699
|
-
}
|
6700
|
-
MeetingUtil.handleDeviceLogging(devices);
|
6701
|
-
} catch {
|
6702
|
-
// getDevices may fail if we don't have browser permissions, that's ok, we still can have a media connection
|
6703
|
-
}
|
6704
|
-
}
|
6705
|
-
|
6706
7001
|
/**
|
6707
7002
|
* Returns a promise. This promise is created once the local sdp offer has been successfully created and is resolved
|
6708
7003
|
* once the remote sdp answer has been received.
|
@@ -6926,7 +7221,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6926
7221
|
|
6927
7222
|
const mc = await this.createMediaConnection(turnServerInfo, bundlePolicy);
|
6928
7223
|
|
6929
|
-
LoggerProxy.logger.info(
|
7224
|
+
LoggerProxy.logger.info(
|
7225
|
+
`${LOG_HEADER} media connection created this.isMultistream=${this.isMultistream}`
|
7226
|
+
);
|
6930
7227
|
|
6931
7228
|
if (this.isMultistream) {
|
6932
7229
|
this.remoteMediaManager = new RemoteMediaManager(
|
@@ -7004,6 +7301,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7004
7301
|
}
|
7005
7302
|
}
|
7006
7303
|
|
7304
|
+
/**
|
7305
|
+
* Cleans up stats analyzer, peer connection and other things before
|
7306
|
+
* we can create a new transcoded media connection
|
7307
|
+
*
|
7308
|
+
* @private
|
7309
|
+
* @returns {Promise<void>}
|
7310
|
+
*/
|
7311
|
+
private async downgradeFromMultistreamToTranscoded(): Promise<void> {
|
7312
|
+
if (this.statsAnalyzer) {
|
7313
|
+
await this.statsAnalyzer.stopAnalyzer();
|
7314
|
+
}
|
7315
|
+
this.statsAnalyzer = null;
|
7316
|
+
|
7317
|
+
this.isMultistream = false;
|
7318
|
+
|
7319
|
+
if (this.mediaProperties.webrtcMediaConnection) {
|
7320
|
+
// close peer connection, but don't reset mute state information, because we will want to use it on the retry
|
7321
|
+
this.closePeerConnections(false);
|
7322
|
+
|
7323
|
+
this.mediaProperties.unsetPeerConnection();
|
7324
|
+
}
|
7325
|
+
|
7326
|
+
this.locusMediaRequest?.downgradeFromMultistreamToTranscoded();
|
7327
|
+
|
7328
|
+
this.createStatsAnalyzer();
|
7329
|
+
}
|
7330
|
+
|
7007
7331
|
/**
|
7008
7332
|
* Sends stats report, closes peer connection and cleans up any media connection
|
7009
7333
|
* related things before trying to establish media connection again with turn server
|
@@ -7190,6 +7514,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7190
7514
|
|
7191
7515
|
this.audio = createMuteState(AUDIO, this, audioEnabled);
|
7192
7516
|
this.video = createMuteState(VIDEO, this, videoEnabled);
|
7517
|
+
this.brbState = createBrbState(this, false);
|
7193
7518
|
|
7194
7519
|
try {
|
7195
7520
|
await this.setUpLocalStreamReferences(localStreams);
|
@@ -7198,19 +7523,36 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7198
7523
|
|
7199
7524
|
this.createStatsAnalyzer();
|
7200
7525
|
|
7201
|
-
|
7202
|
-
|
7203
|
-
|
7204
|
-
|
7205
|
-
|
7206
|
-
|
7526
|
+
try {
|
7527
|
+
await this.establishMediaConnection(
|
7528
|
+
remoteMediaManagerConfig,
|
7529
|
+
bundlePolicy,
|
7530
|
+
forceTurnDiscovery,
|
7531
|
+
turnServerInfo
|
7532
|
+
);
|
7533
|
+
} catch (error) {
|
7534
|
+
if (error instanceof MultistreamNotSupportedError) {
|
7535
|
+
LoggerProxy.logger.warn(
|
7536
|
+
`${LOG_HEADER} we asked for multistream backend (Homer), but got transcoded backend, recreating media connection...`
|
7537
|
+
);
|
7207
7538
|
|
7208
|
-
|
7209
|
-
|
7210
|
-
|
7211
|
-
|
7539
|
+
await this.downgradeFromMultistreamToTranscoded();
|
7540
|
+
|
7541
|
+
// Establish new media connection with forced TURN discovery
|
7542
|
+
// We need to do TURN discovery again, because backend will be creating a new confluence, so it might land on a different node or cluster
|
7543
|
+
await this.establishMediaConnection(
|
7544
|
+
remoteMediaManagerConfig,
|
7545
|
+
bundlePolicy,
|
7546
|
+
true,
|
7547
|
+
undefined
|
7548
|
+
);
|
7549
|
+
} else {
|
7550
|
+
throw error;
|
7551
|
+
}
|
7212
7552
|
}
|
7213
7553
|
|
7554
|
+
LoggerProxy.logger.info(`${LOG_HEADER} media connected, finalizing...`);
|
7555
|
+
|
7214
7556
|
if (this.mediaProperties.hasLocalShareStream()) {
|
7215
7557
|
await this.enqueueScreenShareFloorRequest();
|
7216
7558
|
}
|
@@ -7247,6 +7589,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7247
7589
|
|
7248
7590
|
// We can log ReceiveSlot SSRCs only after the SDP exchange, so doing it here:
|
7249
7591
|
this.remoteMediaManager?.logAllReceiveSlots();
|
7592
|
+
this.startPeriodicLogUpload();
|
7250
7593
|
} catch (error) {
|
7251
7594
|
LoggerProxy.logger.error(`${LOG_HEADER} failed to establish media connection: `, error);
|
7252
7595
|
|
@@ -8179,7 +8522,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8179
8522
|
if (layoutType) {
|
8180
8523
|
if (!LAYOUT_TYPES.includes(layoutType)) {
|
8181
8524
|
return this.rejectWithErrorLog(
|
8182
|
-
|
8525
|
+
`Meeting:index#changeVideoLayout --> cannot change video layout, invalid layoutType "${layoutType}" received.`
|
8183
8526
|
);
|
8184
8527
|
}
|
8185
8528
|
|
@@ -8335,6 +8678,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8335
8678
|
correlationId: this.correlationId,
|
8336
8679
|
muted,
|
8337
8680
|
encoderImplementation: this.statsAnalyzer?.shareVideoEncoderImplementation,
|
8681
|
+
// TypeScript 4 does not recognize the `displaySurface` property. Instead of upgrading the
|
8682
|
+
// SDK to TypeScript 5, which may affect other packages, use bracket notation for now, since
|
8683
|
+
// all we're doing here is adding metrics.
|
8684
|
+
// eslint-disable-next-line dot-notation
|
8685
|
+
displaySurface: this.mediaProperties?.shareVideoStream?.getSettings()['displaySurface'],
|
8686
|
+
isMultistream: this.isMultistream,
|
8338
8687
|
});
|
8339
8688
|
};
|
8340
8689
|
|
@@ -8537,6 +8886,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8537
8886
|
this.stopTranscription();
|
8538
8887
|
this.transcription = undefined;
|
8539
8888
|
}
|
8889
|
+
|
8890
|
+
this.annotation.deregisterEvents();
|
8891
|
+
|
8892
|
+
// @ts-ignore - fix types
|
8893
|
+
this.webex.internal.llm.off('event:relay.event', this.processRelayEvent);
|
8540
8894
|
};
|
8541
8895
|
|
8542
8896
|
/**
|
@@ -8574,10 +8928,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
8574
8928
|
|
8575
8929
|
return;
|
8576
8930
|
}
|
8577
|
-
|
8931
|
+
|
8578
8932
|
const keepAliveInterval = (this.joinedWith.keepAliveSecs - 1) * 750; // taken from UCF
|
8579
8933
|
|
8580
8934
|
this.keepAliveTimerId = setInterval(() => {
|
8935
|
+
const {keepAliveUrl} = this.joinedWith;
|
8936
|
+
|
8581
8937
|
this.meetingRequest.keepAlive({keepAliveUrl}).catch((error) => {
|
8582
8938
|
LoggerProxy.logger.warn(
|
8583
8939
|
`Meeting:index#startKeepAlive --> Stopping sending keepAlives to ${keepAliveUrl} after error ${error}`
|