@webex/plugin-meetings 3.0.0-beta.13 → 3.0.0-beta.15
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/UPGRADING.md +9 -9
- package/browsers.js +19 -24
- package/dist/common/browser-detection.js +1 -0
- package/dist/common/browser-detection.js.map +1 -1
- package/dist/common/collection.js.map +1 -1
- package/dist/common/errors/captcha-error.js +5 -5
- package/dist/common/errors/captcha-error.js.map +1 -1
- package/dist/common/errors/intent-to-join.js +5 -5
- package/dist/common/errors/intent-to-join.js.map +1 -1
- package/dist/common/errors/join-meeting.js +6 -6
- package/dist/common/errors/join-meeting.js.map +1 -1
- package/dist/common/errors/media.js +5 -5
- package/dist/common/errors/media.js.map +1 -1
- package/dist/common/errors/parameter.js +5 -5
- package/dist/common/errors/parameter.js.map +1 -1
- package/dist/common/errors/password-error.js +5 -5
- package/dist/common/errors/password-error.js.map +1 -1
- package/dist/common/errors/permission.js +4 -4
- package/dist/common/errors/permission.js.map +1 -1
- package/dist/common/errors/reconnection.js +5 -5
- package/dist/common/errors/reconnection.js.map +1 -1
- package/dist/common/errors/stats.js +5 -5
- package/dist/common/errors/stats.js.map +1 -1
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/errors/webex-meetings-error.js.map +1 -1
- package/dist/common/events/events-scope.js.map +1 -1
- package/dist/common/events/events.js.map +1 -1
- package/dist/common/events/trigger-proxy.js.map +1 -1
- package/dist/common/events/util.js.map +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/fullState.js.map +1 -1
- package/dist/locus-info/hostUtils.js.map +1 -1
- package/dist/locus-info/index.js +11 -8
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +2 -1
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js +2 -1
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js.map +1 -1
- package/dist/media/internal-media-core-wrapper.js.map +1 -1
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.js +1 -1
- package/dist/media/util.js.map +1 -1
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/effectsState.js +1 -1
- package/dist/meeting/effectsState.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +118 -89
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +1 -1
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +25 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js +8 -0
- package/dist/meeting/request.type.js.map +1 -0
- package/dist/meeting/state.js +5 -5
- package/dist/meeting/state.js.map +1 -1
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/collection.js.map +1 -1
- package/dist/meeting-info/index.js +2 -2
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +48 -48
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/request.js.map +1 -1
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +1 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +251 -250
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/request.js +2 -2
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js +14 -14
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +31 -31
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +43 -43
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.js +23 -20
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/multistreamMedia.js +2 -1
- package/dist/multistream/multistreamMedia.js.map +1 -1
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +2 -0
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/networkQualityMonitor/index.js +8 -8
- package/dist/networkQualityMonitor/index.js.map +1 -1
- package/dist/personal-meeting-room/index.js +7 -7
- package/dist/personal-meeting-room/index.js.map +1 -1
- package/dist/personal-meeting-room/request.js.map +1 -1
- package/dist/personal-meeting-room/util.js.map +1 -1
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js.map +1 -1
- package/dist/reactions/reactions.js.map +1 -1
- package/dist/reactions/reactions.type.js +3 -1
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/reconnection-manager/index.js +4 -4
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.js +5 -5
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/statsAnalyzer/global.js.map +1 -1
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/transcription/index.js +4 -1
- package/dist/transcription/index.js.map +1 -1
- package/internal-README.md +7 -6
- package/package.json +18 -18
- package/src/common/browser-detection.ts +9 -6
- package/src/common/collection.ts +3 -1
- package/src/common/errors/captcha-error.ts +6 -6
- package/src/common/errors/intent-to-join.ts +6 -6
- package/src/common/errors/join-meeting.ts +12 -8
- package/src/common/errors/media.ts +6 -6
- package/src/common/errors/parameter.ts +9 -6
- package/src/common/errors/password-error.ts +6 -6
- package/src/common/errors/permission.ts +5 -5
- package/src/common/errors/reconnection.ts +6 -6
- package/src/common/errors/stats.ts +6 -6
- package/src/common/errors/webex-errors.ts +7 -5
- package/src/common/errors/webex-meetings-error.ts +1 -1
- package/src/common/events/events-scope.ts +5 -1
- package/src/common/events/events.ts +5 -1
- package/src/common/events/trigger-proxy.ts +8 -3
- package/src/common/events/util.ts +1 -2
- package/src/common/logs/logger-proxy.ts +21 -10
- package/src/common/logs/request.ts +11 -8
- package/src/config.ts +11 -11
- package/src/constants.ts +1 -1
- package/src/index.js +1 -1
- package/src/locus-info/controlsUtils.ts +34 -24
- package/src/locus-info/fullState.ts +15 -11
- package/src/locus-info/hostUtils.ts +4 -3
- package/src/locus-info/index.ts +25 -34
- package/src/locus-info/infoUtils.ts +12 -4
- package/src/locus-info/mediaSharesUtils.ts +4 -4
- package/src/locus-info/parser.ts +45 -68
- package/src/locus-info/selfUtils.ts +106 -57
- package/src/media/index.ts +123 -135
- package/src/media/internal-media-core-wrapper.ts +2 -2
- package/src/media/properties.ts +30 -20
- package/src/media/util.ts +1 -1
- package/src/mediaQualityMetrics/config.ts +46 -46
- package/src/meeting/effectsState.ts +35 -35
- package/src/meeting/in-meeting-actions.ts +7 -3
- package/src/meeting/index.ts +1576 -1291
- package/src/meeting/muteState.ts +62 -31
- package/src/meeting/request.ts +174 -113
- package/src/meeting/request.type.ts +11 -0
- package/src/meeting/state.ts +45 -30
- package/src/meeting/util.ts +101 -70
- package/src/meeting-info/collection.ts +2 -1
- package/src/meeting-info/index.ts +32 -30
- package/src/meeting-info/meeting-info-v2.ts +106 -108
- package/src/meeting-info/request.ts +9 -3
- package/src/meeting-info/util.ts +54 -46
- package/src/meeting-info/utilv2.ts +59 -53
- package/src/meetings/collection.ts +1 -1
- package/src/meetings/index.ts +512 -440
- package/src/meetings/request.ts +26 -24
- package/src/meetings/util.ts +29 -29
- package/src/member/index.ts +55 -49
- package/src/member/util.ts +26 -13
- package/src/members/collection.ts +0 -1
- package/src/members/index.ts +182 -126
- package/src/members/request.ts +46 -14
- package/src/members/util.ts +44 -42
- package/src/metrics/config.ts +254 -81
- package/src/metrics/constants.ts +0 -2
- package/src/metrics/index.ts +84 -71
- package/src/multistream/multistreamMedia.ts +1 -0
- package/src/multistream/receiveSlot.ts +1 -0
- package/src/multistream/receiveSlotManager.ts +1 -0
- package/src/multistream/remoteMedia.ts +1 -1
- package/src/multistream/remoteMediaGroup.ts +2 -1
- package/src/multistream/remoteMediaManager.ts +3 -0
- package/src/networkQualityMonitor/index.ts +20 -23
- package/src/personal-meeting-room/index.ts +12 -16
- package/src/personal-meeting-room/request.ts +10 -3
- package/src/personal-meeting-room/util.ts +3 -3
- package/src/reachability/index.ts +61 -59
- package/src/reachability/request.ts +36 -32
- package/src/reactions/reactions.ts +4 -4
- package/src/reactions/reactions.type.ts +4 -3
- package/src/reconnection-manager/index.ts +139 -84
- package/src/roap/index.ts +46 -38
- package/src/roap/request.ts +44 -31
- package/src/roap/turnDiscovery.ts +59 -30
- package/src/statsAnalyzer/global.ts +30 -33
- package/src/statsAnalyzer/index.ts +432 -175
- package/src/statsAnalyzer/mqaUtil.ts +178 -72
- package/src/transcription/index.ts +34 -32
- package/test/integration/spec/journey.js +663 -462
- package/test/integration/spec/space-meeting.js +318 -203
- package/test/integration/spec/transcription.js +6 -7
- package/test/unit/spec/common/browser-detection.js +9 -28
- package/test/unit/spec/fixture/locus.js +92 -90
- package/test/unit/spec/locus-info/controlsUtils.js +5 -5
- package/test/unit/spec/locus-info/embeddedAppsUtils.js +8 -6
- package/test/unit/spec/locus-info/index.js +1 -2
- package/test/unit/spec/locus-info/infoUtils.js +26 -33
- package/test/unit/spec/locus-info/lib/BasicSeqCmp.json +88 -430
- package/test/unit/spec/locus-info/lib/SeqCmp.json +513 -685
- package/test/unit/spec/locus-info/parser.js +3 -9
- package/test/unit/spec/locus-info/selfConstant.js +72 -103
- package/test/unit/spec/locus-info/selfUtils.js +21 -12
- package/test/unit/spec/meeting/effectsState.js +36 -46
- package/test/unit/spec/meeting/in-meeting-actions.ts +2 -3
- package/test/unit/spec/meeting/index.js +1342 -684
- package/test/unit/spec/meeting/muteState.js +42 -33
- package/test/unit/spec/meeting/request.js +75 -45
- package/test/unit/spec/meeting/utils.js +78 -53
- package/test/unit/spec/meeting-info/meetinginfov2.js +100 -73
- package/test/unit/spec/meeting-info/request.js +7 -9
- package/test/unit/spec/meeting-info/util.js +11 -12
- package/test/unit/spec/meeting-info/utilv2.js +110 -74
- package/test/unit/spec/meetings/collection.js +1 -1
- package/test/unit/spec/meetings/index.js +438 -257
- package/test/unit/spec/meetings/utils.js +14 -12
- package/test/unit/spec/member/index.js +0 -1
- package/test/unit/spec/member/util.js +5 -6
- package/test/unit/spec/members/index.js +104 -54
- package/test/unit/spec/members/request.js +29 -20
- package/test/unit/spec/members/utils.js +8 -5
- package/test/unit/spec/metrics/index.js +16 -21
- package/test/unit/spec/networkQualityMonitor/index.js +21 -15
- package/test/unit/spec/personal-meeting-room/personal-meeting-room.js +2 -7
- package/test/unit/spec/reachability/index.ts +9 -11
- package/test/unit/spec/reconnection-manager/index.js +16 -18
- package/test/unit/spec/roap/turnDiscovery.ts +22 -19
- package/test/unit/spec/stats-analyzer/index.js +25 -20
- package/test/utils/cmr.js +44 -42
- package/test/utils/testUtils.js +83 -74
- package/test/utils/webex-config.js +18 -18
- package/test/utils/webex-test-users.js +53 -50
package/src/meeting/index.ts
CHANGED
|
@@ -5,8 +5,11 @@ import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
|
5
5
|
import {Media as WebRTCMedia, MediaConnection as MC} from '@webex/internal-media-core';
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
|
-
MeetingNotActiveError,
|
|
9
|
-
|
|
8
|
+
MeetingNotActiveError,
|
|
9
|
+
createMeetingsError,
|
|
10
|
+
UserInLobbyError,
|
|
11
|
+
NoMediaEstablishedYetError,
|
|
12
|
+
UserNotJoinedError,
|
|
10
13
|
} from '../common/errors/webex-errors';
|
|
11
14
|
import {StatsAnalyzer, EVENTS as StatsAnalyzerEvents} from '../statsAnalyzer';
|
|
12
15
|
import NetworkQualityMonitor from '../networkQualityMonitor';
|
|
@@ -15,16 +18,16 @@ import Trigger from '../common/events/trigger-proxy';
|
|
|
15
18
|
import Roap from '../roap/index';
|
|
16
19
|
import Media from '../media';
|
|
17
20
|
import MediaProperties from '../media/properties';
|
|
18
|
-
import MeetingStateMachine from '
|
|
19
|
-
import createMuteState from '
|
|
20
|
-
import createEffectsState from '
|
|
21
|
+
import MeetingStateMachine from './state';
|
|
22
|
+
import createMuteState from './muteState';
|
|
23
|
+
import createEffectsState from './effectsState';
|
|
21
24
|
import LocusInfo from '../locus-info';
|
|
22
25
|
import Metrics from '../metrics';
|
|
23
26
|
import {trigger, mediaType, error as MetricsError, eventType} from '../metrics/config';
|
|
24
27
|
import ReconnectionManager from '../reconnection-manager';
|
|
25
|
-
import MeetingRequest from '
|
|
28
|
+
import MeetingRequest from './request';
|
|
26
29
|
import Members from '../members/index';
|
|
27
|
-
import MeetingUtil from '
|
|
30
|
+
import MeetingUtil from './util';
|
|
28
31
|
import MediaUtil from '../media/util';
|
|
29
32
|
import Transcription from '../transcription';
|
|
30
33
|
import PasswordError from '../common/errors/password-error';
|
|
@@ -64,26 +67,31 @@ import {
|
|
|
64
67
|
VIDEO_RESOLUTIONS,
|
|
65
68
|
VIDEO,
|
|
66
69
|
BNR_STATUS,
|
|
67
|
-
HTTP_VERBS
|
|
70
|
+
HTTP_VERBS,
|
|
68
71
|
} from '../constants';
|
|
69
72
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
70
73
|
import ParameterError from '../common/errors/parameter';
|
|
71
74
|
import MediaError from '../common/errors/media';
|
|
72
|
-
import {
|
|
75
|
+
import {
|
|
76
|
+
MeetingInfoV2PasswordError,
|
|
77
|
+
MeetingInfoV2CaptchaError,
|
|
78
|
+
} from '../meeting-info/meeting-info-v2';
|
|
73
79
|
import BrowserDetection from '../common/browser-detection';
|
|
74
80
|
import {ReceiveSlotManager} from '../multistream/receiveSlotManager';
|
|
75
81
|
import {MediaRequestManager} from '../multistream/mediaRequestManager';
|
|
76
|
-
import {
|
|
82
|
+
import {
|
|
83
|
+
RemoteMediaManager,
|
|
84
|
+
Event as RemoteMediaManagerEvent,
|
|
85
|
+
} from '../multistream/remoteMediaManager';
|
|
77
86
|
import {MultistreamMedia} from '../multistream/multistreamMedia';
|
|
78
87
|
import {SkinTones, Reactions} from '../reactions/reactions';
|
|
79
88
|
import {Reaction, ReactionType, SkinToneType} from '../reactions/reactions.type';
|
|
80
89
|
|
|
81
90
|
import InMeetingActions from './in-meeting-actions';
|
|
82
91
|
|
|
83
|
-
|
|
84
92
|
const {isBrowser} = BrowserDetection();
|
|
85
93
|
|
|
86
|
-
const logRequest = (request: any, {
|
|
94
|
+
const logRequest = (request: any, {header = '', success = '', failure = ''}) => {
|
|
87
95
|
LoggerProxy.logger.info(header);
|
|
88
96
|
|
|
89
97
|
return request
|
|
@@ -102,7 +110,7 @@ export const MEDIA_UPDATE_TYPE = {
|
|
|
102
110
|
ALL: 'ALL',
|
|
103
111
|
AUDIO: 'AUDIO',
|
|
104
112
|
VIDEO: 'VIDEO',
|
|
105
|
-
SHARE: 'SHARE'
|
|
113
|
+
SHARE: 'SHARE',
|
|
106
114
|
};
|
|
107
115
|
|
|
108
116
|
/**
|
|
@@ -118,21 +126,21 @@ export const MEDIA_UPDATE_TYPE = {
|
|
|
118
126
|
*/
|
|
119
127
|
|
|
120
128
|
/**
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
* AudioVideo
|
|
130
|
+
* @typedef {Object} AudioVideo
|
|
131
|
+
* @property {Object} audio
|
|
132
|
+
* @property {String} audio.deviceId
|
|
133
|
+
* @property {Object} video
|
|
134
|
+
* @property {String} video.deviceId
|
|
135
|
+
* @property {String} video.localVideoQuality // [240p, 360p, 480p, 720p, 1080p]
|
|
136
|
+
*/
|
|
129
137
|
|
|
130
138
|
/**
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
* SharePreferences
|
|
140
|
+
* @typedef {Object} SharePreferences
|
|
141
|
+
* @property {Object} [shareConstraints]
|
|
142
|
+
* @property {Boolean} [highFrameRate]
|
|
143
|
+
*/
|
|
136
144
|
|
|
137
145
|
/**
|
|
138
146
|
* JoinOptions
|
|
@@ -163,36 +171,36 @@ export const MEDIA_UPDATE_TYPE = {
|
|
|
163
171
|
*/
|
|
164
172
|
|
|
165
173
|
/**
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
174
|
+
* Meeting State Change Event
|
|
175
|
+
* Emitted when ever there is a meeting state change
|
|
176
|
+
* @event meeting:stateChange
|
|
177
|
+
* @instance
|
|
178
|
+
* @type {Object}
|
|
179
|
+
* @property {String} currentState current state of the meeting
|
|
180
|
+
* @property {String} previousState previous state of the meeting
|
|
181
|
+
* @memberof Meeting
|
|
182
|
+
*/
|
|
175
183
|
|
|
176
184
|
/**
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
185
|
+
* Media Ready Event
|
|
186
|
+
* Emitted when a stream is ready to be rendered
|
|
187
|
+
* @event media:ready
|
|
188
|
+
* @instance
|
|
189
|
+
* @type {Object}
|
|
190
|
+
* @property {MediaStream} stream the media stream
|
|
191
|
+
* @property {String} type what type of stream, remote, local
|
|
192
|
+
* @memberof Meeting
|
|
193
|
+
*/
|
|
186
194
|
|
|
187
195
|
/**
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
+
* Media Stopped Event
|
|
197
|
+
* Emitted when a stream has stopped sending
|
|
198
|
+
* @event media:stopped
|
|
199
|
+
* @instance
|
|
200
|
+
* @type {Object}
|
|
201
|
+
* @property {String} type what type of stream, remote, local
|
|
202
|
+
* @memberof Meeting
|
|
203
|
+
*/
|
|
196
204
|
|
|
197
205
|
/**
|
|
198
206
|
* Meeting Ringing Event
|
|
@@ -319,7 +327,6 @@ export const MEDIA_UPDATE_TYPE = {
|
|
|
319
327
|
* @memberof Meeting
|
|
320
328
|
*/
|
|
321
329
|
|
|
322
|
-
|
|
323
330
|
/**
|
|
324
331
|
* Meeting Self Guest Admitted Event
|
|
325
332
|
* Emitted when a joined user get admitted to the meeting by another member or host
|
|
@@ -351,42 +358,42 @@ export const MEDIA_UPDATE_TYPE = {
|
|
|
351
358
|
*/
|
|
352
359
|
|
|
353
360
|
/**
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
361
|
+
* Reconnection Starting Event
|
|
362
|
+
* Emitted when reconnection of media to the active meeting was successful
|
|
363
|
+
* @event meeting:reconnectionStarting
|
|
364
|
+
* @instance
|
|
365
|
+
* @memberof Meeting
|
|
366
|
+
*/
|
|
360
367
|
|
|
361
368
|
/**
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
369
|
+
* Reconnection Success Event
|
|
370
|
+
* Emitted when reconnection of media to the active meeting was successful
|
|
371
|
+
* @event meeting:reconnectionSuccess
|
|
372
|
+
* @instance
|
|
373
|
+
* @type {Object}
|
|
374
|
+
* @property {Object} reconnect
|
|
375
|
+
* @memberof Meeting
|
|
376
|
+
*/
|
|
370
377
|
|
|
371
378
|
/**
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
379
|
+
* Reconnection Failure Event
|
|
380
|
+
* Emitted when reconnection of media to the active meeting was successful
|
|
381
|
+
* @event meeting:reconnectionFailure
|
|
382
|
+
* @instance
|
|
383
|
+
* @type {Object}
|
|
384
|
+
* @property {Error} error
|
|
385
|
+
* @memberof Meeting
|
|
386
|
+
*/
|
|
380
387
|
|
|
381
388
|
/**
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
389
|
+
* Meeting network quality event
|
|
390
|
+
* Emitted on each interval of retrieving stats Analyzer data
|
|
391
|
+
* @event network:quality
|
|
392
|
+
* @type {Object}
|
|
393
|
+
* @property {string} mediaType {video|audio}
|
|
394
|
+
* @property {number} networkQualityScore - {1|0} 1 indicates acceptable uplink 0 indicates unacceptable uplink based on threshold
|
|
395
|
+
* @memberof Meeting
|
|
396
|
+
*/
|
|
390
397
|
|
|
391
398
|
/**
|
|
392
399
|
* @description Meeting is the crux of the plugin
|
|
@@ -448,6 +455,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
448
455
|
audio: MediaRequestManager;
|
|
449
456
|
video: MediaRequestManager;
|
|
450
457
|
};
|
|
458
|
+
|
|
451
459
|
meetingInfoFailureReason: string;
|
|
452
460
|
networkQualityMonitor: NetworkQualityMonitor;
|
|
453
461
|
networkStatus: string;
|
|
@@ -479,6 +487,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
479
487
|
resourceUrl: string;
|
|
480
488
|
selfId: string;
|
|
481
489
|
state: any;
|
|
490
|
+
|
|
482
491
|
namespace = MEETINGS;
|
|
483
492
|
|
|
484
493
|
/**
|
|
@@ -486,7 +495,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
486
495
|
* @param {Object} options
|
|
487
496
|
* @constructor
|
|
488
497
|
* @memberof Meeting
|
|
489
|
-
|
|
498
|
+
*/
|
|
490
499
|
constructor(attrs: any, options: object) {
|
|
491
500
|
super({}, options);
|
|
492
501
|
/**
|
|
@@ -575,20 +584,30 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
575
584
|
this.mediaRequestManagers = {
|
|
576
585
|
audio: new MediaRequestManager((mediaRequests) => {
|
|
577
586
|
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
578
|
-
LoggerProxy.logger.warn(
|
|
587
|
+
LoggerProxy.logger.warn(
|
|
588
|
+
'Meeting:index#mediaRequestManager --> trying to send audio media request before media connection was created'
|
|
589
|
+
);
|
|
579
590
|
|
|
580
591
|
return;
|
|
581
592
|
}
|
|
582
|
-
this.mediaProperties.webrtcMediaConnection.requestMedia(
|
|
593
|
+
this.mediaProperties.webrtcMediaConnection.requestMedia(
|
|
594
|
+
MC.MediaType.AudioMain,
|
|
595
|
+
mediaRequests
|
|
596
|
+
);
|
|
583
597
|
}),
|
|
584
598
|
video: new MediaRequestManager((mediaRequests) => {
|
|
585
599
|
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
586
|
-
LoggerProxy.logger.warn(
|
|
600
|
+
LoggerProxy.logger.warn(
|
|
601
|
+
'Meeting:index#mediaRequestManager --> trying to send video media request before media connection was created'
|
|
602
|
+
);
|
|
587
603
|
|
|
588
604
|
return;
|
|
589
605
|
}
|
|
590
|
-
this.mediaProperties.webrtcMediaConnection.requestMedia(
|
|
591
|
-
|
|
606
|
+
this.mediaProperties.webrtcMediaConnection.requestMedia(
|
|
607
|
+
MC.MediaType.VideoMain,
|
|
608
|
+
mediaRequests
|
|
609
|
+
);
|
|
610
|
+
}),
|
|
592
611
|
};
|
|
593
612
|
/**
|
|
594
613
|
* @instance
|
|
@@ -596,12 +615,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
596
615
|
* @public
|
|
597
616
|
* @memberof Meeting
|
|
598
617
|
*/
|
|
599
|
-
this.members = new Members(
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
618
|
+
this.members = new Members(
|
|
619
|
+
{
|
|
620
|
+
locusUrl: attrs.locus && attrs.locus.url,
|
|
621
|
+
receiveSlotManager: this.receiveSlotManager,
|
|
622
|
+
mediaRequestManagers: this.mediaRequestManagers,
|
|
623
|
+
// @ts-ignore - Fix type
|
|
624
|
+
},
|
|
625
|
+
{parent: this.webex}
|
|
626
|
+
);
|
|
605
627
|
/**
|
|
606
628
|
* @instance
|
|
607
629
|
* @type {Roap}
|
|
@@ -800,7 +822,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
800
822
|
* @type {InMeetingActions}
|
|
801
823
|
* @public
|
|
802
824
|
* @memberof Meeting
|
|
803
|
-
|
|
825
|
+
*/
|
|
804
826
|
this.inMeetingActions = new InMeetingActions();
|
|
805
827
|
/**
|
|
806
828
|
* This is deprecated, please use shareStatus instead.
|
|
@@ -1022,32 +1044,55 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1022
1044
|
* @memberof Meeting
|
|
1023
1045
|
* @returns {Promise}
|
|
1024
1046
|
*/
|
|
1025
|
-
public async fetchMeetingInfo({
|
|
1047
|
+
public async fetchMeetingInfo({
|
|
1048
|
+
password = null,
|
|
1049
|
+
captchaCode = null,
|
|
1050
|
+
}: {
|
|
1051
|
+
password?: string;
|
|
1052
|
+
captchaCode?: string;
|
|
1053
|
+
}) {
|
|
1026
1054
|
// when fetch meeting info is called directly by the client, we want to clear out the random timer for sdk to do it
|
|
1027
1055
|
if (this.fetchMeetingInfoTimeoutId) {
|
|
1028
1056
|
clearTimeout(this.fetchMeetingInfoTimeoutId);
|
|
1029
1057
|
this.fetchMeetingInfoTimeoutId = undefined;
|
|
1030
1058
|
}
|
|
1031
1059
|
if (captchaCode && !this.requiredCaptcha) {
|
|
1032
|
-
return Promise.reject(
|
|
1060
|
+
return Promise.reject(
|
|
1061
|
+
new Error('fetchMeetingInfo() called with captchaCode when captcha was not required')
|
|
1062
|
+
);
|
|
1033
1063
|
}
|
|
1034
|
-
if (
|
|
1035
|
-
|
|
1064
|
+
if (
|
|
1065
|
+
password &&
|
|
1066
|
+
this.passwordStatus !== PASSWORD_STATUS.REQUIRED &&
|
|
1067
|
+
this.passwordStatus !== PASSWORD_STATUS.UNKNOWN
|
|
1068
|
+
) {
|
|
1069
|
+
return Promise.reject(
|
|
1070
|
+
new Error('fetchMeetingInfo() called with password when password was not required')
|
|
1071
|
+
);
|
|
1036
1072
|
}
|
|
1037
1073
|
|
|
1038
1074
|
try {
|
|
1039
|
-
const captchaInfo = captchaCode
|
|
1040
|
-
|
|
1041
|
-
|
|
1075
|
+
const captchaInfo = captchaCode
|
|
1076
|
+
? {code: captchaCode, id: this.requiredCaptcha.captchaId}
|
|
1077
|
+
: null;
|
|
1078
|
+
|
|
1079
|
+
const info = await this.attrs.meetingInfoProvider.fetchMeetingInfo(
|
|
1080
|
+
this.destination,
|
|
1081
|
+
this.destinationType,
|
|
1082
|
+
password,
|
|
1083
|
+
captchaInfo
|
|
1084
|
+
);
|
|
1042
1085
|
|
|
1043
1086
|
this.parseMeetingInfo(info, this.destination);
|
|
1044
1087
|
this.meetingInfo = info ? info.body : null;
|
|
1045
1088
|
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NONE;
|
|
1046
1089
|
this.requiredCaptcha = null;
|
|
1047
|
-
if (
|
|
1090
|
+
if (
|
|
1091
|
+
this.passwordStatus === PASSWORD_STATUS.REQUIRED ||
|
|
1092
|
+
this.passwordStatus === PASSWORD_STATUS.VERIFIED
|
|
1093
|
+
) {
|
|
1048
1094
|
this.passwordStatus = PASSWORD_STATUS.VERIFIED;
|
|
1049
|
-
}
|
|
1050
|
-
else {
|
|
1095
|
+
} else {
|
|
1051
1096
|
this.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
|
|
1052
1097
|
}
|
|
1053
1098
|
|
|
@@ -1055,17 +1100,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1055
1100
|
this,
|
|
1056
1101
|
{
|
|
1057
1102
|
file: 'meetings',
|
|
1058
|
-
function: 'fetchMeetingInfo'
|
|
1103
|
+
function: 'fetchMeetingInfo',
|
|
1059
1104
|
},
|
|
1060
1105
|
EVENT_TRIGGERS.MEETING_INFO_AVAILABLE
|
|
1061
1106
|
);
|
|
1062
1107
|
|
|
1063
1108
|
return Promise.resolve();
|
|
1064
|
-
}
|
|
1065
|
-
catch (err) {
|
|
1109
|
+
} catch (err) {
|
|
1066
1110
|
if (err instanceof MeetingInfoV2PasswordError) {
|
|
1067
1111
|
// @ts-ignore
|
|
1068
|
-
LoggerProxy.logger.info(
|
|
1112
|
+
LoggerProxy.logger.info(
|
|
1113
|
+
`Meeting:index#fetchMeetingInfo --> Info Unable to fetch meeting info for ${this.destination} - password required (code=${err?.body?.code}).`
|
|
1114
|
+
);
|
|
1069
1115
|
|
|
1070
1116
|
// when wbxappapi requires password it still populates partial meeting info in the response
|
|
1071
1117
|
if (err.meetingInfo) {
|
|
@@ -1080,26 +1126,26 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1080
1126
|
await this.refreshCaptcha();
|
|
1081
1127
|
}
|
|
1082
1128
|
|
|
1083
|
-
throw
|
|
1084
|
-
}
|
|
1085
|
-
else if (err instanceof MeetingInfoV2CaptchaError) {
|
|
1129
|
+
throw new PasswordError();
|
|
1130
|
+
} else if (err instanceof MeetingInfoV2CaptchaError) {
|
|
1086
1131
|
// @ts-ignore
|
|
1087
|
-
LoggerProxy.logger.info(
|
|
1132
|
+
LoggerProxy.logger.info(
|
|
1133
|
+
`Meeting:index#fetchMeetingInfo --> Info Unable to fetch meeting info for ${this.destination} - captcha required (code=${err?.body?.code}).`
|
|
1134
|
+
);
|
|
1088
1135
|
|
|
1089
|
-
this.meetingInfoFailureReason =
|
|
1090
|
-
MEETING_INFO_FAILURE_REASON.WRONG_CAPTCHA
|
|
1091
|
-
MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD;
|
|
1136
|
+
this.meetingInfoFailureReason = this.requiredCaptcha
|
|
1137
|
+
? MEETING_INFO_FAILURE_REASON.WRONG_CAPTCHA
|
|
1138
|
+
: MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD;
|
|
1092
1139
|
|
|
1093
1140
|
if (err.isPasswordRequired) {
|
|
1094
1141
|
this.passwordStatus = PASSWORD_STATUS.REQUIRED;
|
|
1095
1142
|
}
|
|
1096
1143
|
|
|
1097
1144
|
this.requiredCaptcha = err.captchaInfo;
|
|
1098
|
-
throw
|
|
1099
|
-
}
|
|
1100
|
-
else {
|
|
1145
|
+
throw new CaptchaError();
|
|
1146
|
+
} else {
|
|
1101
1147
|
this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.OTHER;
|
|
1102
|
-
throw
|
|
1148
|
+
throw err;
|
|
1103
1149
|
}
|
|
1104
1150
|
}
|
|
1105
1151
|
}
|
|
@@ -1115,24 +1161,27 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1115
1161
|
*/
|
|
1116
1162
|
public verifyPassword(password: string, captchaCode: string) {
|
|
1117
1163
|
return this.fetchMeetingInfo({
|
|
1118
|
-
password,
|
|
1164
|
+
password,
|
|
1165
|
+
captchaCode,
|
|
1119
1166
|
})
|
|
1120
1167
|
.then(() => {
|
|
1121
|
-
Metrics.sendBehavioralMetric(
|
|
1122
|
-
BEHAVIORAL_METRICS.VERIFY_PASSWORD_SUCCESS
|
|
1123
|
-
);
|
|
1168
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.VERIFY_PASSWORD_SUCCESS);
|
|
1124
1169
|
|
|
1125
|
-
return {
|
|
1170
|
+
return {
|
|
1171
|
+
isPasswordValid: true,
|
|
1172
|
+
requiredCaptcha: null,
|
|
1173
|
+
failureReason: MEETING_INFO_FAILURE_REASON.NONE,
|
|
1174
|
+
};
|
|
1126
1175
|
})
|
|
1127
1176
|
.catch((error) => {
|
|
1128
1177
|
if (error instanceof PasswordError || error instanceof CaptchaError) {
|
|
1129
1178
|
return {
|
|
1130
1179
|
isPasswordValid: this.passwordStatus === PASSWORD_STATUS.VERIFIED,
|
|
1131
1180
|
requiredCaptcha: this.requiredCaptcha,
|
|
1132
|
-
failureReason: this.meetingInfoFailureReason
|
|
1181
|
+
failureReason: this.meetingInfoFailureReason,
|
|
1133
1182
|
};
|
|
1134
1183
|
}
|
|
1135
|
-
throw
|
|
1184
|
+
throw error;
|
|
1136
1185
|
});
|
|
1137
1186
|
}
|
|
1138
1187
|
|
|
@@ -1152,18 +1201,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1152
1201
|
// we have to pass the wbxappapi hostname as the siteFullName parameter
|
|
1153
1202
|
const {hostname} = new URL(this.requiredCaptcha.refreshURL);
|
|
1154
1203
|
|
|
1155
|
-
return this.meetingRequest
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1204
|
+
return this.meetingRequest
|
|
1205
|
+
.refreshCaptcha({
|
|
1206
|
+
captchaRefreshUrl: `${this.requiredCaptcha.refreshURL}&siteFullName=${hostname}`,
|
|
1207
|
+
captchaId: this.requiredCaptcha.captchaId,
|
|
1208
|
+
})
|
|
1159
1209
|
.then((response) => {
|
|
1160
1210
|
this.requiredCaptcha.captchaId = response.body.captchaID;
|
|
1161
1211
|
this.requiredCaptcha.verificationImageURL = response.body.verificationImageURL;
|
|
1162
1212
|
this.requiredCaptcha.verificationAudioURL = response.body.verificationAudioURL;
|
|
1163
1213
|
})
|
|
1164
1214
|
.catch((error) => {
|
|
1165
|
-
LoggerProxy.logger.error(
|
|
1166
|
-
|
|
1215
|
+
LoggerProxy.logger.error(
|
|
1216
|
+
`Meeting:index#refreshCaptcha --> Error Unable to refresh captcha for ${this.destination} - ${error}`
|
|
1217
|
+
);
|
|
1218
|
+
throw error;
|
|
1167
1219
|
});
|
|
1168
1220
|
}
|
|
1169
1221
|
|
|
@@ -1203,13 +1255,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1203
1255
|
// https:// jira-eng-gpk2.cisco.com/jira/browse/SPARK-240520
|
|
1204
1256
|
// TODO: send custom parameter explaining why the inactivity happened
|
|
1205
1257
|
// refresh , no media or network got dsconnected or something else
|
|
1206
|
-
Metrics.sendBehavioralMetric(
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
locus_id: this.locusId
|
|
1211
|
-
}
|
|
1212
|
-
);
|
|
1258
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.DISCONNECT_DUE_TO_INACTIVITY, {
|
|
1259
|
+
correlation_id: this.correlationId,
|
|
1260
|
+
locus_id: this.locusId,
|
|
1261
|
+
});
|
|
1213
1262
|
|
|
1214
1263
|
// Upload logs on media inactivity
|
|
1215
1264
|
// Normally media should not be inactive
|
|
@@ -1217,24 +1266,25 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1217
1266
|
this,
|
|
1218
1267
|
{
|
|
1219
1268
|
file: 'meeting/index',
|
|
1220
|
-
function: 'setUpLocusInfoMediaInactiveListener'
|
|
1269
|
+
function: 'setUpLocusInfoMediaInactiveListener',
|
|
1221
1270
|
},
|
|
1222
1271
|
EVENTS.REQUEST_UPLOAD_LOGS,
|
|
1223
1272
|
this
|
|
1224
1273
|
);
|
|
1225
1274
|
|
|
1226
|
-
LoggerProxy.logger.error(
|
|
1275
|
+
LoggerProxy.logger.error(
|
|
1276
|
+
`Meeting:index#setUpLocusInfoMediaInactiveListener --> Meeting disconnected due to inactivity: ${res.reason}`
|
|
1277
|
+
);
|
|
1227
1278
|
|
|
1228
1279
|
// @ts-ignore - config coming from registerPlugin
|
|
1229
1280
|
if (this.config.reconnection.autoRejoin) {
|
|
1230
1281
|
this.reconnect();
|
|
1231
|
-
}
|
|
1232
|
-
else {
|
|
1282
|
+
} else {
|
|
1233
1283
|
Trigger.trigger(
|
|
1234
1284
|
this,
|
|
1235
1285
|
{
|
|
1236
1286
|
file: 'meeting/index',
|
|
1237
|
-
function: 'setUpLocusInfoMediaInactiveListener'
|
|
1287
|
+
function: 'setUpLocusInfoMediaInactiveListener',
|
|
1238
1288
|
},
|
|
1239
1289
|
EVENT_TRIGGERS.MEETING_SELF_LEFT,
|
|
1240
1290
|
res.reason
|
|
@@ -1260,7 +1310,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1260
1310
|
this,
|
|
1261
1311
|
{
|
|
1262
1312
|
file: 'meeting/index',
|
|
1263
|
-
function: 'setUpLocusInfoAssignHostListener'
|
|
1313
|
+
function: 'setUpLocusInfoAssignHostListener',
|
|
1264
1314
|
},
|
|
1265
1315
|
EVENT_TRIGGERS.MEETING_ACTIONS_UPDATE,
|
|
1266
1316
|
this.inMeetingActions.get()
|
|
@@ -1281,11 +1331,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1281
1331
|
this,
|
|
1282
1332
|
{
|
|
1283
1333
|
file: 'meeting/index',
|
|
1284
|
-
function: 'setUpLocusFullStateListener'
|
|
1334
|
+
function: 'setUpLocusFullStateListener',
|
|
1285
1335
|
},
|
|
1286
1336
|
EVENT_TRIGGERS.MEETING_STATE_CHANGE,
|
|
1287
1337
|
{
|
|
1288
|
-
payload
|
|
1338
|
+
payload,
|
|
1289
1339
|
}
|
|
1290
1340
|
);
|
|
1291
1341
|
});
|
|
@@ -1306,22 +1356,26 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1306
1356
|
* @returns {Object}
|
|
1307
1357
|
* @memberof Meeting
|
|
1308
1358
|
*/
|
|
1309
|
-
getAnalyzerMetricsPrePayload(
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1359
|
+
getAnalyzerMetricsPrePayload(
|
|
1360
|
+
options:
|
|
1361
|
+
| {
|
|
1362
|
+
event: string;
|
|
1363
|
+
trackingId: string;
|
|
1364
|
+
locus: object;
|
|
1365
|
+
mediaConnections: Array<any>;
|
|
1366
|
+
errors: object;
|
|
1367
|
+
}
|
|
1368
|
+
| any
|
|
1369
|
+
) {
|
|
1316
1370
|
if (options) {
|
|
1317
|
-
const {
|
|
1318
|
-
event,
|
|
1319
|
-
trackingId,
|
|
1320
|
-
mediaConnections
|
|
1321
|
-
} = options;
|
|
1371
|
+
const {event, trackingId, mediaConnections} = options;
|
|
1322
1372
|
|
|
1323
1373
|
if (!event) {
|
|
1324
|
-
LoggerProxy.logger.error(
|
|
1374
|
+
LoggerProxy.logger.error(
|
|
1375
|
+
'Meeting:index#getAnalyzerMetricsPrePayload --> Error [Call Analyzer Event',
|
|
1376
|
+
event || '',
|
|
1377
|
+
`]: invalid identifers or event type! ${this.correlationId}`
|
|
1378
|
+
);
|
|
1325
1379
|
|
|
1326
1380
|
return null;
|
|
1327
1381
|
}
|
|
@@ -1332,13 +1386,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1332
1386
|
deviceId: this.deviceUrl,
|
|
1333
1387
|
orgId: this.orgId,
|
|
1334
1388
|
// @ts-ignore fix type
|
|
1335
|
-
locusUrl: this.webex.internal.services.get('locus')
|
|
1389
|
+
locusUrl: this.webex.internal.services.get('locus'),
|
|
1336
1390
|
};
|
|
1337
1391
|
|
|
1338
1392
|
if (this.locusUrl && this.locusInfo.fullState) {
|
|
1339
1393
|
identifiers.locusUrl = this.locusUrl;
|
|
1340
1394
|
identifiers.locusId = this.locusUrl && this.locusUrl.split('/').pop();
|
|
1341
|
-
identifiers.locusStartTime =
|
|
1395
|
+
identifiers.locusStartTime =
|
|
1396
|
+
this.locusInfo.fullState && this.locusInfo.fullState.lastActive;
|
|
1342
1397
|
}
|
|
1343
1398
|
|
|
1344
1399
|
// Check if mediaConnections has been passed in or else use this.mediaConnections
|
|
@@ -1346,8 +1401,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1346
1401
|
identifiers.mediaAgentAlias = mediaConnections?.[0].mediaAgentAlias;
|
|
1347
1402
|
identifiers.mediaAgentGroupId = mediaConnections?.[0].mediaAgentGroupId;
|
|
1348
1403
|
identifiers.mediaAgentCluster = mediaConnections?.[0].mediaAgentCluster;
|
|
1349
|
-
}
|
|
1350
|
-
else if (this.mediaConnections) {
|
|
1404
|
+
} else if (this.mediaConnections) {
|
|
1351
1405
|
identifiers.mediaAgentAlias = this.mediaConnections?.[0].mediaAgentAlias;
|
|
1352
1406
|
identifiers.mediaAgentGroupId = this.mediaConnections?.[0].mediaAgentGroupId;
|
|
1353
1407
|
identifiers.mediaAgentCluster = this.mediaConnections?.[0].mediaAgentCluster;
|
|
@@ -1363,7 +1417,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1363
1417
|
|
|
1364
1418
|
if (joinRespRxStartAudio) {
|
|
1365
1419
|
options.audioSetupDelay = {
|
|
1366
|
-
joinRespRxStart: joinRespRxStartAudio
|
|
1420
|
+
joinRespRxStart: joinRespRxStartAudio,
|
|
1367
1421
|
};
|
|
1368
1422
|
}
|
|
1369
1423
|
|
|
@@ -1371,7 +1425,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1371
1425
|
|
|
1372
1426
|
if (joinRespRxStartAudio) {
|
|
1373
1427
|
options.videoSetupDelay = {
|
|
1374
|
-
joinRespRxStart: joinRespRxStartVideo
|
|
1428
|
+
joinRespRxStart: joinRespRxStartVideo,
|
|
1375
1429
|
};
|
|
1376
1430
|
}
|
|
1377
1431
|
|
|
@@ -1380,7 +1434,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1380
1434
|
if (joinRespTxStartAudio) {
|
|
1381
1435
|
options.audioSetupDelay = {
|
|
1382
1436
|
...options.audioSetupDelay,
|
|
1383
|
-
joinRespTxStart: joinRespTxStartAudio
|
|
1437
|
+
joinRespTxStart: joinRespTxStartAudio,
|
|
1384
1438
|
};
|
|
1385
1439
|
}
|
|
1386
1440
|
|
|
@@ -1389,7 +1443,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1389
1443
|
if (joinRespTxStartVideo) {
|
|
1390
1444
|
options.videoSetupDelay = {
|
|
1391
1445
|
...options.videoSetupDelay,
|
|
1392
|
-
joinRespTxStart: joinRespTxStartVideo
|
|
1446
|
+
joinRespTxStart: joinRespTxStartVideo,
|
|
1393
1447
|
};
|
|
1394
1448
|
}
|
|
1395
1449
|
|
|
@@ -1398,7 +1452,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1398
1452
|
if (localSDPGenRemoteSDPRecv) {
|
|
1399
1453
|
options.joinTimes = {
|
|
1400
1454
|
...options.joinTimes,
|
|
1401
|
-
localSDPGenRemoteSDPRecv
|
|
1455
|
+
localSDPGenRemoteSDPRecv,
|
|
1402
1456
|
};
|
|
1403
1457
|
}
|
|
1404
1458
|
|
|
@@ -1407,7 +1461,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1407
1461
|
if (callInitiateJoinReq) {
|
|
1408
1462
|
options.joinTimes = {
|
|
1409
1463
|
...options.joinTimes,
|
|
1410
|
-
callInitiateJoinReq
|
|
1464
|
+
callInitiateJoinReq,
|
|
1411
1465
|
};
|
|
1412
1466
|
}
|
|
1413
1467
|
|
|
@@ -1416,7 +1470,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1416
1470
|
if (joinReqResp) {
|
|
1417
1471
|
options.joinTimes = {
|
|
1418
1472
|
...options.joinTimes,
|
|
1419
|
-
joinReqResp
|
|
1473
|
+
joinReqResp,
|
|
1420
1474
|
};
|
|
1421
1475
|
}
|
|
1422
1476
|
|
|
@@ -1425,14 +1479,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1425
1479
|
if (getTotalJmt) {
|
|
1426
1480
|
options.joinTimes = {
|
|
1427
1481
|
...options.joinTimes,
|
|
1428
|
-
getTotalJmt
|
|
1482
|
+
getTotalJmt,
|
|
1429
1483
|
};
|
|
1430
1484
|
}
|
|
1431
1485
|
|
|
1432
1486
|
if (options.type === MQA_STATS.CA_TYPE) {
|
|
1433
1487
|
payload = Metrics.initMediaPayload(options.event, identifiers, options);
|
|
1434
|
-
}
|
|
1435
|
-
else {
|
|
1488
|
+
} else {
|
|
1436
1489
|
payload = Metrics.initPayload(options.event, identifiers, options);
|
|
1437
1490
|
}
|
|
1438
1491
|
|
|
@@ -1453,11 +1506,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1453
1506
|
* @private
|
|
1454
1507
|
* @memberof Meeting
|
|
1455
1508
|
*/
|
|
1456
|
-
private sendCallAnalyzerMetrics(options: {
|
|
1509
|
+
private sendCallAnalyzerMetrics(options: {
|
|
1510
|
+
event: string;
|
|
1511
|
+
trackingId: string;
|
|
1512
|
+
locus: object;
|
|
1513
|
+
errors: object;
|
|
1514
|
+
}) {
|
|
1457
1515
|
const payload = this.getAnalyzerMetricsPrePayload({
|
|
1458
1516
|
// @ts-ignore - config coming from registerPlugin
|
|
1459
1517
|
...pick(this.config.metrics, ['clientType', 'subClientType']),
|
|
1460
|
-
...options
|
|
1518
|
+
...options,
|
|
1461
1519
|
});
|
|
1462
1520
|
|
|
1463
1521
|
// @ts-ignore - fix type
|
|
@@ -1474,12 +1532,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1474
1532
|
* @private
|
|
1475
1533
|
* @memberof Meeting
|
|
1476
1534
|
*/
|
|
1477
|
-
private sendMediaQualityAnalyzerMetrics(options: {
|
|
1535
|
+
private sendMediaQualityAnalyzerMetrics(options: {
|
|
1536
|
+
event: string;
|
|
1537
|
+
trackingId: string;
|
|
1538
|
+
locus: object;
|
|
1539
|
+
}) {
|
|
1478
1540
|
const payload = this.getAnalyzerMetricsPrePayload({
|
|
1479
1541
|
type: MQA_STATS.CA_TYPE,
|
|
1480
1542
|
// @ts-ignore - config coming from registerPlugin
|
|
1481
1543
|
...pick(this.config.metrics, ['clientType', 'subClientType']),
|
|
1482
|
-
...options
|
|
1544
|
+
...options,
|
|
1483
1545
|
});
|
|
1484
1546
|
|
|
1485
1547
|
// @ts-ignore
|
|
@@ -1499,19 +1561,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1499
1561
|
this,
|
|
1500
1562
|
{
|
|
1501
1563
|
file: 'meeting/index',
|
|
1502
|
-
function: 'setNetworkStatus'
|
|
1564
|
+
function: 'setNetworkStatus',
|
|
1503
1565
|
},
|
|
1504
|
-
EVENT_TRIGGERS.MEETINGS_NETWORK_DISCONNECTED
|
|
1566
|
+
EVENT_TRIGGERS.MEETINGS_NETWORK_DISCONNECTED
|
|
1505
1567
|
);
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1568
|
+
} else if (
|
|
1569
|
+
networkStatus === NETWORK_STATUS.CONNECTED &&
|
|
1570
|
+
this.networkStatus === NETWORK_STATUS.DISCONNECTED
|
|
1571
|
+
) {
|
|
1508
1572
|
Trigger.trigger(
|
|
1509
1573
|
this,
|
|
1510
1574
|
{
|
|
1511
1575
|
file: 'meeting/index',
|
|
1512
|
-
function: 'setNetworkStatus'
|
|
1576
|
+
function: 'setNetworkStatus',
|
|
1513
1577
|
},
|
|
1514
|
-
EVENT_TRIGGERS.MEETINGS_NETWORK_CONNECTED
|
|
1578
|
+
EVENT_TRIGGERS.MEETINGS_NETWORK_CONNECTED
|
|
1515
1579
|
);
|
|
1516
1580
|
}
|
|
1517
1581
|
|
|
@@ -1533,8 +1597,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1533
1597
|
|
|
1534
1598
|
// If user moved to a JOINED state and there is a pending floor grant trigger it
|
|
1535
1599
|
if (this.floorGrantPending && payload.newSelf.state === MEETING_STATE.STATES.JOINED) {
|
|
1536
|
-
this.requestScreenShareFloor()
|
|
1537
|
-
|
|
1600
|
+
this.requestScreenShareFloor().then(() => {
|
|
1601
|
+
this.floorGrantPending = false;
|
|
1602
|
+
});
|
|
1538
1603
|
}
|
|
1539
1604
|
});
|
|
1540
1605
|
}
|
|
@@ -1548,8 +1613,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1548
1613
|
*/
|
|
1549
1614
|
private pstnUpdate(payload: any) {
|
|
1550
1615
|
if (this.locusInfo.self) {
|
|
1551
|
-
const dialInPstnDevice = payload.newSelf?.pstnDevices.find(
|
|
1552
|
-
|
|
1616
|
+
const dialInPstnDevice = payload.newSelf?.pstnDevices.find(
|
|
1617
|
+
(device) => device.url === this.dialInUrl
|
|
1618
|
+
);
|
|
1619
|
+
const dialOutPstnDevice = payload.newSelf?.pstnDevices.find(
|
|
1620
|
+
(device) => device.url === this.dialOutUrl
|
|
1621
|
+
);
|
|
1553
1622
|
let changed = false;
|
|
1554
1623
|
|
|
1555
1624
|
if (dialInPstnDevice) {
|
|
@@ -1575,18 +1644,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1575
1644
|
this,
|
|
1576
1645
|
{
|
|
1577
1646
|
file: 'meeting/index',
|
|
1578
|
-
function: 'setUpLocusSelfListener'
|
|
1647
|
+
function: 'setUpLocusSelfListener',
|
|
1579
1648
|
},
|
|
1580
1649
|
EVENT_TRIGGERS.MEETING_SELF_PHONE_AUDIO_UPDATE,
|
|
1581
1650
|
{
|
|
1582
1651
|
dialIn: {
|
|
1583
1652
|
status: this.dialInDeviceStatus,
|
|
1584
|
-
attendeeId: dialInPstnDevice?.attendeeId
|
|
1653
|
+
attendeeId: dialInPstnDevice?.attendeeId,
|
|
1585
1654
|
},
|
|
1586
1655
|
dialOut: {
|
|
1587
1656
|
status: this.dialOutDeviceStatus,
|
|
1588
|
-
attendeeId: dialOutPstnDevice?.attendeeId
|
|
1589
|
-
}
|
|
1657
|
+
attendeeId: dialOutPstnDevice?.attendeeId,
|
|
1658
|
+
},
|
|
1590
1659
|
}
|
|
1591
1660
|
);
|
|
1592
1661
|
}
|
|
@@ -1639,8 +1708,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1639
1708
|
* @private
|
|
1640
1709
|
* @memberof Meeting
|
|
1641
1710
|
*/
|
|
1642
|
-
|
|
1643
|
-
this.locusInfo.on(
|
|
1711
|
+
private setupLocusControlsListener() {
|
|
1712
|
+
this.locusInfo.on(
|
|
1713
|
+
LOCUSINFO.EVENTS.CONTROLS_RECORDING_UPDATED,
|
|
1644
1714
|
({state, modifiedBy, lastModified}) => {
|
|
1645
1715
|
let event;
|
|
1646
1716
|
|
|
@@ -1666,65 +1736,67 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1666
1736
|
this.recording = {
|
|
1667
1737
|
state: state === RECORDING_STATE.RESUMED ? RECORDING_STATE.RECORDING : state,
|
|
1668
1738
|
modifiedBy,
|
|
1669
|
-
lastModified
|
|
1739
|
+
lastModified,
|
|
1670
1740
|
};
|
|
1671
1741
|
|
|
1672
1742
|
Trigger.trigger(
|
|
1673
1743
|
this,
|
|
1674
1744
|
{
|
|
1675
1745
|
file: 'meeting/index',
|
|
1676
|
-
function: 'setupLocusControlsListener'
|
|
1746
|
+
function: 'setupLocusControlsListener',
|
|
1677
1747
|
},
|
|
1678
1748
|
event,
|
|
1679
1749
|
this.recording
|
|
1680
1750
|
);
|
|
1681
|
-
}
|
|
1751
|
+
}
|
|
1752
|
+
);
|
|
1682
1753
|
|
|
1683
|
-
this.locusInfo.on(
|
|
1754
|
+
this.locusInfo.on(
|
|
1755
|
+
LOCUSINFO.EVENTS.CONTROLS_MEETING_CONTAINER_UPDATED,
|
|
1684
1756
|
({meetingContainerUrl}) => {
|
|
1685
1757
|
Trigger.trigger(
|
|
1686
1758
|
this,
|
|
1687
1759
|
{
|
|
1688
1760
|
file: 'meeting/index',
|
|
1689
|
-
function: 'setupLocusControlsListener'
|
|
1761
|
+
function: 'setupLocusControlsListener',
|
|
1690
1762
|
},
|
|
1691
1763
|
EVENT_TRIGGERS.MEETING_MEETING_CONTAINER_UPDATE,
|
|
1692
1764
|
{meetingContainerUrl}
|
|
1693
1765
|
);
|
|
1694
|
-
}
|
|
1766
|
+
}
|
|
1767
|
+
);
|
|
1695
1768
|
|
|
1696
|
-
this.locusInfo.on(
|
|
1769
|
+
this.locusInfo.on(
|
|
1770
|
+
LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIBE_UPDATED,
|
|
1697
1771
|
({caption, transcribing}) => {
|
|
1698
|
-
|
|
1699
1772
|
// @ts-ignore - config coming from registerPlugin
|
|
1700
1773
|
if (transcribing && this.transcription && this.config.receiveTranscription) {
|
|
1701
1774
|
this.receiveTranscription();
|
|
1702
|
-
}
|
|
1703
|
-
else if (!transcribing && this.transcription) {
|
|
1775
|
+
} else if (!transcribing && this.transcription) {
|
|
1704
1776
|
Trigger.trigger(
|
|
1705
1777
|
this,
|
|
1706
1778
|
{
|
|
1707
1779
|
file: 'meeting/index',
|
|
1708
|
-
function: 'setupLocusControlsListener'
|
|
1780
|
+
function: 'setupLocusControlsListener',
|
|
1709
1781
|
},
|
|
1710
1782
|
EVENT_TRIGGERS.MEETING_STOPPED_RECEIVING_TRANSCRIPTION,
|
|
1711
1783
|
{caption, transcribing}
|
|
1712
1784
|
);
|
|
1713
1785
|
}
|
|
1714
|
-
}
|
|
1786
|
+
}
|
|
1787
|
+
);
|
|
1715
1788
|
|
|
1716
|
-
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_ENTRY_EXIT_TONE_UPDATED,
|
|
1717
|
-
(
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
});
|
|
1789
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_ENTRY_EXIT_TONE_UPDATED, ({entryExitTone}) => {
|
|
1790
|
+
Trigger.trigger(
|
|
1791
|
+
this,
|
|
1792
|
+
{
|
|
1793
|
+
file: 'meeting/index',
|
|
1794
|
+
function: 'setupLocusControlsListener',
|
|
1795
|
+
},
|
|
1796
|
+
EVENT_TRIGGERS.MEETING_ENTRY_EXIT_TONE_UPDATE,
|
|
1797
|
+
{entryExitTone}
|
|
1798
|
+
);
|
|
1799
|
+
});
|
|
1728
1800
|
}
|
|
1729
1801
|
|
|
1730
1802
|
/**
|
|
@@ -1735,7 +1807,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1735
1807
|
* @private
|
|
1736
1808
|
* @memberof Meeting
|
|
1737
1809
|
*/
|
|
1738
|
-
|
|
1810
|
+
private setUpLocusMediaSharesListener() {
|
|
1739
1811
|
// Will get triggered on local and remote share
|
|
1740
1812
|
this.locusInfo.on(EVENTS.LOCUS_INFO_UPDATE_MEDIA_SHARES, (payload) => {
|
|
1741
1813
|
const {content: contentShare, whiteboard: whiteboardShare} = payload.current;
|
|
@@ -1743,11 +1815,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1743
1815
|
const previousWhiteboardShare = payload.previous?.whiteboard;
|
|
1744
1816
|
|
|
1745
1817
|
if (
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1818
|
+
contentShare.beneficiaryId === previousContentShare?.beneficiaryId &&
|
|
1819
|
+
contentShare.disposition === previousContentShare?.disposition &&
|
|
1820
|
+
whiteboardShare.beneficiaryId === previousWhiteboardShare?.beneficiaryId &&
|
|
1821
|
+
whiteboardShare.disposition === previousWhiteboardShare?.disposition &&
|
|
1822
|
+
whiteboardShare.resourceUrl === previousWhiteboardShare?.resourceUrl
|
|
1751
1823
|
) {
|
|
1752
1824
|
// nothing changed, so ignore
|
|
1753
1825
|
// (this happens when we steal presentation from remote)
|
|
@@ -1771,13 +1843,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1771
1843
|
) {
|
|
1772
1844
|
if (this.mediaProperties.shareTrack?.readyState === 'ended') {
|
|
1773
1845
|
this.stopShare({
|
|
1774
|
-
skipSignalingCheck: true
|
|
1775
|
-
})
|
|
1776
|
-
.
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1846
|
+
skipSignalingCheck: true,
|
|
1847
|
+
}).catch((error) => {
|
|
1848
|
+
LoggerProxy.logger.log(
|
|
1849
|
+
'Meeting:index#setUpLocusMediaSharesListener --> Error stopping share: ',
|
|
1850
|
+
error
|
|
1851
|
+
);
|
|
1852
|
+
});
|
|
1853
|
+
} else {
|
|
1781
1854
|
// CONTENT - sharing content local
|
|
1782
1855
|
newShareStatus = SHARE_STATUS.LOCAL_SHARE_ACTIVE;
|
|
1783
1856
|
}
|
|
@@ -1791,10 +1864,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1791
1864
|
}
|
|
1792
1865
|
// or if content share is either released or null and whiteboard share is either released or null, no one is sharing
|
|
1793
1866
|
else if (
|
|
1794
|
-
(previousContentShare &&
|
|
1795
|
-
|
|
1796
|
-
(previousWhiteboardShare &&
|
|
1797
|
-
|
|
1867
|
+
((previousContentShare && contentShare.disposition === FLOOR_ACTION.RELEASED) ||
|
|
1868
|
+
contentShare.disposition === null) &&
|
|
1869
|
+
((previousWhiteboardShare && whiteboardShare.disposition === FLOOR_ACTION.RELEASED) ||
|
|
1870
|
+
whiteboardShare.disposition === null)
|
|
1798
1871
|
) {
|
|
1799
1872
|
newShareStatus = SHARE_STATUS.NO_SHARE;
|
|
1800
1873
|
}
|
|
@@ -1812,7 +1885,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1812
1885
|
this,
|
|
1813
1886
|
{
|
|
1814
1887
|
file: 'meetings/index',
|
|
1815
|
-
function: 'remoteShare'
|
|
1888
|
+
function: 'remoteShare',
|
|
1816
1889
|
},
|
|
1817
1890
|
EVENT_TRIGGERS.MEETING_STOPPED_SHARING_REMOTE
|
|
1818
1891
|
);
|
|
@@ -1823,11 +1896,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1823
1896
|
this,
|
|
1824
1897
|
{
|
|
1825
1898
|
file: 'meeting/index',
|
|
1826
|
-
function: 'localShare'
|
|
1899
|
+
function: 'localShare',
|
|
1827
1900
|
},
|
|
1828
1901
|
EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
|
|
1829
1902
|
{
|
|
1830
|
-
reason: SHARE_STOPPED_REASON.SELF_STOPPED
|
|
1903
|
+
reason: SHARE_STOPPED_REASON.SELF_STOPPED,
|
|
1831
1904
|
}
|
|
1832
1905
|
);
|
|
1833
1906
|
break;
|
|
@@ -1837,7 +1910,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1837
1910
|
this,
|
|
1838
1911
|
{
|
|
1839
1912
|
file: 'meeting/index',
|
|
1840
|
-
function: 'stopWhiteboardShare'
|
|
1913
|
+
function: 'stopWhiteboardShare',
|
|
1841
1914
|
},
|
|
1842
1915
|
EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD
|
|
1843
1916
|
);
|
|
@@ -1859,27 +1932,28 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1859
1932
|
this,
|
|
1860
1933
|
{
|
|
1861
1934
|
file: 'meetings/index',
|
|
1862
|
-
function: 'remoteShare'
|
|
1935
|
+
function: 'remoteShare',
|
|
1863
1936
|
},
|
|
1864
1937
|
EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
|
1865
1938
|
{
|
|
1866
|
-
memberId: contentShare.beneficiaryId
|
|
1939
|
+
memberId: contentShare.beneficiaryId,
|
|
1867
1940
|
}
|
|
1868
1941
|
);
|
|
1869
1942
|
};
|
|
1870
1943
|
|
|
1871
1944
|
// if a remote participant is stealing the presentation from us
|
|
1872
|
-
if (
|
|
1945
|
+
if (
|
|
1946
|
+
!this.mediaProperties.mediaDirection?.sendShare ||
|
|
1947
|
+
oldShareStatus === SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE
|
|
1948
|
+
) {
|
|
1873
1949
|
sendStartedSharingRemote();
|
|
1874
|
-
}
|
|
1875
|
-
else {
|
|
1950
|
+
} else {
|
|
1876
1951
|
this.updateShare({
|
|
1877
1952
|
sendShare: false,
|
|
1878
|
-
receiveShare: this.mediaProperties.mediaDirection.receiveShare
|
|
1879
|
-
})
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
});
|
|
1953
|
+
receiveShare: this.mediaProperties.mediaDirection.receiveShare,
|
|
1954
|
+
}).finally(() => {
|
|
1955
|
+
sendStartedSharingRemote();
|
|
1956
|
+
});
|
|
1883
1957
|
}
|
|
1884
1958
|
break;
|
|
1885
1959
|
}
|
|
@@ -1889,9 +1963,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1889
1963
|
this,
|
|
1890
1964
|
{
|
|
1891
1965
|
file: 'meeting/index',
|
|
1892
|
-
function: 'share'
|
|
1966
|
+
function: 'share',
|
|
1893
1967
|
},
|
|
1894
|
-
EVENT_TRIGGERS.MEETING_STARTED_SHARING_LOCAL
|
|
1968
|
+
EVENT_TRIGGERS.MEETING_STARTED_SHARING_LOCAL
|
|
1895
1969
|
);
|
|
1896
1970
|
Metrics.postEvent({event: eventType.LOCAL_SHARE_FLOOR_GRANTED, meeting: this});
|
|
1897
1971
|
break;
|
|
@@ -1901,19 +1975,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1901
1975
|
this,
|
|
1902
1976
|
{
|
|
1903
1977
|
file: 'meeting/index',
|
|
1904
|
-
function: 'startWhiteboardShare'
|
|
1978
|
+
function: 'startWhiteboardShare',
|
|
1905
1979
|
},
|
|
1906
1980
|
EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
|
1907
1981
|
{
|
|
1908
1982
|
resourceUrl: whiteboardShare.resourceUrl,
|
|
1909
|
-
memberId: whiteboardShare.beneficiaryId
|
|
1983
|
+
memberId: whiteboardShare.beneficiaryId,
|
|
1910
1984
|
}
|
|
1911
1985
|
);
|
|
1912
1986
|
Metrics.postEvent({event: eventType.WHITEBOARD_SHARE_FLOOR_GRANTED, meeting: this});
|
|
1913
1987
|
break;
|
|
1914
1988
|
|
|
1915
1989
|
case SHARE_STATUS.NO_SHARE:
|
|
1916
|
-
|
|
1990
|
+
// nothing to do
|
|
1917
1991
|
break;
|
|
1918
1992
|
|
|
1919
1993
|
default:
|
|
@@ -1921,36 +1995,34 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1921
1995
|
}
|
|
1922
1996
|
|
|
1923
1997
|
this.members.locusMediaSharesUpdate(payload);
|
|
1924
|
-
}
|
|
1925
|
-
else if (newShareStatus === SHARE_STATUS.REMOTE_SHARE_ACTIVE) {
|
|
1998
|
+
} else if (newShareStatus === SHARE_STATUS.REMOTE_SHARE_ACTIVE) {
|
|
1926
1999
|
// if we got here, then some remote participant has stolen
|
|
1927
2000
|
// the presentation from another remote participant
|
|
1928
2001
|
Trigger.trigger(
|
|
1929
2002
|
this,
|
|
1930
2003
|
{
|
|
1931
2004
|
file: 'meetings/index',
|
|
1932
|
-
function: 'remoteShare'
|
|
2005
|
+
function: 'remoteShare',
|
|
1933
2006
|
},
|
|
1934
2007
|
EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
|
|
1935
2008
|
{
|
|
1936
|
-
memberId: contentShare.beneficiaryId
|
|
2009
|
+
memberId: contentShare.beneficiaryId,
|
|
1937
2010
|
}
|
|
1938
2011
|
);
|
|
1939
2012
|
this.members.locusMediaSharesUpdate(payload);
|
|
1940
|
-
}
|
|
1941
|
-
else if (newShareStatus === SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE) {
|
|
2013
|
+
} else if (newShareStatus === SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE) {
|
|
1942
2014
|
// if we got here, then some remote participant has stolen
|
|
1943
2015
|
// the presentation from another remote participant
|
|
1944
2016
|
Trigger.trigger(
|
|
1945
2017
|
this,
|
|
1946
2018
|
{
|
|
1947
2019
|
file: 'meeting/index',
|
|
1948
|
-
function: 'startWhiteboardShare'
|
|
2020
|
+
function: 'startWhiteboardShare',
|
|
1949
2021
|
},
|
|
1950
2022
|
EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
|
|
1951
2023
|
{
|
|
1952
2024
|
resourceUrl: whiteboardShare.resourceUrl,
|
|
1953
|
-
memberId: whiteboardShare.beneficiaryId
|
|
2025
|
+
memberId: whiteboardShare.beneficiaryId,
|
|
1954
2026
|
}
|
|
1955
2027
|
);
|
|
1956
2028
|
Metrics.postEvent({event: eventType.WHITEBOARD_SHARE_FLOOR_GRANTED, meeting: this});
|
|
@@ -1987,11 +2059,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1987
2059
|
this,
|
|
1988
2060
|
{
|
|
1989
2061
|
file: 'meeting/index',
|
|
1990
|
-
function: 'setUpLocusInfoMeetingInfoListener'
|
|
2062
|
+
function: 'setUpLocusInfoMeetingInfoListener',
|
|
1991
2063
|
},
|
|
1992
2064
|
EVENT_TRIGGERS.MEETING_LOCKED,
|
|
1993
2065
|
{
|
|
1994
|
-
payload
|
|
2066
|
+
payload,
|
|
1995
2067
|
}
|
|
1996
2068
|
);
|
|
1997
2069
|
}
|
|
@@ -2002,11 +2074,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2002
2074
|
this,
|
|
2003
2075
|
{
|
|
2004
2076
|
file: 'meeting/index',
|
|
2005
|
-
function: 'setUpLocusInfoMeetingInfoListener'
|
|
2077
|
+
function: 'setUpLocusInfoMeetingInfoListener',
|
|
2006
2078
|
},
|
|
2007
2079
|
EVENT_TRIGGERS.MEETING_UNLOCKED,
|
|
2008
2080
|
{
|
|
2009
|
-
payload
|
|
2081
|
+
payload,
|
|
2010
2082
|
}
|
|
2011
2083
|
);
|
|
2012
2084
|
}
|
|
@@ -2014,7 +2086,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2014
2086
|
this.locusInfo.on(LOCUSINFO.EVENTS.MEETING_INFO_UPDATED, (payload) => {
|
|
2015
2087
|
if (payload && payload.info) {
|
|
2016
2088
|
const changed = this.inMeetingActions.set({
|
|
2017
|
-
canInviteNewParticipants: MeetingUtil.canInviteNewParticipants(
|
|
2089
|
+
canInviteNewParticipants: MeetingUtil.canInviteNewParticipants(
|
|
2090
|
+
payload.info.userDisplayHints
|
|
2091
|
+
),
|
|
2018
2092
|
canAdmitParticipant: MeetingUtil.canAdmitParticipant(payload.info.userDisplayHints),
|
|
2019
2093
|
canLock: MeetingUtil.canUserLock(payload.info.userDisplayHints),
|
|
2020
2094
|
canUnlock: MeetingUtil.canUserUnlock(payload.info.userDisplayHints),
|
|
@@ -2024,16 +2098,24 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2024
2098
|
canResumeRecording: MeetingUtil.canUserResume(payload.info.userDisplayHints),
|
|
2025
2099
|
canRaiseHand: MeetingUtil.canUserRaiseHand(payload.info.userDisplayHints),
|
|
2026
2100
|
canLowerAllHands: MeetingUtil.canUserLowerAllHands(payload.info.userDisplayHints),
|
|
2027
|
-
canLowerSomeoneElsesHand: MeetingUtil.canUserLowerSomeoneElsesHand(
|
|
2028
|
-
|
|
2101
|
+
canLowerSomeoneElsesHand: MeetingUtil.canUserLowerSomeoneElsesHand(
|
|
2102
|
+
payload.info.userDisplayHints
|
|
2103
|
+
),
|
|
2104
|
+
bothLeaveAndEndMeetingAvailable: MeetingUtil.bothLeaveAndEndMeetingAvailable(
|
|
2105
|
+
payload.info.userDisplayHints
|
|
2106
|
+
),
|
|
2029
2107
|
canEnableClosedCaption: MeetingUtil.canEnableClosedCaption(payload.info.userDisplayHints),
|
|
2030
2108
|
canStartTranscribing: MeetingUtil.canStartTranscribing(payload.info.userDisplayHints),
|
|
2031
2109
|
canStopTranscribing: MeetingUtil.canStopTranscribing(payload.info.userDisplayHints),
|
|
2032
2110
|
isClosedCaptionActive: MeetingUtil.isClosedCaptionActive(payload.info.userDisplayHints),
|
|
2033
2111
|
isWebexAssistantActive: MeetingUtil.isWebexAssistantActive(payload.info.userDisplayHints),
|
|
2034
2112
|
canViewCaptionPanel: MeetingUtil.canViewCaptionPanel(payload.info.userDisplayHints),
|
|
2035
|
-
isRealTimeTranslationEnabled: MeetingUtil.isRealTimeTranslationEnabled(
|
|
2036
|
-
|
|
2113
|
+
isRealTimeTranslationEnabled: MeetingUtil.isRealTimeTranslationEnabled(
|
|
2114
|
+
payload.info.userDisplayHints
|
|
2115
|
+
),
|
|
2116
|
+
canSelectSpokenLanguages: MeetingUtil.canSelectSpokenLanguages(
|
|
2117
|
+
payload.info.userDisplayHints
|
|
2118
|
+
),
|
|
2037
2119
|
waitingForOthersToJoin: MeetingUtil.waitingForOthersToJoin(payload.info.userDisplayHints),
|
|
2038
2120
|
});
|
|
2039
2121
|
|
|
@@ -2042,7 +2124,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2042
2124
|
this,
|
|
2043
2125
|
{
|
|
2044
2126
|
file: 'meeting/index',
|
|
2045
|
-
function: 'setUpLocusInfoMeetingInfoListener'
|
|
2127
|
+
function: 'setUpLocusInfoMeetingInfoListener',
|
|
2046
2128
|
},
|
|
2047
2129
|
EVENT_TRIGGERS.MEETING_ACTIONS_UPDATE,
|
|
2048
2130
|
this.inMeetingActions.get()
|
|
@@ -2082,7 +2164,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2082
2164
|
this,
|
|
2083
2165
|
{
|
|
2084
2166
|
file: 'meeting/index',
|
|
2085
|
-
function: 'setUpLocusEmbeddedAppsListener'
|
|
2167
|
+
function: 'setUpLocusEmbeddedAppsListener',
|
|
2086
2168
|
},
|
|
2087
2169
|
EVENT_TRIGGERS.MEETING_EMBEDDED_APPS_UPDATE,
|
|
2088
2170
|
embeddedApps
|
|
@@ -2105,11 +2187,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2105
2187
|
this,
|
|
2106
2188
|
{
|
|
2107
2189
|
file: 'meeting/index',
|
|
2108
|
-
function: 'setUpLocusInfoSelfListener'
|
|
2190
|
+
function: 'setUpLocusInfoSelfListener',
|
|
2109
2191
|
},
|
|
2110
2192
|
EVENT_TRIGGERS.MEETING_SELF_UNMUTED_BY_OTHERS,
|
|
2111
2193
|
{
|
|
2112
|
-
payload
|
|
2194
|
+
payload,
|
|
2113
2195
|
}
|
|
2114
2196
|
);
|
|
2115
2197
|
}
|
|
@@ -2122,17 +2204,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2122
2204
|
// with "mute on entry" server will send us remote mute even if we don't have media configured,
|
|
2123
2205
|
// so if being muted by others, always send the notification,
|
|
2124
2206
|
// but if being unmuted, only send it if we are also locally unmuted
|
|
2125
|
-
if (payload.muted ||
|
|
2207
|
+
if (payload.muted || !this.audio?.isMuted()) {
|
|
2126
2208
|
Trigger.trigger(
|
|
2127
2209
|
this,
|
|
2128
2210
|
{
|
|
2129
2211
|
file: 'meeting/index',
|
|
2130
|
-
function: 'setUpLocusInfoSelfListener'
|
|
2212
|
+
function: 'setUpLocusInfoSelfListener',
|
|
2131
2213
|
},
|
|
2132
|
-
payload.muted
|
|
2214
|
+
payload.muted
|
|
2215
|
+
? EVENT_TRIGGERS.MEETING_SELF_MUTED_BY_OTHERS
|
|
2216
|
+
: EVENT_TRIGGERS.MEETING_SELF_UNMUTED_BY_OTHERS,
|
|
2133
2217
|
{
|
|
2134
|
-
payload
|
|
2135
|
-
}
|
|
2218
|
+
payload,
|
|
2219
|
+
}
|
|
2136
2220
|
);
|
|
2137
2221
|
}
|
|
2138
2222
|
}
|
|
@@ -2142,11 +2226,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2142
2226
|
this,
|
|
2143
2227
|
{
|
|
2144
2228
|
file: 'meeting/index',
|
|
2145
|
-
function: 'setUpLocusInfoSelfListener'
|
|
2229
|
+
function: 'setUpLocusInfoSelfListener',
|
|
2146
2230
|
},
|
|
2147
2231
|
EVENT_TRIGGERS.MEETING_SELF_REQUESTED_TO_UNMUTE,
|
|
2148
2232
|
{
|
|
2149
|
-
payload
|
|
2233
|
+
payload,
|
|
2150
2234
|
}
|
|
2151
2235
|
);
|
|
2152
2236
|
});
|
|
@@ -2158,17 +2242,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2158
2242
|
this,
|
|
2159
2243
|
{
|
|
2160
2244
|
file: 'meeting/index',
|
|
2161
|
-
function: 'setUpLocusInfoSelfListener'
|
|
2245
|
+
function: 'setUpLocusInfoSelfListener',
|
|
2162
2246
|
},
|
|
2163
2247
|
EVENT_TRIGGERS.MEETING_SELF_LOBBY_WAITING,
|
|
2164
2248
|
{
|
|
2165
|
-
payload
|
|
2249
|
+
payload,
|
|
2166
2250
|
}
|
|
2167
2251
|
);
|
|
2168
2252
|
|
|
2169
2253
|
Metrics.postEvent({
|
|
2170
2254
|
event: eventType.LOBBY_ENTERED,
|
|
2171
|
-
meeting: this
|
|
2255
|
+
meeting: this,
|
|
2172
2256
|
});
|
|
2173
2257
|
}
|
|
2174
2258
|
});
|
|
@@ -2180,30 +2264,27 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2180
2264
|
this,
|
|
2181
2265
|
{
|
|
2182
2266
|
file: 'meeting/index',
|
|
2183
|
-
function: 'setUpLocusInfoSelfListener'
|
|
2267
|
+
function: 'setUpLocusInfoSelfListener',
|
|
2184
2268
|
},
|
|
2185
2269
|
EVENT_TRIGGERS.MEETING_SELF_GUEST_ADMITTED,
|
|
2186
2270
|
{
|
|
2187
|
-
payload
|
|
2271
|
+
payload,
|
|
2188
2272
|
}
|
|
2189
2273
|
);
|
|
2190
2274
|
|
|
2191
2275
|
Metrics.postEvent({
|
|
2192
2276
|
event: eventType.LOBBY_EXITED,
|
|
2193
|
-
meeting: this
|
|
2277
|
+
meeting: this,
|
|
2194
2278
|
});
|
|
2195
2279
|
}
|
|
2196
2280
|
});
|
|
2197
2281
|
|
|
2198
2282
|
// @ts-ignore - check if MEDIA_INACTIVITY exists
|
|
2199
2283
|
this.locusInfo.on(LOCUSINFO.EVENTS.MEDIA_INACTIVITY, () => {
|
|
2200
|
-
Metrics.sendBehavioralMetric(
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
locus_id: this.locusId
|
|
2205
|
-
}
|
|
2206
|
-
);
|
|
2284
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_MEDIA_INACTIVE, {
|
|
2285
|
+
correlation_id: this.correlationId,
|
|
2286
|
+
locus_id: this.locusId,
|
|
2287
|
+
});
|
|
2207
2288
|
this.reconnect();
|
|
2208
2289
|
});
|
|
2209
2290
|
|
|
@@ -2221,8 +2302,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2221
2302
|
sendShare: this.mediaProperties.mediaDirection?.sendShare,
|
|
2222
2303
|
receiveAudio: this.mediaProperties.mediaDirection?.receiveAudio,
|
|
2223
2304
|
receiveVideo: this.mediaProperties.mediaDirection?.receiveVideo,
|
|
2224
|
-
receiveShare: this.mediaProperties.mediaDirection?.receiveShare
|
|
2225
|
-
}
|
|
2305
|
+
receiveShare: this.mediaProperties.mediaDirection?.receiveShare,
|
|
2306
|
+
},
|
|
2226
2307
|
});
|
|
2227
2308
|
}
|
|
2228
2309
|
});
|
|
@@ -2232,11 +2313,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2232
2313
|
this,
|
|
2233
2314
|
{
|
|
2234
2315
|
file: 'meeting/index',
|
|
2235
|
-
function: 'setUpLocusInfoSelfListener'
|
|
2316
|
+
function: 'setUpLocusInfoSelfListener',
|
|
2236
2317
|
},
|
|
2237
2318
|
EVENT_TRIGGERS.MEETING_SELF_CANNOT_VIEW_PARTICIPANT_LIST,
|
|
2238
2319
|
{
|
|
2239
|
-
payload
|
|
2320
|
+
payload,
|
|
2240
2321
|
}
|
|
2241
2322
|
);
|
|
2242
2323
|
});
|
|
@@ -2246,11 +2327,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2246
2327
|
this,
|
|
2247
2328
|
{
|
|
2248
2329
|
file: 'meeting/index',
|
|
2249
|
-
function: 'setUpLocusInfoSelfListener'
|
|
2330
|
+
function: 'setUpLocusInfoSelfListener',
|
|
2250
2331
|
},
|
|
2251
2332
|
EVENT_TRIGGERS.MEETING_SELF_IS_SHARING_BLOCKED,
|
|
2252
2333
|
{
|
|
2253
|
-
payload
|
|
2334
|
+
payload,
|
|
2254
2335
|
}
|
|
2255
2336
|
);
|
|
2256
2337
|
});
|
|
@@ -2267,12 +2348,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2267
2348
|
this.meetingFiniteStateMachine.remote(payload);
|
|
2268
2349
|
|
|
2269
2350
|
if (payload.remoteDeclined) {
|
|
2270
|
-
this.leave({reason: payload.reason})
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2351
|
+
this.leave({reason: payload.reason})
|
|
2352
|
+
.then(() => {
|
|
2353
|
+
LoggerProxy.logger.info(
|
|
2354
|
+
'Meeting:index#setUpLocusInfoMeetingListener --> REMOTE_RESPONSE. Attempting to leave meeting.'
|
|
2355
|
+
);
|
|
2356
|
+
})
|
|
2357
|
+
.catch((error) => {
|
|
2358
|
+
// @ts-ignore
|
|
2359
|
+
LoggerProxy.logger.error(
|
|
2360
|
+
`Meeting:index#setUpLocusInfoMeetingListener --> REMOTE_RESPONSE. Issue with leave for meeting, meeting still in collection: ${this.meeting}, error: ${error}`
|
|
2361
|
+
);
|
|
2362
|
+
});
|
|
2276
2363
|
}
|
|
2277
2364
|
});
|
|
2278
2365
|
this.locusInfo.on(EVENTS.DESTROY_MEETING, (payload) => {
|
|
@@ -2296,27 +2383,35 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2296
2383
|
if (payload.shouldLeave) {
|
|
2297
2384
|
// TODO: We should do cleaning of meeting object if the shouldLeave: false because there might be meeting object which we are not cleaning
|
|
2298
2385
|
|
|
2299
|
-
this.leave({reason: payload.reason})
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2386
|
+
this.leave({reason: payload.reason})
|
|
2387
|
+
.then(() => {
|
|
2388
|
+
LoggerProxy.logger.warn(
|
|
2389
|
+
'Meeting:index#setUpLocusInfoMeetingListener --> DESTROY_MEETING. The meeting has been left, but has not been destroyed, you should see a later event for leave.'
|
|
2390
|
+
);
|
|
2391
|
+
})
|
|
2392
|
+
.catch((error) => {
|
|
2393
|
+
// @ts-ignore
|
|
2394
|
+
LoggerProxy.logger.error(
|
|
2395
|
+
`Meeting:index#setUpLocusInfoMeetingListener --> DESTROY_MEETING. Issue with leave for meeting, meeting still in collection: ${this.meeting}, error: ${error}`
|
|
2396
|
+
);
|
|
2397
|
+
});
|
|
2398
|
+
} else {
|
|
2399
|
+
LoggerProxy.logger.info(
|
|
2400
|
+
'Meeting:index#setUpLocusInfoMeetingListener --> MEETING_REMOVED_REASON',
|
|
2401
|
+
payload.reason
|
|
2402
|
+
);
|
|
2308
2403
|
|
|
2309
2404
|
MeetingUtil.cleanUp(this);
|
|
2310
2405
|
Trigger.trigger(
|
|
2311
2406
|
this,
|
|
2312
2407
|
{
|
|
2313
2408
|
file: 'meeting/index',
|
|
2314
|
-
function: 'setUpLocusInfoMeetingListener'
|
|
2409
|
+
function: 'setUpLocusInfoMeetingListener',
|
|
2315
2410
|
},
|
|
2316
2411
|
EVENTS.DESTROY_MEETING,
|
|
2317
2412
|
{
|
|
2318
2413
|
reason: payload.reason,
|
|
2319
|
-
meetingId: this.id
|
|
2414
|
+
meetingId: this.id,
|
|
2320
2415
|
}
|
|
2321
2416
|
);
|
|
2322
2417
|
}
|
|
@@ -2359,7 +2454,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2359
2454
|
email: string;
|
|
2360
2455
|
phoneNumber: string;
|
|
2361
2456
|
},
|
|
2362
|
-
alertIfActive
|
|
2457
|
+
alertIfActive = true
|
|
2363
2458
|
) {
|
|
2364
2459
|
return this.members.addMember(invitee, alertIfActive);
|
|
2365
2460
|
}
|
|
@@ -2372,7 +2467,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2372
2467
|
* @public
|
|
2373
2468
|
* @memberof Meeting
|
|
2374
2469
|
*/
|
|
2375
|
-
public cancelPhoneInvite(invitee: {
|
|
2470
|
+
public cancelPhoneInvite(invitee: {phoneNumber: string}) {
|
|
2376
2471
|
return this.members.cancelPhoneInvite(invitee);
|
|
2377
2472
|
}
|
|
2378
2473
|
|
|
@@ -2406,7 +2501,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2406
2501
|
* @public
|
|
2407
2502
|
* @memberof Meeting
|
|
2408
2503
|
*/
|
|
2409
|
-
public mute(memberId: string, mute
|
|
2504
|
+
public mute(memberId: string, mute = true) {
|
|
2410
2505
|
return this.members.muteMember(memberId, mute);
|
|
2411
2506
|
}
|
|
2412
2507
|
|
|
@@ -2418,7 +2513,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2418
2513
|
* @public
|
|
2419
2514
|
* @memberof Meeting
|
|
2420
2515
|
*/
|
|
2421
|
-
public transfer(memberId: string, moderator
|
|
2516
|
+
public transfer(memberId: string, moderator = true) {
|
|
2422
2517
|
return this.members.transferHostToMember(memberId, moderator);
|
|
2423
2518
|
}
|
|
2424
2519
|
|
|
@@ -2506,14 +2601,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2506
2601
|
* @memberof Meeting
|
|
2507
2602
|
*/
|
|
2508
2603
|
parseMeetingInfo(
|
|
2509
|
-
meetingInfo:
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2604
|
+
meetingInfo:
|
|
2605
|
+
| {
|
|
2606
|
+
body: {
|
|
2607
|
+
conversationUrl: string;
|
|
2608
|
+
locusUrl: string;
|
|
2609
|
+
sipUri: string;
|
|
2610
|
+
owner: object;
|
|
2611
|
+
};
|
|
2612
|
+
}
|
|
2613
|
+
| any,
|
|
2517
2614
|
destination: object | string | null = null
|
|
2518
2615
|
) {
|
|
2519
2616
|
const webexMeetingInfo = meetingInfo?.body;
|
|
@@ -2526,17 +2623,32 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2526
2623
|
}
|
|
2527
2624
|
|
|
2528
2625
|
// MeetingInfo will be undefined for 1:1 calls
|
|
2529
|
-
if (
|
|
2530
|
-
|
|
2626
|
+
if (
|
|
2627
|
+
locusMeetingObject ||
|
|
2628
|
+
(webexMeetingInfo && !(meetingInfo?.errors && meetingInfo?.errors.length > 0))
|
|
2629
|
+
) {
|
|
2630
|
+
this.conversationUrl =
|
|
2631
|
+
locusMeetingObject?.conversationUrl ||
|
|
2632
|
+
webexMeetingInfo?.conversationUrl ||
|
|
2633
|
+
this.conversationUrl;
|
|
2531
2634
|
this.locusUrl = locusMeetingObject?.url || webexMeetingInfo?.locusUrl || this.locusUrl;
|
|
2532
2635
|
// @ts-ignore - config coming from registerPlugin
|
|
2533
|
-
this.setSipUri(
|
|
2636
|
+
this.setSipUri(
|
|
2637
|
+
this.config.experimental.enableUnifiedMeetings
|
|
2638
|
+
? locusMeetingObject?.info.sipUri || webexMeetingInfo?.sipUrl
|
|
2639
|
+
: locusMeetingObject?.info.sipUri || webexMeetingInfo?.sipMeetingUri || this.sipUri
|
|
2640
|
+
);
|
|
2534
2641
|
// @ts-ignore - config coming from registerPlugin
|
|
2535
2642
|
if (this.config.experimental.enableUnifiedMeetings) {
|
|
2536
|
-
this.meetingNumber =
|
|
2643
|
+
this.meetingNumber =
|
|
2644
|
+
locusMeetingObject?.info.webExMeetingId || webexMeetingInfo?.meetingNumber;
|
|
2537
2645
|
this.meetingJoinUrl = webexMeetingInfo?.meetingJoinUrl;
|
|
2538
2646
|
}
|
|
2539
|
-
this.owner =
|
|
2647
|
+
this.owner =
|
|
2648
|
+
locusMeetingObject?.info.owner ||
|
|
2649
|
+
webexMeetingInfo?.owner ||
|
|
2650
|
+
webexMeetingInfo?.hostId ||
|
|
2651
|
+
this.owner;
|
|
2540
2652
|
this.permissionToken = webexMeetingInfo?.permissionToken;
|
|
2541
2653
|
}
|
|
2542
2654
|
}
|
|
@@ -2551,7 +2663,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2551
2663
|
* @private
|
|
2552
2664
|
* @memberof Meeting
|
|
2553
2665
|
*/
|
|
2554
|
-
private parseLocus(locus: {
|
|
2666
|
+
private parseLocus(locus: {url: string; participants: Array<any>; self: object}) {
|
|
2555
2667
|
if (locus) {
|
|
2556
2668
|
this.locusUrl = locus.url;
|
|
2557
2669
|
// TODO: move this to parse participants module
|
|
@@ -2596,13 +2708,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2596
2708
|
* @private
|
|
2597
2709
|
* @memberof Meeting
|
|
2598
2710
|
*/
|
|
2599
|
-
private setLocus(
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2711
|
+
private setLocus(
|
|
2712
|
+
locus:
|
|
2713
|
+
| {
|
|
2714
|
+
mediaConnections: Array<any>;
|
|
2715
|
+
locusUrl: string;
|
|
2716
|
+
locusId: string;
|
|
2717
|
+
mediaId: string;
|
|
2718
|
+
host: object;
|
|
2719
|
+
}
|
|
2720
|
+
| any
|
|
2721
|
+
) {
|
|
2606
2722
|
const mtgLocus: any = locus.locus || locus;
|
|
2607
2723
|
|
|
2608
2724
|
// LocusInfo object saves the locus object
|
|
@@ -2623,13 +2739,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2623
2739
|
* @public
|
|
2624
2740
|
* @memberof Meeting
|
|
2625
2741
|
*/
|
|
2626
|
-
public uploadLogs(options: object = {
|
|
2627
|
-
Trigger.trigger(
|
|
2628
|
-
this,
|
|
2629
|
-
options,
|
|
2630
|
-
EVENTS.REQUEST_UPLOAD_LOGS,
|
|
2631
|
-
this
|
|
2632
|
-
);
|
|
2742
|
+
public uploadLogs(options: object = {file: 'meeting/index', function: 'uploadLogs'}) {
|
|
2743
|
+
Trigger.trigger(this, options, EVENTS.REQUEST_UPLOAD_LOGS, this);
|
|
2633
2744
|
}
|
|
2634
2745
|
|
|
2635
2746
|
/**
|
|
@@ -2641,7 +2752,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2641
2752
|
* @deprecated after v1.89.3
|
|
2642
2753
|
*/
|
|
2643
2754
|
public unsetRemoteStream() {
|
|
2644
|
-
LoggerProxy.logger.warn(
|
|
2755
|
+
LoggerProxy.logger.warn(
|
|
2756
|
+
'Meeting:index#unsetRemoteStream --> [DEPRECATION WARNING]: unsetRemoteStream has been deprecated after v1.89.3'
|
|
2757
|
+
);
|
|
2645
2758
|
this.mediaProperties.unsetRemoteMedia();
|
|
2646
2759
|
}
|
|
2647
2760
|
|
|
@@ -2662,7 +2775,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2662
2775
|
* @deprecated after v1.89.3
|
|
2663
2776
|
*/
|
|
2664
2777
|
public closeRemoteStream() {
|
|
2665
|
-
LoggerProxy.logger.warn(
|
|
2778
|
+
LoggerProxy.logger.warn(
|
|
2779
|
+
'Meeting:index#closeRemoteStream --> [DEPRECATION WARNING]: closeRemoteStream has been deprecated after v1.89.3'
|
|
2780
|
+
);
|
|
2666
2781
|
this.closeRemoteTracks();
|
|
2667
2782
|
}
|
|
2668
2783
|
|
|
@@ -2673,11 +2788,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2673
2788
|
* @memberof Meeting
|
|
2674
2789
|
*/
|
|
2675
2790
|
closeRemoteTracks() {
|
|
2676
|
-
const {
|
|
2677
|
-
remoteAudioTrack,
|
|
2678
|
-
remoteVideoTrack,
|
|
2679
|
-
remoteShare
|
|
2680
|
-
} = this.mediaProperties;
|
|
2791
|
+
const {remoteAudioTrack, remoteVideoTrack, remoteShare} = this.mediaProperties;
|
|
2681
2792
|
|
|
2682
2793
|
/**
|
|
2683
2794
|
* Triggers an event to the developer
|
|
@@ -2685,16 +2796,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2685
2796
|
* @returns {void}
|
|
2686
2797
|
* @inner
|
|
2687
2798
|
*/
|
|
2799
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
2688
2800
|
const triggerMediaStoppedEvent = (mediaType: string) => {
|
|
2689
2801
|
Trigger.trigger(
|
|
2690
2802
|
this,
|
|
2691
2803
|
{
|
|
2692
2804
|
file: 'meeting/index',
|
|
2693
|
-
function: 'closeRemoteTracks'
|
|
2805
|
+
function: 'closeRemoteTracks',
|
|
2694
2806
|
},
|
|
2695
2807
|
EVENT_TRIGGERS.MEDIA_STOPPED,
|
|
2696
2808
|
{
|
|
2697
|
-
type: mediaType
|
|
2809
|
+
type: mediaType,
|
|
2698
2810
|
}
|
|
2699
2811
|
);
|
|
2700
2812
|
};
|
|
@@ -2708,24 +2820,24 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2708
2820
|
*/
|
|
2709
2821
|
// eslint-disable-next-line arrow-body-style
|
|
2710
2822
|
const stopTrack = (track: MediaStreamTrack, type: string) => {
|
|
2711
|
-
return Media.stopTracks(track)
|
|
2712
|
-
.
|
|
2713
|
-
|
|
2714
|
-
const isWrongReadyState = track && !isTrackStopped;
|
|
2823
|
+
return Media.stopTracks(track).then(() => {
|
|
2824
|
+
const isTrackStopped = track && track.readyState === ENDED;
|
|
2825
|
+
const isWrongReadyState = track && !isTrackStopped;
|
|
2715
2826
|
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
}
|
|
2827
|
+
if (isTrackStopped) {
|
|
2828
|
+
triggerMediaStoppedEvent(type);
|
|
2829
|
+
} else if (isWrongReadyState) {
|
|
2830
|
+
LoggerProxy.logger.warn(
|
|
2831
|
+
`Meeting:index#closeRemoteTracks --> Error: MediaStreamTrack.readyState is ${track.readyState} for ${type}`
|
|
2832
|
+
);
|
|
2833
|
+
}
|
|
2834
|
+
});
|
|
2723
2835
|
};
|
|
2724
2836
|
|
|
2725
2837
|
return Promise.all([
|
|
2726
2838
|
stopTrack(remoteAudioTrack, EVENT_TYPES.REMOTE_AUDIO),
|
|
2727
2839
|
stopTrack(remoteVideoTrack, EVENT_TYPES.REMOTE_VIDEO),
|
|
2728
|
-
stopTrack(remoteShare, EVENT_TYPES.REMOTE_SHARE)
|
|
2840
|
+
stopTrack(remoteShare, EVENT_TYPES.REMOTE_SHARE),
|
|
2729
2841
|
]);
|
|
2730
2842
|
}
|
|
2731
2843
|
|
|
@@ -2740,12 +2852,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2740
2852
|
this,
|
|
2741
2853
|
{
|
|
2742
2854
|
file: 'meeting/index',
|
|
2743
|
-
function: 'setLocalTracks'
|
|
2855
|
+
function: 'setLocalTracks',
|
|
2744
2856
|
},
|
|
2745
2857
|
EVENT_TRIGGERS.MEDIA_READY,
|
|
2746
2858
|
{
|
|
2747
2859
|
type: EVENT_TYPES.LOCAL,
|
|
2748
|
-
stream: MediaUtil.createMediaStream([
|
|
2860
|
+
stream: MediaUtil.createMediaStream([
|
|
2861
|
+
this.mediaProperties.audioTrack,
|
|
2862
|
+
this.mediaProperties.videoTrack,
|
|
2863
|
+
]),
|
|
2749
2864
|
}
|
|
2750
2865
|
);
|
|
2751
2866
|
}
|
|
@@ -2758,16 +2873,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2758
2873
|
* @private
|
|
2759
2874
|
* @memberof Meeting
|
|
2760
2875
|
*/
|
|
2761
|
-
private setLocalAudioTrack(audioTrack: MediaStreamTrack, emitEvent
|
|
2876
|
+
private setLocalAudioTrack(audioTrack: MediaStreamTrack, emitEvent = true) {
|
|
2762
2877
|
if (audioTrack) {
|
|
2763
2878
|
const settings = audioTrack.getSettings();
|
|
2764
2879
|
|
|
2765
2880
|
this.mediaProperties.setMediaSettings('audio', {
|
|
2766
2881
|
echoCancellation: settings.echoCancellation,
|
|
2767
|
-
noiseSuppression: settings.noiseSuppression
|
|
2882
|
+
noiseSuppression: settings.noiseSuppression,
|
|
2768
2883
|
});
|
|
2769
2884
|
|
|
2770
|
-
LoggerProxy.logger.log(
|
|
2885
|
+
LoggerProxy.logger.log(
|
|
2886
|
+
'Meeting:index#setLocalAudioTrack --> Audio settings.',
|
|
2887
|
+
JSON.stringify(this.mediaProperties.mediaSettings.audio)
|
|
2888
|
+
);
|
|
2771
2889
|
this.mediaProperties.setLocalAudioTrack(audioTrack);
|
|
2772
2890
|
if (this.audio) this.audio.applyClientStateLocally(this);
|
|
2773
2891
|
}
|
|
@@ -2785,16 +2903,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2785
2903
|
* @private
|
|
2786
2904
|
* @memberof Meeting
|
|
2787
2905
|
*/
|
|
2788
|
-
private setLocalVideoTrack(videoTrack: MediaStreamTrack, emitEvent
|
|
2906
|
+
private setLocalVideoTrack(videoTrack: MediaStreamTrack, emitEvent = true) {
|
|
2789
2907
|
if (videoTrack) {
|
|
2790
|
-
const {
|
|
2791
|
-
aspectRatio, frameRate, height, width, deviceId
|
|
2792
|
-
} = videoTrack.getSettings();
|
|
2908
|
+
const {aspectRatio, frameRate, height, width, deviceId} = videoTrack.getSettings();
|
|
2793
2909
|
|
|
2794
2910
|
const {localQualityLevel} = this.mediaProperties;
|
|
2795
2911
|
|
|
2796
2912
|
if (Number(localQualityLevel.slice(0, -1)) > height) {
|
|
2797
|
-
LoggerProxy.logger
|
|
2913
|
+
LoggerProxy.logger
|
|
2914
|
+
.warn(`Meeting:index#setLocalVideoTrack --> Local video quality of ${localQualityLevel} not supported,
|
|
2798
2915
|
downscaling to highest possible resolution of ${height}p`);
|
|
2799
2916
|
|
|
2800
2917
|
this.mediaProperties.setLocalQualityLevel(`${height}p`);
|
|
@@ -2804,13 +2921,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2804
2921
|
if (this.video) this.video.applyClientStateLocally(this);
|
|
2805
2922
|
|
|
2806
2923
|
this.mediaProperties.setMediaSettings('video', {
|
|
2807
|
-
aspectRatio,
|
|
2924
|
+
aspectRatio,
|
|
2925
|
+
frameRate,
|
|
2926
|
+
height,
|
|
2927
|
+
width,
|
|
2808
2928
|
});
|
|
2809
2929
|
// store and save the selected video input device
|
|
2810
2930
|
if (deviceId) {
|
|
2811
2931
|
this.mediaProperties.setVideoDeviceId(deviceId);
|
|
2812
2932
|
}
|
|
2813
|
-
LoggerProxy.logger.log(
|
|
2933
|
+
LoggerProxy.logger.log(
|
|
2934
|
+
'Meeting:index#setLocalVideoTrack --> Video settings.',
|
|
2935
|
+
JSON.stringify(this.mediaProperties.mediaSettings.video)
|
|
2936
|
+
);
|
|
2814
2937
|
}
|
|
2815
2938
|
|
|
2816
2939
|
if (emitEvent) {
|
|
@@ -2858,9 +2981,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2858
2981
|
height: settings.height,
|
|
2859
2982
|
width: settings.width,
|
|
2860
2983
|
displaySurface: settings.displaySurface,
|
|
2861
|
-
cursor: settings.cursor
|
|
2984
|
+
cursor: settings.cursor,
|
|
2862
2985
|
});
|
|
2863
|
-
LoggerProxy.logger.log(
|
|
2986
|
+
LoggerProxy.logger.log(
|
|
2987
|
+
'Meeting:index#setLocalShareTrack --> Screen settings.',
|
|
2988
|
+
JSON.stringify(this.mediaProperties.mediaSettings.screen)
|
|
2989
|
+
);
|
|
2864
2990
|
}
|
|
2865
2991
|
|
|
2866
2992
|
contentTracks.onended = () => this.handleShareTrackEnded(localShare);
|
|
@@ -2869,12 +2995,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2869
2995
|
this,
|
|
2870
2996
|
{
|
|
2871
2997
|
file: 'meeting/index',
|
|
2872
|
-
function: 'setLocalShareTrack'
|
|
2998
|
+
function: 'setLocalShareTrack',
|
|
2873
2999
|
},
|
|
2874
3000
|
EVENT_TRIGGERS.MEDIA_READY,
|
|
2875
3001
|
{
|
|
2876
3002
|
type: EVENT_TYPES.LOCAL_SHARE,
|
|
2877
|
-
stream: localShare
|
|
3003
|
+
stream: localShare,
|
|
2878
3004
|
}
|
|
2879
3005
|
);
|
|
2880
3006
|
}
|
|
@@ -2902,15 +3028,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2902
3028
|
this,
|
|
2903
3029
|
{
|
|
2904
3030
|
file: 'meeting/index',
|
|
2905
|
-
function: 'closeLocalStream'
|
|
3031
|
+
function: 'closeLocalStream',
|
|
2906
3032
|
},
|
|
2907
|
-
EVENT_TRIGGERS.MEDIA_STOPPED,
|
|
2908
|
-
|
|
3033
|
+
EVENT_TRIGGERS.MEDIA_STOPPED,
|
|
3034
|
+
{
|
|
3035
|
+
type: EVENT_TYPES.LOCAL,
|
|
2909
3036
|
}
|
|
2910
3037
|
);
|
|
2911
|
-
}
|
|
2912
|
-
|
|
2913
|
-
|
|
3038
|
+
} else if (audioTrack || videoTrack) {
|
|
3039
|
+
LoggerProxy.logger.warn(
|
|
3040
|
+
'Meeting:index#closeLocalStream --> Warning: track might already been ended or unavaliable.'
|
|
3041
|
+
);
|
|
2914
3042
|
}
|
|
2915
3043
|
});
|
|
2916
3044
|
}
|
|
@@ -2931,16 +3059,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2931
3059
|
this,
|
|
2932
3060
|
{
|
|
2933
3061
|
file: 'meeting/index',
|
|
2934
|
-
function: 'closeLocalShare'
|
|
3062
|
+
function: 'closeLocalShare',
|
|
2935
3063
|
},
|
|
2936
|
-
EVENT_TRIGGERS.MEDIA_STOPPED,
|
|
2937
|
-
|
|
3064
|
+
EVENT_TRIGGERS.MEDIA_STOPPED,
|
|
3065
|
+
{
|
|
3066
|
+
type: EVENT_TYPES.LOCAL_SHARE,
|
|
2938
3067
|
}
|
|
2939
3068
|
);
|
|
2940
|
-
}
|
|
2941
|
-
else if (track) {
|
|
3069
|
+
} else if (track) {
|
|
2942
3070
|
// Track exists but with wrong readyState
|
|
2943
|
-
LoggerProxy.logger.warn(
|
|
3071
|
+
LoggerProxy.logger.warn(
|
|
3072
|
+
`Meeting:index#closeLocalShare --> Error: MediaStreamTrack.readyState is ${track.readyState} for localShare`
|
|
3073
|
+
);
|
|
2944
3074
|
}
|
|
2945
3075
|
});
|
|
2946
3076
|
}
|
|
@@ -2982,14 +3112,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2982
3112
|
if (!this.hasWebsocketConnected) {
|
|
2983
3113
|
Metrics.postEvent({
|
|
2984
3114
|
event: eventType.MERCURY_CONNECTION_RESTORED,
|
|
2985
|
-
meeting: this
|
|
3115
|
+
meeting: this,
|
|
3116
|
+
});
|
|
3117
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_RESTORED, {
|
|
3118
|
+
correlation_id: this.correlationId,
|
|
2986
3119
|
});
|
|
2987
|
-
Metrics.sendBehavioralMetric(
|
|
2988
|
-
BEHAVIORAL_METRICS.MERCURY_CONNECTION_RESTORED,
|
|
2989
|
-
{
|
|
2990
|
-
correlation_id: this.correlationId
|
|
2991
|
-
}
|
|
2992
|
-
);
|
|
2993
3120
|
}
|
|
2994
3121
|
this.hasWebsocketConnected = true;
|
|
2995
3122
|
});
|
|
@@ -2999,14 +3126,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2999
3126
|
LoggerProxy.logger.error('Meeting:index#setMercuryListener --> Web socket offline');
|
|
3000
3127
|
Metrics.postEvent({
|
|
3001
3128
|
event: eventType.MERCURY_CONNECTION_LOST,
|
|
3002
|
-
meeting: this
|
|
3129
|
+
meeting: this,
|
|
3130
|
+
});
|
|
3131
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MERCURY_CONNECTION_FAILURE, {
|
|
3132
|
+
correlation_id: this.correlationId,
|
|
3003
3133
|
});
|
|
3004
|
-
Metrics.sendBehavioralMetric(
|
|
3005
|
-
BEHAVIORAL_METRICS.MERCURY_CONNECTION_FAILURE,
|
|
3006
|
-
{
|
|
3007
|
-
correlation_id: this.correlationId
|
|
3008
|
-
}
|
|
3009
|
-
);
|
|
3010
3134
|
});
|
|
3011
3135
|
}
|
|
3012
3136
|
|
|
@@ -3025,7 +3149,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3025
3149
|
this.remoteMediaManager = null;
|
|
3026
3150
|
}
|
|
3027
3151
|
|
|
3028
|
-
Object.values(this.mediaRequestManagers).forEach((mediaRequestManager) =>
|
|
3152
|
+
Object.values(this.mediaRequestManagers).forEach((mediaRequestManager) =>
|
|
3153
|
+
mediaRequestManager.reset()
|
|
3154
|
+
);
|
|
3029
3155
|
|
|
3030
3156
|
this.receiveSlotManager.reset();
|
|
3031
3157
|
this.mediaProperties.webrtcMediaConnection.close();
|
|
@@ -3085,32 +3211,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3085
3211
|
const LOG_HEADER = 'Meeting:index#muteAudio -->';
|
|
3086
3212
|
|
|
3087
3213
|
// First, stop sending the local audio media
|
|
3088
|
-
return logRequest(
|
|
3089
|
-
.
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3214
|
+
return logRequest(
|
|
3215
|
+
this.audio
|
|
3216
|
+
.handleClientRequest(this, true)
|
|
3217
|
+
.then(() => {
|
|
3218
|
+
MeetingUtil.handleAudioLogging(this.mediaProperties.audioTrack);
|
|
3219
|
+
Metrics.postEvent({
|
|
3220
|
+
event: eventType.MUTED,
|
|
3221
|
+
meeting: this,
|
|
3222
|
+
data: {trigger: trigger.USER_INTERACTION, mediaType: mediaType.AUDIO},
|
|
3223
|
+
});
|
|
3224
|
+
})
|
|
3225
|
+
.catch((error) => {
|
|
3226
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MUTE_AUDIO_FAILURE, {
|
|
3100
3227
|
correlation_id: this.correlationId,
|
|
3101
3228
|
locus_id: this.locusUrl.split('/').pop(),
|
|
3102
3229
|
reason: error.message,
|
|
3103
|
-
stack: error.stack
|
|
3104
|
-
}
|
|
3105
|
-
);
|
|
3230
|
+
stack: error.stack,
|
|
3231
|
+
});
|
|
3106
3232
|
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3233
|
+
throw error;
|
|
3234
|
+
}),
|
|
3235
|
+
{
|
|
3236
|
+
header: `${LOG_HEADER} muting audio`,
|
|
3237
|
+
success: `${LOG_HEADER} muted audio successfully`,
|
|
3238
|
+
failure: `${LOG_HEADER} muting audio failed, `,
|
|
3239
|
+
}
|
|
3240
|
+
);
|
|
3114
3241
|
}
|
|
3115
3242
|
|
|
3116
3243
|
/**
|
|
@@ -3137,32 +3264,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3137
3264
|
const LOG_HEADER = 'Meeting:index#unmuteAudio -->';
|
|
3138
3265
|
|
|
3139
3266
|
// First, send the control to unmute the participant on the server
|
|
3140
|
-
return logRequest(
|
|
3141
|
-
.
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3267
|
+
return logRequest(
|
|
3268
|
+
this.audio
|
|
3269
|
+
.handleClientRequest(this, false)
|
|
3270
|
+
.then(() => {
|
|
3271
|
+
MeetingUtil.handleAudioLogging(this.mediaProperties.audioTrack);
|
|
3272
|
+
Metrics.postEvent({
|
|
3273
|
+
event: eventType.UNMUTED,
|
|
3274
|
+
meeting: this,
|
|
3275
|
+
data: {trigger: trigger.USER_INTERACTION, mediaType: mediaType.AUDIO},
|
|
3276
|
+
});
|
|
3277
|
+
})
|
|
3278
|
+
.catch((error) => {
|
|
3279
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.UNMUTE_AUDIO_FAILURE, {
|
|
3152
3280
|
correlation_id: this.correlationId,
|
|
3153
3281
|
locus_id: this.locusUrl.split('/').pop(),
|
|
3154
3282
|
reason: error.message,
|
|
3155
|
-
stack: error.stack
|
|
3156
|
-
}
|
|
3157
|
-
);
|
|
3283
|
+
stack: error.stack,
|
|
3284
|
+
});
|
|
3158
3285
|
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3286
|
+
throw error;
|
|
3287
|
+
}),
|
|
3288
|
+
{
|
|
3289
|
+
header: `${LOG_HEADER} unmuting audio`,
|
|
3290
|
+
success: `${LOG_HEADER} unmuted audio successfully`,
|
|
3291
|
+
failure: `${LOG_HEADER} unmuting audio failed, `,
|
|
3292
|
+
}
|
|
3293
|
+
);
|
|
3166
3294
|
}
|
|
3167
3295
|
|
|
3168
3296
|
/**
|
|
@@ -3188,32 +3316,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3188
3316
|
|
|
3189
3317
|
const LOG_HEADER = 'Meeting:index#muteVideo -->';
|
|
3190
3318
|
|
|
3191
|
-
return logRequest(
|
|
3192
|
-
.
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3319
|
+
return logRequest(
|
|
3320
|
+
this.video
|
|
3321
|
+
.handleClientRequest(this, true)
|
|
3322
|
+
.then(() => {
|
|
3323
|
+
MeetingUtil.handleVideoLogging(this.mediaProperties.videoTrack);
|
|
3324
|
+
Metrics.postEvent({
|
|
3325
|
+
event: eventType.MUTED,
|
|
3326
|
+
meeting: this,
|
|
3327
|
+
data: {trigger: trigger.USER_INTERACTION, mediaType: mediaType.VIDEO},
|
|
3328
|
+
});
|
|
3329
|
+
})
|
|
3330
|
+
.catch((error) => {
|
|
3331
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MUTE_VIDEO_FAILURE, {
|
|
3203
3332
|
correlation_id: this.correlationId,
|
|
3204
3333
|
locus_id: this.locusUrl.split('/').pop(),
|
|
3205
3334
|
reason: error.message,
|
|
3206
|
-
stack: error.stack
|
|
3207
|
-
}
|
|
3208
|
-
);
|
|
3335
|
+
stack: error.stack,
|
|
3336
|
+
});
|
|
3209
3337
|
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3338
|
+
throw error;
|
|
3339
|
+
}),
|
|
3340
|
+
{
|
|
3341
|
+
header: `${LOG_HEADER} muting video`,
|
|
3342
|
+
success: `${LOG_HEADER} muted video successfully`,
|
|
3343
|
+
failure: `${LOG_HEADER} muting video failed, `,
|
|
3344
|
+
}
|
|
3345
|
+
);
|
|
3217
3346
|
}
|
|
3218
3347
|
|
|
3219
3348
|
/**
|
|
@@ -3239,32 +3368,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3239
3368
|
|
|
3240
3369
|
const LOG_HEADER = 'Meeting:index#unmuteVideo -->';
|
|
3241
3370
|
|
|
3242
|
-
return logRequest(
|
|
3243
|
-
.
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3371
|
+
return logRequest(
|
|
3372
|
+
this.video
|
|
3373
|
+
.handleClientRequest(this, false)
|
|
3374
|
+
.then(() => {
|
|
3375
|
+
MeetingUtil.handleVideoLogging(this.mediaProperties.videoTrack);
|
|
3376
|
+
Metrics.postEvent({
|
|
3377
|
+
event: eventType.UNMUTED,
|
|
3378
|
+
meeting: this,
|
|
3379
|
+
data: {trigger: trigger.USER_INTERACTION, mediaType: mediaType.VIDEO},
|
|
3380
|
+
});
|
|
3381
|
+
})
|
|
3382
|
+
.catch((error) => {
|
|
3383
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.UNMUTE_VIDEO_FAILURE, {
|
|
3254
3384
|
correlation_id: this.correlationId,
|
|
3255
3385
|
locus_id: this.locusUrl.split('/').pop(),
|
|
3256
3386
|
reason: error.message,
|
|
3257
|
-
stack: error.stack
|
|
3258
|
-
}
|
|
3259
|
-
);
|
|
3387
|
+
stack: error.stack,
|
|
3388
|
+
});
|
|
3260
3389
|
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3390
|
+
throw error;
|
|
3391
|
+
}),
|
|
3392
|
+
{
|
|
3393
|
+
header: `${LOG_HEADER} unmuting video`,
|
|
3394
|
+
success: `${LOG_HEADER} unmuted video successfully`,
|
|
3395
|
+
failure: `${LOG_HEADER} unmuting video failed, `,
|
|
3396
|
+
}
|
|
3397
|
+
);
|
|
3268
3398
|
}
|
|
3269
3399
|
|
|
3270
3400
|
/**
|
|
@@ -3308,12 +3438,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3308
3438
|
this.addMedia({
|
|
3309
3439
|
mediaSettings,
|
|
3310
3440
|
localShare,
|
|
3311
|
-
localStream
|
|
3441
|
+
localStream,
|
|
3312
3442
|
}).then((mediaResponse) => ({
|
|
3313
3443
|
join: joinResponse,
|
|
3314
3444
|
media: mediaResponse,
|
|
3315
|
-
local: [localStream, localShare]
|
|
3316
|
-
}))
|
|
3445
|
+
local: [localStream, localShare],
|
|
3446
|
+
}))
|
|
3447
|
+
)
|
|
3448
|
+
)
|
|
3317
3449
|
.catch((error) => {
|
|
3318
3450
|
LoggerProxy.logger.error('Meeting:index#joinWithMedia --> ', error);
|
|
3319
3451
|
|
|
@@ -3323,10 +3455,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3323
3455
|
correlation_id: this.correlationId,
|
|
3324
3456
|
locus_id: this.locusUrl.split('/').pop(),
|
|
3325
3457
|
reason: error.message,
|
|
3326
|
-
stack: error.stack
|
|
3458
|
+
stack: error.stack,
|
|
3327
3459
|
},
|
|
3328
3460
|
{
|
|
3329
|
-
type: error.name
|
|
3461
|
+
type: error.name,
|
|
3330
3462
|
}
|
|
3331
3463
|
);
|
|
3332
3464
|
|
|
@@ -3343,28 +3475,34 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3343
3475
|
* @memberof Meeting
|
|
3344
3476
|
*/
|
|
3345
3477
|
public reconnect(options?: object) {
|
|
3346
|
-
LoggerProxy.logger.log(
|
|
3478
|
+
LoggerProxy.logger.log(
|
|
3479
|
+
`Meeting:index#reconnect --> attempting to reconnect meeting ${this.id}`
|
|
3480
|
+
);
|
|
3347
3481
|
|
|
3348
3482
|
if (!this.reconnectionManager || !this.reconnectionManager.reconnect) {
|
|
3349
|
-
return Promise.reject(
|
|
3483
|
+
return Promise.reject(
|
|
3484
|
+
new ParameterError('Cannot reconnect, ReconnectionManager must first be defined.')
|
|
3485
|
+
);
|
|
3350
3486
|
}
|
|
3351
3487
|
|
|
3352
3488
|
// @ts-ignore - currentMediaStatus coming from SelfUtil
|
|
3353
3489
|
if (!MeetingUtil.isMediaEstablished(this.currentMediaStatus)) {
|
|
3354
|
-
return Promise.reject(
|
|
3490
|
+
return Promise.reject(
|
|
3491
|
+
new ParameterError('Cannot reconnect, Media has not established to reconnect')
|
|
3492
|
+
);
|
|
3355
3493
|
}
|
|
3356
3494
|
|
|
3357
3495
|
try {
|
|
3358
3496
|
LoggerProxy.logger.info('Meeting:index#reconnect --> Validating reconnect ability.');
|
|
3359
3497
|
// @ts-ignore
|
|
3360
3498
|
this.reconnectionManager.validate();
|
|
3361
|
-
}
|
|
3362
|
-
catch (error) {
|
|
3499
|
+
} catch (error) {
|
|
3363
3500
|
// Unable to reconnect this call
|
|
3364
3501
|
if (error instanceof ReconnectInProgress) {
|
|
3365
|
-
LoggerProxy.logger.info(
|
|
3366
|
-
|
|
3367
|
-
|
|
3502
|
+
LoggerProxy.logger.info(
|
|
3503
|
+
'Meeting:index#reconnect --> Unable to reconnect, reconnection in progress.'
|
|
3504
|
+
);
|
|
3505
|
+
} else {
|
|
3368
3506
|
LoggerProxy.logger.log('Meeting:index#reconnect --> Unable to reconnect.', error);
|
|
3369
3507
|
}
|
|
3370
3508
|
|
|
@@ -3375,7 +3513,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3375
3513
|
this,
|
|
3376
3514
|
{
|
|
3377
3515
|
file: 'meeting/index',
|
|
3378
|
-
function: 'reconnect'
|
|
3516
|
+
function: 'reconnect',
|
|
3379
3517
|
},
|
|
3380
3518
|
EVENT_TRIGGERS.MEETING_RECONNECTION_STARTING
|
|
3381
3519
|
);
|
|
@@ -3387,7 +3525,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3387
3525
|
this,
|
|
3388
3526
|
{
|
|
3389
3527
|
file: 'meeting/index',
|
|
3390
|
-
function: 'reconnect'
|
|
3528
|
+
function: 'reconnect',
|
|
3391
3529
|
},
|
|
3392
3530
|
EVENT_TRIGGERS.MEETING_RECONNECTION_SUCCESS
|
|
3393
3531
|
);
|
|
@@ -3398,29 +3536,26 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3398
3536
|
this,
|
|
3399
3537
|
{
|
|
3400
3538
|
file: 'meeting/index',
|
|
3401
|
-
function: 'reconnect'
|
|
3539
|
+
function: 'reconnect',
|
|
3402
3540
|
},
|
|
3403
3541
|
EVENT_TRIGGERS.MEETING_RECONNECTION_FAILURE,
|
|
3404
3542
|
{
|
|
3405
|
-
error: new ReconnectionError('Reconnection failure event', error)
|
|
3543
|
+
error: new ReconnectionError('Reconnection failure event', error),
|
|
3406
3544
|
}
|
|
3407
3545
|
);
|
|
3408
3546
|
|
|
3409
3547
|
LoggerProxy.logger.error('Meeting:index#reconnect --> Meeting reconnect failed', error);
|
|
3410
3548
|
|
|
3411
|
-
Metrics.sendBehavioralMetric(
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
stack: error.stack
|
|
3418
|
-
}
|
|
3419
|
-
);
|
|
3549
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_RECONNECT_FAILURE, {
|
|
3550
|
+
correlation_id: this.correlationId,
|
|
3551
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
3552
|
+
reason: error.message,
|
|
3553
|
+
stack: error.stack,
|
|
3554
|
+
});
|
|
3420
3555
|
|
|
3421
3556
|
this.uploadLogs({
|
|
3422
3557
|
file: 'meeting/index',
|
|
3423
|
-
function: 'reconnect'
|
|
3558
|
+
function: 'reconnect',
|
|
3424
3559
|
});
|
|
3425
3560
|
|
|
3426
3561
|
return Promise.reject(new ReconnectionError('Reconnection failure event', error));
|
|
@@ -3474,14 +3609,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3474
3609
|
|
|
3475
3610
|
this.triggerStopReceivingTranscriptionEvent();
|
|
3476
3611
|
|
|
3477
|
-
Metrics.sendBehavioralMetric(
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
event
|
|
3483
|
-
}
|
|
3484
|
-
);
|
|
3612
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_FAILURE, {
|
|
3613
|
+
correlation_id: this.correlationId,
|
|
3614
|
+
reason: 'unexpected error: transcription LLM web socket connection error had occured.',
|
|
3615
|
+
event,
|
|
3616
|
+
});
|
|
3485
3617
|
});
|
|
3486
3618
|
}
|
|
3487
3619
|
|
|
@@ -3499,10 +3631,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3499
3631
|
try {
|
|
3500
3632
|
const {datachannelUrl} = this.locusInfo.info;
|
|
3501
3633
|
// @ts-ignore - fix type
|
|
3502
|
-
const {
|
|
3634
|
+
const {
|
|
3635
|
+
body: {webSocketUrl},
|
|
3636
|
+
} = await this.request({
|
|
3503
3637
|
method: HTTP_VERBS.POST,
|
|
3504
3638
|
uri: datachannelUrl,
|
|
3505
|
-
body: {deviceUrl: this.deviceUrl}
|
|
3639
|
+
body: {deviceUrl: this.deviceUrl},
|
|
3506
3640
|
});
|
|
3507
3641
|
|
|
3508
3642
|
LoggerProxy.logger.info(
|
|
@@ -3514,7 +3648,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3514
3648
|
webSocketUrl,
|
|
3515
3649
|
// @ts-ignore - fix type
|
|
3516
3650
|
this.webex.sessionId,
|
|
3517
|
-
this.members
|
|
3651
|
+
this.members
|
|
3518
3652
|
);
|
|
3519
3653
|
|
|
3520
3654
|
LoggerProxy.logger.info(
|
|
@@ -3528,7 +3662,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3528
3662
|
this,
|
|
3529
3663
|
{
|
|
3530
3664
|
file: 'meeting/index',
|
|
3531
|
-
function: 'join'
|
|
3665
|
+
function: 'join',
|
|
3532
3666
|
},
|
|
3533
3667
|
EVENT_TRIGGERS.MEETING_STARTED_RECEIVING_TRANSCRIPTION,
|
|
3534
3668
|
payload
|
|
@@ -3538,17 +3672,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3538
3672
|
this.monitorTranscriptionSocketConnection();
|
|
3539
3673
|
// @ts-ignore - fix type
|
|
3540
3674
|
this.transcription.connect(this.webex.credentials.supertoken.access_token);
|
|
3541
|
-
}
|
|
3542
|
-
catch (error) {
|
|
3675
|
+
} catch (error) {
|
|
3543
3676
|
LoggerProxy.logger.error(`Meeting:index#receiveTranscription --> ${error}`);
|
|
3544
|
-
Metrics.sendBehavioralMetric(
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
stack: error.stack
|
|
3550
|
-
}
|
|
3551
|
-
);
|
|
3677
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_FAILURE, {
|
|
3678
|
+
correlation_id: this.correlationId,
|
|
3679
|
+
reason: error.message,
|
|
3680
|
+
stack: error.stack,
|
|
3681
|
+
});
|
|
3552
3682
|
}
|
|
3553
3683
|
}
|
|
3554
3684
|
|
|
@@ -3578,7 +3708,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3578
3708
|
this,
|
|
3579
3709
|
{
|
|
3580
3710
|
file: 'meeting',
|
|
3581
|
-
function: 'triggerStopReceivingTranscriptionEvent'
|
|
3711
|
+
function: 'triggerStopReceivingTranscriptionEvent',
|
|
3582
3712
|
},
|
|
3583
3713
|
EVENT_TRIGGERS.MEETING_STOPPED_RECEIVING_TRANSCRIPTION
|
|
3584
3714
|
);
|
|
@@ -3625,10 +3755,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3625
3755
|
|
|
3626
3756
|
if (!this.hasJoinedOnce) {
|
|
3627
3757
|
this.hasJoinedOnce = true;
|
|
3628
|
-
}
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3758
|
+
} else {
|
|
3759
|
+
LoggerProxy.logger.log(
|
|
3760
|
+
`Meeting:index#join --> Generating a new correlation id for meeting ${this.id}`
|
|
3761
|
+
);
|
|
3762
|
+
LoggerProxy.logger.log(
|
|
3763
|
+
`Meeting:index#join --> Previous correlation id ${this.correlationId}`
|
|
3764
|
+
);
|
|
3632
3765
|
this.setCorrelationId(uuid.v4());
|
|
3633
3766
|
LoggerProxy.logger.log(`Meeting:index#join --> New correlation id ${this.correlationId}`);
|
|
3634
3767
|
}
|
|
@@ -3640,7 +3773,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3640
3773
|
Metrics.postEvent({
|
|
3641
3774
|
event: eventType.CALL_INITIATED,
|
|
3642
3775
|
meeting: this,
|
|
3643
|
-
data: {trigger: trigger.USER_INTERACTION, isRoapCallEnabled: true}
|
|
3776
|
+
data: {trigger: trigger.USER_INTERACTION, isRoapCallEnabled: true},
|
|
3644
3777
|
});
|
|
3645
3778
|
|
|
3646
3779
|
LoggerProxy.logger.log('Meeting:index#join --> Joining a meeting');
|
|
@@ -3715,12 +3848,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3715
3848
|
.then((join) => {
|
|
3716
3849
|
joinSuccess(join);
|
|
3717
3850
|
this.deferJoin = undefined;
|
|
3718
|
-
Metrics.sendBehavioralMetric(
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
correlation_id: this.correlationId
|
|
3722
|
-
}
|
|
3723
|
-
);
|
|
3851
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_SUCCESS, {
|
|
3852
|
+
correlation_id: this.correlationId,
|
|
3853
|
+
});
|
|
3724
3854
|
|
|
3725
3855
|
return join;
|
|
3726
3856
|
})
|
|
@@ -3740,9 +3870,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3740
3870
|
LoggerProxy.logger.info('Meeting:index#join --> enabled to recieve transcription!');
|
|
3741
3871
|
}
|
|
3742
3872
|
}
|
|
3743
|
-
}
|
|
3744
|
-
|
|
3745
|
-
|
|
3873
|
+
} else {
|
|
3874
|
+
LoggerProxy.logger.error(
|
|
3875
|
+
'Meeting:index#join --> Receving transcription is not supported on this platform'
|
|
3876
|
+
);
|
|
3746
3877
|
}
|
|
3747
3878
|
|
|
3748
3879
|
return join;
|
|
@@ -3756,28 +3887,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3756
3887
|
meeting: this,
|
|
3757
3888
|
meetingId: this.id,
|
|
3758
3889
|
data: {
|
|
3759
|
-
errors: [
|
|
3760
|
-
|
|
3761
|
-
]
|
|
3762
|
-
}
|
|
3890
|
+
errors: [Metrics.parseLocusError(error.error, true)],
|
|
3891
|
+
},
|
|
3763
3892
|
});
|
|
3764
3893
|
|
|
3765
3894
|
// TODO: change this to error codes and pre defined dictionary
|
|
3766
|
-
Metrics.sendBehavioralMetric(
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
stack: error.stack
|
|
3772
|
-
}
|
|
3773
|
-
);
|
|
3895
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_FAILURE, {
|
|
3896
|
+
correlation_id: this.correlationId,
|
|
3897
|
+
reason: error.error?.message,
|
|
3898
|
+
stack: error.stack,
|
|
3899
|
+
});
|
|
3774
3900
|
|
|
3775
3901
|
// Upload logs on join Failure
|
|
3776
3902
|
Trigger.trigger(
|
|
3777
3903
|
this,
|
|
3778
3904
|
{
|
|
3779
3905
|
file: 'meeting/index',
|
|
3780
|
-
function: 'join'
|
|
3906
|
+
function: 'join',
|
|
3781
3907
|
},
|
|
3782
3908
|
EVENTS.REQUEST_UPLOAD_LOGS,
|
|
3783
3909
|
this
|
|
@@ -3854,28 +3980,28 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3854
3980
|
|
|
3855
3981
|
if (!this.dialInUrl) this.dialInUrl = `dialin:///${uuid.v4()}`;
|
|
3856
3982
|
|
|
3857
|
-
return this.meetingRequest
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3983
|
+
return this.meetingRequest
|
|
3984
|
+
.dialIn({
|
|
3985
|
+
correlationId,
|
|
3986
|
+
dialInUrl: this.dialInUrl,
|
|
3987
|
+
locusUrl,
|
|
3988
|
+
clientUrl: this.deviceUrl,
|
|
3989
|
+
})
|
|
3990
|
+
.then((res) => {
|
|
3991
|
+
this.locusInfo.onFullLocus(res.body.locus);
|
|
3992
|
+
})
|
|
3993
|
+
.catch((error) => {
|
|
3994
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_IN_FAILURE, {
|
|
3868
3995
|
correlation_id: this.correlationId,
|
|
3869
3996
|
dial_in_url: this.dialInUrl,
|
|
3870
3997
|
locus_id: locusUrl.split('/').pop(),
|
|
3871
3998
|
client_url: this.deviceUrl,
|
|
3872
3999
|
reason: error.error?.message,
|
|
3873
|
-
stack: error.stack
|
|
3874
|
-
}
|
|
3875
|
-
);
|
|
4000
|
+
stack: error.stack,
|
|
4001
|
+
});
|
|
3876
4002
|
|
|
3877
|
-
|
|
3878
|
-
|
|
4003
|
+
return Promise.reject(error);
|
|
4004
|
+
});
|
|
3879
4005
|
}
|
|
3880
4006
|
|
|
3881
4007
|
/**
|
|
@@ -3892,29 +4018,29 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3892
4018
|
|
|
3893
4019
|
if (!this.dialOutUrl) this.dialOutUrl = `dialout:///${uuid.v4()}`;
|
|
3894
4020
|
|
|
3895
|
-
return this.meetingRequest
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
4021
|
+
return this.meetingRequest
|
|
4022
|
+
.dialOut({
|
|
4023
|
+
correlationId,
|
|
4024
|
+
dialOutUrl: this.dialOutUrl,
|
|
4025
|
+
phoneNumber,
|
|
4026
|
+
locusUrl,
|
|
4027
|
+
clientUrl: this.deviceUrl,
|
|
4028
|
+
})
|
|
4029
|
+
.then((res) => {
|
|
4030
|
+
this.locusInfo.onFullLocus(res.body.locus);
|
|
4031
|
+
})
|
|
4032
|
+
.catch((error) => {
|
|
4033
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_DIAL_OUT_FAILURE, {
|
|
3907
4034
|
correlation_id: this.correlationId,
|
|
3908
4035
|
dial_out_url: this.dialOutUrl,
|
|
3909
4036
|
locus_id: locusUrl.split('/').pop(),
|
|
3910
4037
|
client_url: this.deviceUrl,
|
|
3911
4038
|
reason: error.error?.message,
|
|
3912
|
-
stack: error.stack
|
|
3913
|
-
}
|
|
3914
|
-
);
|
|
4039
|
+
stack: error.stack,
|
|
4040
|
+
});
|
|
3915
4041
|
|
|
3916
|
-
|
|
3917
|
-
|
|
4042
|
+
return Promise.reject(error);
|
|
4043
|
+
});
|
|
3918
4044
|
}
|
|
3919
4045
|
|
|
3920
4046
|
/**
|
|
@@ -3926,12 +4052,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3926
4052
|
*/
|
|
3927
4053
|
public disconnectPhoneAudio() {
|
|
3928
4054
|
return Promise.all([
|
|
3929
|
-
this.isPhoneProvisioned(this.dialInDeviceStatus)
|
|
3930
|
-
MeetingUtil.disconnectPhoneAudio(this, this.dialInUrl)
|
|
3931
|
-
Promise.resolve(),
|
|
3932
|
-
this.isPhoneProvisioned(this.dialOutDeviceStatus)
|
|
3933
|
-
MeetingUtil.disconnectPhoneAudio(this, this.dialOutUrl)
|
|
3934
|
-
Promise.resolve()
|
|
4055
|
+
this.isPhoneProvisioned(this.dialInDeviceStatus)
|
|
4056
|
+
? MeetingUtil.disconnectPhoneAudio(this, this.dialInUrl)
|
|
4057
|
+
: Promise.resolve(),
|
|
4058
|
+
this.isPhoneProvisioned(this.dialOutDeviceStatus)
|
|
4059
|
+
? MeetingUtil.disconnectPhoneAudio(this, this.dialOutUrl)
|
|
4060
|
+
: Promise.resolve(),
|
|
3935
4061
|
]);
|
|
3936
4062
|
}
|
|
3937
4063
|
|
|
@@ -3957,17 +4083,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3957
4083
|
share: true,
|
|
3958
4084
|
share_audio: false,
|
|
3959
4085
|
video: false,
|
|
3960
|
-
whiteboard: false
|
|
4086
|
+
whiteboard: false,
|
|
3961
4087
|
},
|
|
3962
4088
|
tx: {
|
|
3963
4089
|
audio: false,
|
|
3964
4090
|
share: false,
|
|
3965
4091
|
share_audio: false,
|
|
3966
4092
|
video: false,
|
|
3967
|
-
whiteboard: false
|
|
3968
|
-
}
|
|
3969
|
-
}
|
|
3970
|
-
}
|
|
4093
|
+
whiteboard: false,
|
|
4094
|
+
},
|
|
4095
|
+
},
|
|
4096
|
+
},
|
|
3971
4097
|
});
|
|
3972
4098
|
|
|
3973
4099
|
Metrics.postEvent({event: eventType.MOVE_MEDIA, meeting: this});
|
|
@@ -3986,8 +4112,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3986
4112
|
sendAudio: false,
|
|
3987
4113
|
receiveAudio: false,
|
|
3988
4114
|
sendShare: false,
|
|
3989
|
-
receiveShare: true
|
|
3990
|
-
}
|
|
4115
|
+
receiveShare: true,
|
|
4116
|
+
},
|
|
3991
4117
|
};
|
|
3992
4118
|
|
|
3993
4119
|
// clean up the local tracks
|
|
@@ -3999,50 +4125,44 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3999
4125
|
|
|
4000
4126
|
this.mediaProperties.unsetMediaTracks();
|
|
4001
4127
|
|
|
4002
|
-
|
|
4003
4128
|
// when a move to is intiated by the client , Locus delets the existing media node from the server as soon the DX answers the meeting
|
|
4004
4129
|
// once the DX answers we establish connection back the media server with only receiveShare enabled
|
|
4005
4130
|
// @ts-ignore - reconnectMedia does not accept any argument
|
|
4006
|
-
await this.reconnectionManager.reconnectMedia(mediaSettings)
|
|
4007
|
-
.
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
);
|
|
4011
|
-
});
|
|
4012
|
-
}
|
|
4013
|
-
catch (error) {
|
|
4131
|
+
await this.reconnectionManager.reconnectMedia(mediaSettings).then(() => {
|
|
4132
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MOVE_TO_SUCCESS);
|
|
4133
|
+
});
|
|
4134
|
+
} catch (error) {
|
|
4014
4135
|
LoggerProxy.logger.error('Meeting:index#moveTo --> Failed to moveTo resourceId', error);
|
|
4015
|
-
Metrics.sendBehavioralMetric(
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
stack: error.stack
|
|
4022
|
-
}
|
|
4023
|
-
);
|
|
4136
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MOVE_TO_FAILURE, {
|
|
4137
|
+
correlation_id: this.correlationId,
|
|
4138
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4139
|
+
reason: error.message,
|
|
4140
|
+
stack: error.stack,
|
|
4141
|
+
});
|
|
4024
4142
|
}
|
|
4025
4143
|
});
|
|
4026
4144
|
|
|
4027
|
-
LoggerProxy.logger.info(
|
|
4145
|
+
LoggerProxy.logger.info(
|
|
4146
|
+
'Meeting:index#moveTo --> Initated moved to using resourceId',
|
|
4147
|
+
resourceId
|
|
4148
|
+
);
|
|
4028
4149
|
|
|
4029
|
-
return MeetingUtil.joinMeetingOptions(this, {resourceId, moveToResource: true})
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
{
|
|
4150
|
+
return MeetingUtil.joinMeetingOptions(this, {resourceId, moveToResource: true})
|
|
4151
|
+
.then(() => {
|
|
4152
|
+
this.meetingFiniteStateMachine.join();
|
|
4153
|
+
})
|
|
4154
|
+
.catch((error) => {
|
|
4155
|
+
this.meetingFiniteStateMachine.fail(error);
|
|
4156
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MOVE_TO_FAILURE, {
|
|
4036
4157
|
correlation_id: this.correlationId,
|
|
4037
4158
|
locus_id: this.locusUrl.split('/').pop(),
|
|
4038
4159
|
reason: error.message,
|
|
4039
|
-
stack: error.stack
|
|
4040
|
-
}
|
|
4041
|
-
|
|
4042
|
-
LoggerProxy.logger.error('Meeting:index#moveTo --> Failed to moveTo resourceId', error);
|
|
4160
|
+
stack: error.stack,
|
|
4161
|
+
});
|
|
4162
|
+
LoggerProxy.logger.error('Meeting:index#moveTo --> Failed to moveTo resourceId', error);
|
|
4043
4163
|
|
|
4044
|
-
|
|
4045
|
-
|
|
4164
|
+
return Promise.reject(error);
|
|
4165
|
+
});
|
|
4046
4166
|
}
|
|
4047
4167
|
|
|
4048
4168
|
/**
|
|
@@ -4062,26 +4182,24 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4062
4182
|
Metrics.postEvent({event: eventType.MOVE_MEDIA, meeting: this});
|
|
4063
4183
|
|
|
4064
4184
|
return MeetingUtil.joinMeetingOptions(this)
|
|
4065
|
-
.then(() =>
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
BEHAVIORAL_METRICS.MOVE_FROM_SUCCESS
|
|
4073
|
-
)
|
|
4074
|
-
|
|
4185
|
+
.then(() =>
|
|
4186
|
+
MeetingUtil.leaveMeeting(this, {
|
|
4187
|
+
resourceId,
|
|
4188
|
+
correlationId: oldCorrelationId,
|
|
4189
|
+
moveMeeting: true,
|
|
4190
|
+
}).then(() => {
|
|
4191
|
+
this.resourceId = '';
|
|
4192
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MOVE_FROM_SUCCESS);
|
|
4193
|
+
})
|
|
4194
|
+
)
|
|
4195
|
+
.catch((error) => {
|
|
4075
4196
|
this.meetingFiniteStateMachine.fail(error);
|
|
4076
|
-
Metrics.sendBehavioralMetric(
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
stack: error.stack
|
|
4083
|
-
}
|
|
4084
|
-
);
|
|
4197
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MOVE_FROM_FAILURE, {
|
|
4198
|
+
correlation_id: this.correlationId,
|
|
4199
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4200
|
+
reason: error.message,
|
|
4201
|
+
stack: error.stack,
|
|
4202
|
+
});
|
|
4085
4203
|
LoggerProxy.logger.error('Meeting:index#moveTo --> Failed to moveTo resourceId', error);
|
|
4086
4204
|
|
|
4087
4205
|
return Promise.reject(error);
|
|
@@ -4104,55 +4222,63 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4104
4222
|
getMediaStreams = (
|
|
4105
4223
|
mediaDirection: any,
|
|
4106
4224
|
// This return an OBJECT {video: {height, widght}}
|
|
4225
|
+
// eslint-disable-next-line default-param-last
|
|
4107
4226
|
audioVideo: any = VIDEO_RESOLUTIONS[this.mediaProperties.localQualityLevel],
|
|
4108
4227
|
sharePreferences?: any
|
|
4109
4228
|
) => {
|
|
4110
4229
|
if (
|
|
4111
4230
|
mediaDirection &&
|
|
4112
|
-
(
|
|
4113
|
-
mediaDirection.sendAudio ||
|
|
4114
|
-
mediaDirection.sendVideo ||
|
|
4115
|
-
mediaDirection.sendShare
|
|
4116
|
-
)
|
|
4231
|
+
(mediaDirection.sendAudio || mediaDirection.sendVideo || mediaDirection.sendShare)
|
|
4117
4232
|
) {
|
|
4118
|
-
if (
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
) &&
|
|
4233
|
+
if (
|
|
4234
|
+
mediaDirection &&
|
|
4235
|
+
mediaDirection.sendAudio &&
|
|
4236
|
+
mediaDirection.sendVideo &&
|
|
4237
|
+
mediaDirection.sendShare &&
|
|
4124
4238
|
isBrowser('safari')
|
|
4125
4239
|
) {
|
|
4126
|
-
LoggerProxy.logger.warn(
|
|
4240
|
+
LoggerProxy.logger.warn(
|
|
4241
|
+
'Meeting:index#getMediaStreams --> Setting `sendShare` to FALSE, due to complications with Safari'
|
|
4242
|
+
);
|
|
4127
4243
|
|
|
4128
4244
|
mediaDirection.sendShare = false;
|
|
4129
4245
|
|
|
4130
|
-
LoggerProxy.logger.warn(
|
|
4131
|
-
|
|
4246
|
+
LoggerProxy.logger.warn(
|
|
4247
|
+
'Meeting:index#getMediaStreams --> Enabling `sendShare` along with `sendAudio` & `sendVideo`, on Safari, causes a failure while setting up a screen share at the same time as the camera+mic stream'
|
|
4248
|
+
);
|
|
4249
|
+
LoggerProxy.logger.warn(
|
|
4250
|
+
'Meeting:index#getMediaStreams --> Please use `meeting.shareScreen()` to manually start the screen share after successfully joining the meeting'
|
|
4251
|
+
);
|
|
4132
4252
|
}
|
|
4133
4253
|
|
|
4134
4254
|
if (audioVideo && isString(audioVideo)) {
|
|
4135
4255
|
if (Object.keys(VIDEO_RESOLUTIONS).includes(audioVideo)) {
|
|
4136
4256
|
this.mediaProperties.setLocalQualityLevel(audioVideo);
|
|
4137
4257
|
audioVideo = {video: VIDEO_RESOLUTIONS[audioVideo].video};
|
|
4138
|
-
}
|
|
4139
|
-
|
|
4140
|
-
|
|
4258
|
+
} else {
|
|
4259
|
+
throw new ParameterError(
|
|
4260
|
+
`${audioVideo} not supported. Either pass level from pre-defined resolutions or pass complete audioVideo object`
|
|
4261
|
+
);
|
|
4141
4262
|
}
|
|
4142
4263
|
}
|
|
4143
4264
|
|
|
4144
4265
|
if (!audioVideo.video) {
|
|
4145
|
-
audioVideo = {
|
|
4266
|
+
audioVideo = {
|
|
4267
|
+
...audioVideo,
|
|
4268
|
+
video: {
|
|
4269
|
+
...audioVideo.video,
|
|
4270
|
+
...VIDEO_RESOLUTIONS[this.mediaProperties.localQualityLevel].video,
|
|
4271
|
+
},
|
|
4272
|
+
};
|
|
4146
4273
|
}
|
|
4147
4274
|
// extract deviceId if exists otherwise default to null.
|
|
4148
|
-
const {deviceId: preferredVideoDevice} = (audioVideo && audioVideo.video || {deviceId: null}
|
|
4275
|
+
const {deviceId: preferredVideoDevice} = (audioVideo && audioVideo.video) || {deviceId: null};
|
|
4149
4276
|
const lastVideoDeviceId = this.mediaProperties.getVideoDeviceId();
|
|
4150
4277
|
|
|
4151
4278
|
if (preferredVideoDevice) {
|
|
4152
4279
|
// Store new preferred video input device
|
|
4153
4280
|
this.mediaProperties.setVideoDeviceId(preferredVideoDevice);
|
|
4154
|
-
}
|
|
4155
|
-
else if (lastVideoDeviceId) {
|
|
4281
|
+
} else if (lastVideoDeviceId) {
|
|
4156
4282
|
// no new video preference specified so use last stored value,
|
|
4157
4283
|
// works with empty object {} or media constraint.
|
|
4158
4284
|
// eslint-disable-next-line no-param-reassign
|
|
@@ -4160,50 +4286,55 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4160
4286
|
...audioVideo,
|
|
4161
4287
|
video: {
|
|
4162
4288
|
...audioVideo.video,
|
|
4163
|
-
deviceId: lastVideoDeviceId
|
|
4164
|
-
}
|
|
4289
|
+
deviceId: lastVideoDeviceId,
|
|
4290
|
+
},
|
|
4165
4291
|
};
|
|
4166
4292
|
}
|
|
4167
4293
|
|
|
4168
4294
|
return Media.getSupportedDevice({
|
|
4169
4295
|
sendAudio: mediaDirection.sendAudio,
|
|
4170
|
-
sendVideo: mediaDirection.sendVideo
|
|
4296
|
+
sendVideo: mediaDirection.sendVideo,
|
|
4171
4297
|
})
|
|
4172
|
-
.catch((error) =>
|
|
4173
|
-
|
|
4174
|
-
|
|
4298
|
+
.catch((error) =>
|
|
4299
|
+
Promise.reject(
|
|
4300
|
+
new MediaError(
|
|
4301
|
+
'Given constraints do not match permission set for either camera or microphone',
|
|
4302
|
+
error
|
|
4303
|
+
)
|
|
4304
|
+
)
|
|
4305
|
+
)
|
|
4175
4306
|
.then((devicePermissions) =>
|
|
4176
4307
|
Media.getUserMedia(
|
|
4177
4308
|
{
|
|
4178
4309
|
...mediaDirection,
|
|
4179
4310
|
sendAudio: devicePermissions.sendAudio,
|
|
4180
4311
|
sendVideo: devicePermissions.sendVideo,
|
|
4181
|
-
isSharing: this.shareStatus === SHARE_STATUS.LOCAL_SHARE_ACTIVE
|
|
4312
|
+
isSharing: this.shareStatus === SHARE_STATUS.LOCAL_SHARE_ACTIVE,
|
|
4182
4313
|
},
|
|
4183
4314
|
audioVideo,
|
|
4184
4315
|
sharePreferences,
|
|
4185
4316
|
// @ts-ignore - config coming from registerPlugin
|
|
4186
4317
|
this.config
|
|
4187
|
-
)
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4318
|
+
).catch((error) => {
|
|
4319
|
+
// Whenever there is a failure when trying to access a user's device
|
|
4320
|
+
// report it as an Behavioral metric
|
|
4321
|
+
// This gives visibility into common errors and can help
|
|
4322
|
+
// with further troubleshooting
|
|
4323
|
+
const metricName = BEHAVIORAL_METRICS.GET_USER_MEDIA_FAILURE;
|
|
4324
|
+
const data = {
|
|
4325
|
+
correlation_id: this.correlationId,
|
|
4326
|
+
locus_id: this.locusUrl?.split('/').pop(),
|
|
4327
|
+
reason: error.message,
|
|
4328
|
+
stack: error.stack,
|
|
4329
|
+
};
|
|
4330
|
+
const metadata = {
|
|
4331
|
+
type: error.name,
|
|
4332
|
+
};
|
|
4333
|
+
|
|
4334
|
+
Metrics.sendBehavioralMetric(metricName, data, metadata);
|
|
4335
|
+
throw new MediaError('Unable to retrieve media streams', error);
|
|
4336
|
+
})
|
|
4337
|
+
);
|
|
4207
4338
|
}
|
|
4208
4339
|
|
|
4209
4340
|
return Promise.reject(
|
|
@@ -4211,7 +4342,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4211
4342
|
);
|
|
4212
4343
|
};
|
|
4213
4344
|
|
|
4214
|
-
|
|
4215
4345
|
/**
|
|
4216
4346
|
* Checks if the machine has at least one audio or video device
|
|
4217
4347
|
* @param {Object} options
|
|
@@ -4220,7 +4350,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4220
4350
|
* @returns {Object}
|
|
4221
4351
|
* @memberof Meetings
|
|
4222
4352
|
*/
|
|
4223
|
-
getSupportedDevices = ({
|
|
4353
|
+
getSupportedDevices = ({
|
|
4354
|
+
sendAudio = true,
|
|
4355
|
+
sendVideo = true,
|
|
4356
|
+
}: {
|
|
4357
|
+
sendAudio: boolean;
|
|
4358
|
+
sendVideo: boolean;
|
|
4359
|
+
}) => Media.getSupportedDevice({sendAudio, sendVideo});
|
|
4224
4360
|
|
|
4225
4361
|
/**
|
|
4226
4362
|
* Get the devices from the Media module
|
|
@@ -4236,21 +4372,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4236
4372
|
* @returns {void}
|
|
4237
4373
|
*/
|
|
4238
4374
|
handleRoapFailure = (error) => {
|
|
4375
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
4239
4376
|
const sendBehavioralMetric = (metricName, error, correlationId) => {
|
|
4240
4377
|
const data = {
|
|
4241
4378
|
code: error.code,
|
|
4242
4379
|
correlation_id: correlationId,
|
|
4243
4380
|
reason: error.message,
|
|
4244
|
-
stack: error.stack
|
|
4381
|
+
stack: error.stack,
|
|
4245
4382
|
};
|
|
4246
4383
|
const metadata = {
|
|
4247
|
-
type: error.cause?.name || error.name
|
|
4384
|
+
type: error.cause?.name || error.name,
|
|
4248
4385
|
};
|
|
4249
4386
|
|
|
4250
4387
|
Metrics.sendBehavioralMetric(metricName, data, metadata);
|
|
4251
4388
|
};
|
|
4252
4389
|
|
|
4253
|
-
|
|
4254
4390
|
if (error instanceof MC.Errors.SdpOfferCreationError) {
|
|
4255
4391
|
sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.id);
|
|
4256
4392
|
|
|
@@ -4260,11 +4396,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4260
4396
|
data: {
|
|
4261
4397
|
canProceed: false,
|
|
4262
4398
|
errors: [
|
|
4263
|
-
Metrics.generateErrorPayload(2001, true, MetricsError.name.MEDIA_ENGINE, undefined)
|
|
4264
|
-
|
|
4399
|
+
Metrics.generateErrorPayload(2001, true, MetricsError.name.MEDIA_ENGINE, undefined),
|
|
4400
|
+
],
|
|
4401
|
+
},
|
|
4265
4402
|
});
|
|
4266
|
-
}
|
|
4267
|
-
|
|
4403
|
+
} else if (
|
|
4404
|
+
error instanceof MC.Errors.SdpOfferHandlingError ||
|
|
4405
|
+
error instanceof MC.Errors.SdpAnswerHandlingError
|
|
4406
|
+
) {
|
|
4268
4407
|
sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.id);
|
|
4269
4408
|
|
|
4270
4409
|
Metrics.postEvent({
|
|
@@ -4272,11 +4411,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4272
4411
|
meetingId: this.id,
|
|
4273
4412
|
data: {
|
|
4274
4413
|
canProceed: false,
|
|
4275
|
-
errors: [
|
|
4276
|
-
|
|
4414
|
+
errors: [
|
|
4415
|
+
Metrics.generateErrorPayload(2001, true, MetricsError.name.MEDIA_ENGINE, undefined),
|
|
4416
|
+
],
|
|
4417
|
+
},
|
|
4277
4418
|
});
|
|
4278
|
-
}
|
|
4279
|
-
|
|
4419
|
+
} else if (error instanceof MC.Errors.SdpError) {
|
|
4420
|
+
// this covers also the case of MC.Errors.IceGatheringError which extends MC.Errors.SdpError
|
|
4280
4421
|
sendBehavioralMetric(BEHAVIORAL_METRICS.INVALID_ICE_CANDIDATE, error, this.id);
|
|
4281
4422
|
|
|
4282
4423
|
Metrics.postEvent({
|
|
@@ -4285,8 +4426,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4285
4426
|
data: {
|
|
4286
4427
|
canProceed: false,
|
|
4287
4428
|
errors: [
|
|
4288
|
-
Metrics.generateErrorPayload(2001, true, MetricsError.name.MEDIA_ENGINE, undefined)
|
|
4289
|
-
|
|
4429
|
+
Metrics.generateErrorPayload(2001, true, MetricsError.name.MEDIA_ENGINE, undefined),
|
|
4430
|
+
],
|
|
4431
|
+
},
|
|
4290
4432
|
});
|
|
4291
4433
|
}
|
|
4292
4434
|
};
|
|
@@ -4314,15 +4456,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4314
4456
|
meetingId: this.id,
|
|
4315
4457
|
});
|
|
4316
4458
|
|
|
4317
|
-
logRequest(
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4459
|
+
logRequest(
|
|
4460
|
+
this.roap.sendRoapOK({
|
|
4461
|
+
seq: event.roapMessage.seq,
|
|
4462
|
+
mediaId: this.mediaId,
|
|
4463
|
+
correlationId: this.correlationId,
|
|
4464
|
+
}),
|
|
4465
|
+
{
|
|
4466
|
+
header: `${LOG_HEADER} Send Roap OK`,
|
|
4467
|
+
success: `${LOG_HEADER} Successfully send roap OK`,
|
|
4468
|
+
failure: `${LOG_HEADER} Error joining the call on send roap OK, `,
|
|
4469
|
+
}
|
|
4470
|
+
);
|
|
4326
4471
|
break;
|
|
4327
4472
|
|
|
4328
4473
|
case 'OFFER':
|
|
@@ -4331,18 +4476,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4331
4476
|
meetingId: this.id,
|
|
4332
4477
|
});
|
|
4333
4478
|
|
|
4334
|
-
logRequest(
|
|
4335
|
-
.sendRoapMediaRequest({
|
|
4479
|
+
logRequest(
|
|
4480
|
+
this.roap.sendRoapMediaRequest({
|
|
4336
4481
|
sdp: event.roapMessage.sdp,
|
|
4337
4482
|
seq: event.roapMessage.seq,
|
|
4338
4483
|
tieBreaker: event.roapMessage.tieBreaker,
|
|
4339
4484
|
meeting: this, // or can pass meeting ID
|
|
4340
|
-
reconnect: this.reconnectionManager.isReconnectInProgress()
|
|
4341
|
-
}),
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4485
|
+
reconnect: this.reconnectionManager.isReconnectInProgress(),
|
|
4486
|
+
}),
|
|
4487
|
+
{
|
|
4488
|
+
header: `${LOG_HEADER} Send Roap Offer`,
|
|
4489
|
+
success: `${LOG_HEADER} Successfully send roap offer`,
|
|
4490
|
+
failure: `${LOG_HEADER} Error joining the call on send roap offer, `,
|
|
4491
|
+
}
|
|
4492
|
+
);
|
|
4346
4493
|
break;
|
|
4347
4494
|
|
|
4348
4495
|
case 'ANSWER':
|
|
@@ -4351,64 +4498,79 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4351
4498
|
meetingId: this.id,
|
|
4352
4499
|
});
|
|
4353
4500
|
|
|
4354
|
-
logRequest(
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4501
|
+
logRequest(
|
|
4502
|
+
this.roap.sendRoapAnswer({
|
|
4503
|
+
sdp: event.roapMessage.sdp,
|
|
4504
|
+
seq: event.roapMessage.seq,
|
|
4505
|
+
mediaId: this.mediaId,
|
|
4506
|
+
correlationId: this.correlationId,
|
|
4507
|
+
}),
|
|
4508
|
+
{
|
|
4509
|
+
header: `${LOG_HEADER} Send Roap Answer.`,
|
|
4510
|
+
success: `${LOG_HEADER} Successfully send roap answer`,
|
|
4511
|
+
failure: `${LOG_HEADER} Error joining the call on send roap answer, `,
|
|
4512
|
+
}
|
|
4513
|
+
).catch((error) => {
|
|
4514
|
+
const metricName = BEHAVIORAL_METRICS.ROAP_ANSWER_FAILURE;
|
|
4515
|
+
const data = {
|
|
4516
|
+
correlation_id: this.correlationId,
|
|
4517
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4518
|
+
reason: error.message,
|
|
4519
|
+
stack: error.stack,
|
|
4520
|
+
};
|
|
4521
|
+
const metadata = {
|
|
4522
|
+
type: error.name,
|
|
4523
|
+
};
|
|
4524
|
+
|
|
4525
|
+
Metrics.sendBehavioralMetric(metricName, data, metadata);
|
|
4526
|
+
});
|
|
4378
4527
|
break;
|
|
4379
4528
|
|
|
4380
4529
|
case 'ERROR':
|
|
4381
|
-
if (
|
|
4530
|
+
if (
|
|
4531
|
+
event.roapMessage.errorType === MC.ErrorType.CONFLICT ||
|
|
4532
|
+
event.roapMessage.errorType === MC.ErrorType.DOUBLECONFLICT
|
|
4533
|
+
) {
|
|
4382
4534
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_GLARE_CONDITION, {
|
|
4383
4535
|
correlation_id: this.correlationId,
|
|
4384
4536
|
locus_id: this.locusUrl.split('/').pop(),
|
|
4385
|
-
sequence: event.roapMessage.seq
|
|
4537
|
+
sequence: event.roapMessage.seq,
|
|
4386
4538
|
});
|
|
4387
4539
|
}
|
|
4388
|
-
logRequest(
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4540
|
+
logRequest(
|
|
4541
|
+
this.roap.sendRoapError({
|
|
4542
|
+
seq: event.roapMessage.seq,
|
|
4543
|
+
errorType: event.roapMessage.errorType,
|
|
4544
|
+
mediaId: this.mediaId,
|
|
4545
|
+
correlationId: this.correlationId,
|
|
4546
|
+
}),
|
|
4547
|
+
{
|
|
4548
|
+
header: `${LOG_HEADER} Send Roap Error.`,
|
|
4549
|
+
success: `${LOG_HEADER} Successfully send roap error`,
|
|
4550
|
+
failure: `${LOG_HEADER} Failed to send roap error, `,
|
|
4551
|
+
}
|
|
4552
|
+
);
|
|
4398
4553
|
break;
|
|
4399
4554
|
|
|
4400
4555
|
default:
|
|
4401
|
-
LoggerProxy.logger.error(
|
|
4556
|
+
LoggerProxy.logger.error(
|
|
4557
|
+
`${LOG_HEADER} Unsupported message type: ${event.roapMessage.messageType}`
|
|
4558
|
+
);
|
|
4402
4559
|
break;
|
|
4403
4560
|
}
|
|
4404
4561
|
});
|
|
4405
4562
|
|
|
4406
4563
|
// eslint-disable-next-line no-param-reassign
|
|
4407
4564
|
this.mediaProperties.webrtcMediaConnection.on(MC.Event.REMOTE_TRACK_ADDED, (event) => {
|
|
4408
|
-
LoggerProxy.logger.log(
|
|
4565
|
+
LoggerProxy.logger.log(
|
|
4566
|
+
`Meeting:index#setupMediaConnectionListeners --> REMOTE_TRACK_ADDED event received for webrtcMediaConnection: ${JSON.stringify(
|
|
4567
|
+
event
|
|
4568
|
+
)}`
|
|
4569
|
+
);
|
|
4409
4570
|
|
|
4410
4571
|
const mediaTrack = event.track;
|
|
4411
4572
|
|
|
4573
|
+
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
4412
4574
|
let eventType;
|
|
4413
4575
|
|
|
4414
4576
|
switch (event.type) {
|
|
@@ -4427,7 +4589,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4427
4589
|
}
|
|
4428
4590
|
break;
|
|
4429
4591
|
default: {
|
|
4430
|
-
LoggerProxy.logger.log(
|
|
4592
|
+
LoggerProxy.logger.log(
|
|
4593
|
+
'Meeting:index#setupMediaConnectionListeners --> unexpected track'
|
|
4594
|
+
);
|
|
4431
4595
|
}
|
|
4432
4596
|
}
|
|
4433
4597
|
|
|
@@ -4440,12 +4604,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4440
4604
|
this,
|
|
4441
4605
|
{
|
|
4442
4606
|
file: 'meeting/index',
|
|
4443
|
-
function: 'setupRemoteTrackListener:Event.REMOTE_TRACK_ADDED'
|
|
4607
|
+
function: 'setupRemoteTrackListener:Event.REMOTE_TRACK_ADDED',
|
|
4444
4608
|
},
|
|
4445
4609
|
EVENT_TRIGGERS.MEDIA_READY,
|
|
4446
4610
|
{
|
|
4447
4611
|
type: eventType,
|
|
4448
|
-
stream: MediaUtil.createMediaStream([mediaTrack])
|
|
4612
|
+
stream: MediaUtil.createMediaStream([mediaTrack]),
|
|
4449
4613
|
}
|
|
4450
4614
|
);
|
|
4451
4615
|
}
|
|
@@ -4464,51 +4628,47 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4464
4628
|
data: {
|
|
4465
4629
|
canProceed: false,
|
|
4466
4630
|
errors: [
|
|
4467
|
-
Metrics.generateErrorPayload(
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
}
|
|
4631
|
+
Metrics.generateErrorPayload(2004, false, MetricsError.name.MEDIA_ENGINE, undefined),
|
|
4632
|
+
],
|
|
4633
|
+
},
|
|
4471
4634
|
});
|
|
4472
4635
|
|
|
4473
4636
|
this.uploadLogs({
|
|
4474
4637
|
file: 'peer-connection-manager/index',
|
|
4475
|
-
function: 'connectionFailed'
|
|
4638
|
+
function: 'connectionFailed',
|
|
4476
4639
|
});
|
|
4477
4640
|
|
|
4478
|
-
Metrics.sendBehavioralMetric(
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
locus_id: this.locusId
|
|
4483
|
-
}
|
|
4484
|
-
);
|
|
4641
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.CONNECTION_FAILURE, {
|
|
4642
|
+
correlation_id: this.correlationId,
|
|
4643
|
+
locus_id: this.locusId,
|
|
4644
|
+
});
|
|
4485
4645
|
};
|
|
4486
4646
|
|
|
4487
|
-
LoggerProxy.logger.info(
|
|
4647
|
+
LoggerProxy.logger.info(
|
|
4648
|
+
`Meeting:index#setupMediaConnectionListeners --> connection state changed to ${event.state}`
|
|
4649
|
+
);
|
|
4488
4650
|
switch (event.state) {
|
|
4489
4651
|
case MC.ConnectionState.Connecting:
|
|
4490
4652
|
Metrics.postEvent({event: eventType.ICE_START, meeting: this});
|
|
4491
4653
|
break;
|
|
4492
4654
|
case MC.ConnectionState.Connected:
|
|
4493
4655
|
Metrics.postEvent({event: eventType.ICE_END, meeting: this});
|
|
4494
|
-
Metrics.sendBehavioralMetric(
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
locus_id: this.locusId
|
|
4499
|
-
}
|
|
4500
|
-
);
|
|
4656
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.CONNECTION_SUCCESS, {
|
|
4657
|
+
correlation_id: this.correlationId,
|
|
4658
|
+
locus_id: this.locusId,
|
|
4659
|
+
});
|
|
4501
4660
|
this.setNetworkStatus(NETWORK_STATUS.CONNECTED);
|
|
4502
4661
|
this.reconnectionManager.iceReconnected();
|
|
4503
4662
|
break;
|
|
4504
4663
|
case MC.ConnectionState.Disconnected:
|
|
4505
4664
|
this.setNetworkStatus(NETWORK_STATUS.DISCONNECTED);
|
|
4506
|
-
this.reconnectionManager.waitForIceReconnect()
|
|
4507
|
-
.
|
|
4508
|
-
|
|
4665
|
+
this.reconnectionManager.waitForIceReconnect().catch(() => {
|
|
4666
|
+
LoggerProxy.logger.info(
|
|
4667
|
+
'Meeting:index#setupMediaConnectionListeners --> state DISCONNECTED, automatic reconnection timed out.'
|
|
4668
|
+
);
|
|
4509
4669
|
|
|
4510
|
-
|
|
4511
|
-
|
|
4670
|
+
connectionFailed();
|
|
4671
|
+
});
|
|
4512
4672
|
break;
|
|
4513
4673
|
case MC.ConnectionState.Failed:
|
|
4514
4674
|
connectionFailed();
|
|
@@ -4518,53 +4678,58 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4518
4678
|
}
|
|
4519
4679
|
});
|
|
4520
4680
|
|
|
4521
|
-
this.mediaProperties.webrtcMediaConnection.on(MC.Event.ACTIVE_SPEAKERS_CHANGED,
|
|
4522
|
-
(
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4681
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.ACTIVE_SPEAKERS_CHANGED, (msg) => {
|
|
4682
|
+
Trigger.trigger(
|
|
4683
|
+
this,
|
|
4684
|
+
{
|
|
4685
|
+
file: 'meeting/index',
|
|
4686
|
+
function: 'setupMediaConnectionListeners',
|
|
4687
|
+
},
|
|
4688
|
+
EVENT_TRIGGERS.ACTIVE_SPEAKER_CHANGED,
|
|
4689
|
+
{
|
|
4690
|
+
seqNum: msg.seqNum,
|
|
4691
|
+
memberIds: msg.csis
|
|
4692
|
+
.map((csi) => this.members.findMemberByCsi(csi)?.id)
|
|
4693
|
+
.filter((item) => item !== undefined),
|
|
4694
|
+
}
|
|
4695
|
+
);
|
|
4696
|
+
});
|
|
4536
4697
|
|
|
4537
|
-
this.mediaProperties.webrtcMediaConnection.on(
|
|
4698
|
+
this.mediaProperties.webrtcMediaConnection.on(
|
|
4699
|
+
MC.Event.VIDEO_SOURCES_COUNT_CHANGED,
|
|
4538
4700
|
(numTotalSources, numLiveSources) => {
|
|
4539
4701
|
Trigger.trigger(
|
|
4540
4702
|
this,
|
|
4541
4703
|
{
|
|
4542
4704
|
file: 'meeting/index',
|
|
4543
|
-
function: 'setupMediaConnectionListeners'
|
|
4705
|
+
function: 'setupMediaConnectionListeners',
|
|
4544
4706
|
},
|
|
4545
4707
|
EVENT_TRIGGERS.REMOTE_VIDEO_SOURCE_COUNT_CHANGED,
|
|
4546
4708
|
{
|
|
4547
4709
|
numTotalSources,
|
|
4548
|
-
numLiveSources
|
|
4710
|
+
numLiveSources,
|
|
4549
4711
|
}
|
|
4550
4712
|
);
|
|
4551
|
-
}
|
|
4713
|
+
}
|
|
4714
|
+
);
|
|
4552
4715
|
|
|
4553
|
-
this.mediaProperties.webrtcMediaConnection.on(
|
|
4716
|
+
this.mediaProperties.webrtcMediaConnection.on(
|
|
4717
|
+
MC.Event.AUDIO_SOURCES_COUNT_CHANGED,
|
|
4554
4718
|
(numTotalSources, numLiveSources) => {
|
|
4555
4719
|
Trigger.trigger(
|
|
4556
4720
|
this,
|
|
4557
4721
|
{
|
|
4558
4722
|
file: 'meeting/index',
|
|
4559
|
-
function: 'setupMediaConnectionListeners'
|
|
4723
|
+
function: 'setupMediaConnectionListeners',
|
|
4560
4724
|
},
|
|
4561
4725
|
EVENT_TRIGGERS.REMOTE_AUDIO_SOURCE_COUNT_CHANGED,
|
|
4562
4726
|
{
|
|
4563
4727
|
numTotalSources,
|
|
4564
|
-
numLiveSources
|
|
4728
|
+
numLiveSources,
|
|
4565
4729
|
}
|
|
4566
4730
|
);
|
|
4567
|
-
}
|
|
4731
|
+
}
|
|
4732
|
+
);
|
|
4568
4733
|
};
|
|
4569
4734
|
|
|
4570
4735
|
/**
|
|
@@ -4578,15 +4743,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4578
4743
|
// TODO: might have to send the same event to the developer
|
|
4579
4744
|
// Add ip address info if geo hint is present
|
|
4580
4745
|
// @ts-ignore fix type
|
|
4581
|
-
options.data.intervalMetadata.peerReflexiveIP =
|
|
4582
|
-
|
|
4746
|
+
options.data.intervalMetadata.peerReflexiveIP =
|
|
4747
|
+
this.webex.meetings.geoHintInfo?.clientAddress ||
|
|
4748
|
+
options.data.intervalMetadata.peerReflexiveIP ||
|
|
4749
|
+
MQA_STATS.DEFAULT_IP;
|
|
4750
|
+
Metrics.postEvent({
|
|
4751
|
+
event: eventType.MEDIA_QUALITY,
|
|
4752
|
+
meeting: this,
|
|
4753
|
+
data: {intervalData: options.data, networkType: options.networkType},
|
|
4754
|
+
});
|
|
4583
4755
|
});
|
|
4584
4756
|
this.statsAnalyzer.on(StatsAnalyzerEvents.LOCAL_MEDIA_STARTED, (data) => {
|
|
4585
4757
|
Trigger.trigger(
|
|
4586
4758
|
this,
|
|
4587
4759
|
{
|
|
4588
4760
|
file: 'meeting/index',
|
|
4589
|
-
function: 'addMedia'
|
|
4761
|
+
function: 'addMedia',
|
|
4590
4762
|
},
|
|
4591
4763
|
EVENT_TRIGGERS.MEETING_MEDIA_LOCAL_STARTED,
|
|
4592
4764
|
data
|
|
@@ -4595,8 +4767,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4595
4767
|
event: eventType.SENDING_MEDIA_START,
|
|
4596
4768
|
meeting: this,
|
|
4597
4769
|
data: {
|
|
4598
|
-
mediaType: data.type
|
|
4599
|
-
}
|
|
4770
|
+
mediaType: data.type,
|
|
4771
|
+
},
|
|
4600
4772
|
});
|
|
4601
4773
|
});
|
|
4602
4774
|
this.statsAnalyzer.on(StatsAnalyzerEvents.LOCAL_MEDIA_STOPPED, (data) => {
|
|
@@ -4604,8 +4776,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4604
4776
|
event: eventType.SENDING_MEDIA_STOP,
|
|
4605
4777
|
meeting: this,
|
|
4606
4778
|
data: {
|
|
4607
|
-
mediaType: data.type
|
|
4608
|
-
}
|
|
4779
|
+
mediaType: data.type,
|
|
4780
|
+
},
|
|
4609
4781
|
});
|
|
4610
4782
|
});
|
|
4611
4783
|
this.statsAnalyzer.on(StatsAnalyzerEvents.REMOTE_MEDIA_STARTED, (data) => {
|
|
@@ -4613,7 +4785,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4613
4785
|
this,
|
|
4614
4786
|
{
|
|
4615
4787
|
file: 'meeting/index',
|
|
4616
|
-
function: 'addMedia'
|
|
4788
|
+
function: 'addMedia',
|
|
4617
4789
|
},
|
|
4618
4790
|
EVENT_TRIGGERS.MEETING_MEDIA_REMOTE_STARTED,
|
|
4619
4791
|
data
|
|
@@ -4622,8 +4794,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4622
4794
|
event: eventType.RECEIVING_MEDIA_START,
|
|
4623
4795
|
meeting: this,
|
|
4624
4796
|
data: {
|
|
4625
|
-
mediaType: data.type
|
|
4626
|
-
}
|
|
4797
|
+
mediaType: data.type,
|
|
4798
|
+
},
|
|
4627
4799
|
});
|
|
4628
4800
|
});
|
|
4629
4801
|
this.statsAnalyzer.on(StatsAnalyzerEvents.REMOTE_MEDIA_STOPPED, (data) => {
|
|
@@ -4631,8 +4803,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4631
4803
|
event: eventType.RECEIVING_MEDIA_STOP,
|
|
4632
4804
|
meeting: this,
|
|
4633
4805
|
data: {
|
|
4634
|
-
mediaType: data.type
|
|
4635
|
-
}
|
|
4806
|
+
mediaType: data.type,
|
|
4807
|
+
},
|
|
4636
4808
|
});
|
|
4637
4809
|
});
|
|
4638
4810
|
};
|
|
@@ -4642,19 +4814,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4642
4814
|
}
|
|
4643
4815
|
|
|
4644
4816
|
createMediaConnection(turnServerInfo) {
|
|
4645
|
-
const mc = Media.createMediaConnection(
|
|
4646
|
-
this.
|
|
4647
|
-
this.
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
enableExtmap: this.config.enableExtmap,
|
|
4655
|
-
turnServerInfo
|
|
4656
|
-
}
|
|
4657
|
-
);
|
|
4817
|
+
const mc = Media.createMediaConnection(this.isMultistream, this.getMediaConnectionDebugId(), {
|
|
4818
|
+
mediaProperties: this.mediaProperties,
|
|
4819
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
|
|
4820
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4821
|
+
enableRtx: this.config.enableRtx,
|
|
4822
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4823
|
+
enableExtmap: this.config.enableExtmap,
|
|
4824
|
+
turnServerInfo,
|
|
4825
|
+
});
|
|
4658
4826
|
|
|
4659
4827
|
this.mediaProperties.setMediaPeerConnection(mc);
|
|
4660
4828
|
this.setupMediaConnectionListeners();
|
|
@@ -4672,15 +4840,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4672
4840
|
* @returns {void}
|
|
4673
4841
|
*/
|
|
4674
4842
|
forwardEvent(eventEmitter, eventTypeToForward, meetingEventType) {
|
|
4675
|
-
eventEmitter.on(eventTypeToForward, (data) =>
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4843
|
+
eventEmitter.on(eventTypeToForward, (data) =>
|
|
4844
|
+
Trigger.trigger(
|
|
4845
|
+
this,
|
|
4846
|
+
{
|
|
4847
|
+
file: 'meetings',
|
|
4848
|
+
function: 'addMedia',
|
|
4849
|
+
},
|
|
4850
|
+
meetingEventType,
|
|
4851
|
+
data
|
|
4852
|
+
)
|
|
4853
|
+
);
|
|
4684
4854
|
}
|
|
4685
4855
|
|
|
4686
4856
|
/**
|
|
@@ -4714,9 +4884,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4714
4884
|
return Promise.reject(new UserInLobbyError());
|
|
4715
4885
|
}
|
|
4716
4886
|
|
|
4717
|
-
const {
|
|
4718
|
-
localStream, localShare, mediaSettings, remoteMediaManagerConfig
|
|
4719
|
-
} = options;
|
|
4887
|
+
const {localStream, localShare, mediaSettings, remoteMediaManagerConfig} = options;
|
|
4720
4888
|
|
|
4721
4889
|
LoggerProxy.logger.info(`${LOG_HEADER} Adding Media.`);
|
|
4722
4890
|
|
|
@@ -4730,17 +4898,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4730
4898
|
share: false,
|
|
4731
4899
|
share_audio: false,
|
|
4732
4900
|
video: false,
|
|
4733
|
-
whiteboard: false
|
|
4901
|
+
whiteboard: false,
|
|
4734
4902
|
},
|
|
4735
4903
|
tx: {
|
|
4736
4904
|
audio: false,
|
|
4737
4905
|
share: false,
|
|
4738
4906
|
share_audio: false,
|
|
4739
4907
|
video: false,
|
|
4740
|
-
whiteboard: false
|
|
4741
|
-
}
|
|
4742
|
-
}
|
|
4743
|
-
}
|
|
4908
|
+
whiteboard: false,
|
|
4909
|
+
},
|
|
4910
|
+
},
|
|
4911
|
+
},
|
|
4744
4912
|
});
|
|
4745
4913
|
|
|
4746
4914
|
return MeetingUtil.validateOptions(options)
|
|
@@ -4762,12 +4930,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4762
4930
|
remoteMediaManagerConfig
|
|
4763
4931
|
);
|
|
4764
4932
|
|
|
4765
|
-
this.forwardEvent(
|
|
4766
|
-
|
|
4767
|
-
|
|
4933
|
+
this.forwardEvent(
|
|
4934
|
+
this.remoteMediaManager,
|
|
4935
|
+
RemoteMediaManagerEvent.AudioCreated,
|
|
4936
|
+
EVENT_TRIGGERS.REMOTE_MEDIA_AUDIO_CREATED
|
|
4937
|
+
);
|
|
4938
|
+
this.forwardEvent(
|
|
4939
|
+
this.remoteMediaManager,
|
|
4940
|
+
RemoteMediaManagerEvent.ScreenShareAudioCreated,
|
|
4941
|
+
EVENT_TRIGGERS.REMOTE_MEDIA_SCREEN_SHARE_AUDIO_CREATED
|
|
4942
|
+
);
|
|
4943
|
+
this.forwardEvent(
|
|
4944
|
+
this.remoteMediaManager,
|
|
4945
|
+
RemoteMediaManagerEvent.VideoLayoutChanged,
|
|
4946
|
+
EVENT_TRIGGERS.REMOTE_MEDIA_VIDEO_LAYOUT_CHANGED
|
|
4947
|
+
);
|
|
4768
4948
|
|
|
4769
|
-
return this.remoteMediaManager.start()
|
|
4770
|
-
.then(() => mc.initiateOffer());
|
|
4949
|
+
return this.remoteMediaManager.start().then(() => mc.initiateOffer());
|
|
4771
4950
|
}
|
|
4772
4951
|
|
|
4773
4952
|
return mc.initiateOffer();
|
|
@@ -4775,9 +4954,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4775
4954
|
.then(() => {
|
|
4776
4955
|
this.setMercuryListener();
|
|
4777
4956
|
})
|
|
4778
|
-
.then(() =>
|
|
4779
|
-
|
|
4780
|
-
|
|
4957
|
+
.then(() =>
|
|
4958
|
+
this.getDevices().then((devices) => {
|
|
4959
|
+
MeetingUtil.handleDeviceLogging(devices);
|
|
4960
|
+
})
|
|
4961
|
+
)
|
|
4781
4962
|
.then(() => {
|
|
4782
4963
|
this.handleMediaLogging(this.mediaProperties);
|
|
4783
4964
|
LoggerProxy.logger.info(`${LOG_HEADER} media connection created`);
|
|
@@ -4789,41 +4970,49 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4789
4970
|
// @ts-ignore - config coming from registerPlugin
|
|
4790
4971
|
this.statsAnalyzer = new StatsAnalyzer(this.config.stats, this.networkQualityMonitor);
|
|
4791
4972
|
this.setupStatsAnalyzerEventHandlers();
|
|
4792
|
-
this.networkQualityMonitor.on(
|
|
4973
|
+
this.networkQualityMonitor.on(
|
|
4974
|
+
EVENT_TRIGGERS.NETWORK_QUALITY,
|
|
4975
|
+
this.sendNetworkQualityEvent.bind(this)
|
|
4976
|
+
);
|
|
4793
4977
|
}
|
|
4794
4978
|
})
|
|
4795
4979
|
.catch((error) => {
|
|
4796
|
-
LoggerProxy.logger.error(
|
|
4980
|
+
LoggerProxy.logger.error(
|
|
4981
|
+
`${LOG_HEADER} Error adding media , setting up peerconnection, `,
|
|
4982
|
+
error
|
|
4983
|
+
);
|
|
4797
4984
|
|
|
4798
4985
|
throw error;
|
|
4799
4986
|
})
|
|
4800
|
-
.then(() => new Promise<void>((resolve, reject) => {
|
|
4801
|
-
let timerCount = 0;
|
|
4802
|
-
|
|
4803
|
-
// eslint-disable-next-line func-names
|
|
4804
|
-
// eslint-disable-next-line prefer-arrow-callback
|
|
4805
|
-
if (this.type === _CALL_) {
|
|
4806
|
-
resolve();
|
|
4807
|
-
}
|
|
4808
|
-
const joiningTimer = setInterval(() => {
|
|
4809
|
-
timerCount += 1;
|
|
4810
|
-
if (this.meetingState === FULL_STATE.ACTIVE) {
|
|
4811
|
-
clearInterval(joiningTimer);
|
|
4812
|
-
resolve();
|
|
4813
|
-
}
|
|
4814
|
-
|
|
4815
|
-
if (timerCount === 4) {
|
|
4816
|
-
clearInterval(joiningTimer);
|
|
4817
|
-
reject(new Error('Meeting is still not active '));
|
|
4818
|
-
}
|
|
4819
|
-
}, 1000);
|
|
4820
|
-
}))
|
|
4821
4987
|
.then(
|
|
4822
|
-
() =>
|
|
4823
|
-
|
|
4824
|
-
|
|
4988
|
+
() =>
|
|
4989
|
+
new Promise<void>((resolve, reject) => {
|
|
4990
|
+
let timerCount = 0;
|
|
4991
|
+
|
|
4992
|
+
// eslint-disable-next-line func-names
|
|
4993
|
+
// eslint-disable-next-line prefer-arrow-callback
|
|
4994
|
+
if (this.type === _CALL_) {
|
|
4995
|
+
resolve();
|
|
4996
|
+
}
|
|
4997
|
+
const joiningTimer = setInterval(() => {
|
|
4998
|
+
timerCount += 1;
|
|
4999
|
+
if (this.meetingState === FULL_STATE.ACTIVE) {
|
|
5000
|
+
clearInterval(joiningTimer);
|
|
5001
|
+
resolve();
|
|
5002
|
+
}
|
|
5003
|
+
|
|
5004
|
+
if (timerCount === 4) {
|
|
5005
|
+
clearInterval(joiningTimer);
|
|
5006
|
+
reject(new Error('Meeting is still not active '));
|
|
5007
|
+
}
|
|
5008
|
+
}, 1000);
|
|
4825
5009
|
})
|
|
4826
5010
|
)
|
|
5011
|
+
.then(() =>
|
|
5012
|
+
this.mediaProperties.waitForMediaConnectionConnected().catch(() => {
|
|
5013
|
+
throw createMeetingsError(30202, 'Meeting connection failed');
|
|
5014
|
+
})
|
|
5015
|
+
)
|
|
4827
5016
|
.then(() => {
|
|
4828
5017
|
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection CONNECTED`);
|
|
4829
5018
|
if (mediaSettings && mediaSettings.sendShare && localShare) {
|
|
@@ -4839,60 +5028,58 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4839
5028
|
})
|
|
4840
5029
|
.then(() => this.mediaProperties.getCurrentConnectionType())
|
|
4841
5030
|
.then((connectionType) => {
|
|
4842
|
-
Metrics.sendBehavioralMetric(
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
connectionType
|
|
4848
|
-
}
|
|
4849
|
-
);
|
|
5031
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS, {
|
|
5032
|
+
correlation_id: this.correlationId,
|
|
5033
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
5034
|
+
connectionType,
|
|
5035
|
+
});
|
|
4850
5036
|
})
|
|
4851
5037
|
.catch((error) => {
|
|
4852
5038
|
// Clean up stats analyzer, peer connection, and turn off listeners
|
|
4853
|
-
const stopStatsAnalyzer =
|
|
5039
|
+
const stopStatsAnalyzer = this.statsAnalyzer
|
|
5040
|
+
? this.statsAnalyzer.stopAnalyzer()
|
|
5041
|
+
: Promise.resolve();
|
|
4854
5042
|
|
|
4855
|
-
return stopStatsAnalyzer
|
|
4856
|
-
.
|
|
4857
|
-
this.statsAnalyzer = null;
|
|
5043
|
+
return stopStatsAnalyzer.then(() => {
|
|
5044
|
+
this.statsAnalyzer = null;
|
|
4858
5045
|
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
5046
|
+
if (this.mediaProperties.webrtcMediaConnection) {
|
|
5047
|
+
this.closePeerConnections();
|
|
5048
|
+
this.unsetPeerConnections();
|
|
5049
|
+
}
|
|
4863
5050
|
|
|
4864
|
-
|
|
5051
|
+
LoggerProxy.logger.error(
|
|
5052
|
+
`${LOG_HEADER} Error adding media failed to initiate PC and send request, `,
|
|
5053
|
+
error
|
|
5054
|
+
);
|
|
4865
5055
|
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
turnServerUsed
|
|
4876
|
-
}
|
|
4877
|
-
);
|
|
5056
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
|
|
5057
|
+
correlation_id: this.correlationId,
|
|
5058
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
5059
|
+
reason: error.message,
|
|
5060
|
+
stack: error.stack,
|
|
5061
|
+
code: error.code,
|
|
5062
|
+
turnDiscoverySkippedReason,
|
|
5063
|
+
turnServerUsed,
|
|
5064
|
+
});
|
|
4878
5065
|
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
5066
|
+
// Upload logs on error while adding media
|
|
5067
|
+
Trigger.trigger(
|
|
5068
|
+
this,
|
|
5069
|
+
{
|
|
5070
|
+
file: 'meeting/index',
|
|
5071
|
+
function: 'addMedia',
|
|
5072
|
+
},
|
|
5073
|
+
EVENTS.REQUEST_UPLOAD_LOGS,
|
|
5074
|
+
this
|
|
5075
|
+
);
|
|
4889
5076
|
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
5077
|
+
if (error instanceof MC.Errors.SdpError) {
|
|
5078
|
+
this.leave({reason: MEETING_REMOVED_REASON.MEETING_CONNECTION_FAILED});
|
|
5079
|
+
}
|
|
4893
5080
|
|
|
4894
|
-
|
|
4895
|
-
|
|
5081
|
+
throw error;
|
|
5082
|
+
});
|
|
4896
5083
|
});
|
|
4897
5084
|
}
|
|
4898
5085
|
|
|
@@ -4918,10 +5105,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4918
5105
|
private enqueueMediaUpdate(mediaUpdateType: string, options: object) {
|
|
4919
5106
|
return new Promise((resolve, reject) => {
|
|
4920
5107
|
const queueItem = {
|
|
4921
|
-
pendingPromiseResolve: resolve,
|
|
5108
|
+
pendingPromiseResolve: resolve,
|
|
5109
|
+
pendingPromiseReject: reject,
|
|
5110
|
+
mediaUpdateType,
|
|
5111
|
+
options,
|
|
4922
5112
|
};
|
|
4923
5113
|
|
|
4924
|
-
LoggerProxy.logger.log(
|
|
5114
|
+
LoggerProxy.logger.log(
|
|
5115
|
+
`Meeting:index#enqueueMediaUpdate --> enqueuing media update type=${mediaUpdateType}`
|
|
5116
|
+
);
|
|
4925
5117
|
this.queuedMediaUpdates.push(queueItem);
|
|
4926
5118
|
});
|
|
4927
5119
|
}
|
|
@@ -4940,9 +5132,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4940
5132
|
this,
|
|
4941
5133
|
{
|
|
4942
5134
|
file: 'meeting/index',
|
|
4943
|
-
function: 'mediaNegotiatedEvent'
|
|
5135
|
+
function: 'mediaNegotiatedEvent',
|
|
4944
5136
|
},
|
|
4945
|
-
EVENT_TRIGGERS.MEDIA_NEGOTIATED
|
|
5137
|
+
EVENT_TRIGGERS.MEDIA_NEGOTIATED
|
|
4946
5138
|
);
|
|
4947
5139
|
}
|
|
4948
5140
|
};
|
|
@@ -4955,12 +5147,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4955
5147
|
* @memberof Meeting
|
|
4956
5148
|
*/
|
|
4957
5149
|
processNextQueuedMediaUpdate = () => {
|
|
4958
|
-
if (this.canUpdateMedia() &&
|
|
4959
|
-
const {
|
|
4960
|
-
|
|
4961
|
-
} = this.queuedMediaUpdates.shift();
|
|
5150
|
+
if (this.canUpdateMedia() && this.queuedMediaUpdates.length > 0) {
|
|
5151
|
+
const {pendingPromiseResolve, pendingPromiseReject, mediaUpdateType, options} =
|
|
5152
|
+
this.queuedMediaUpdates.shift();
|
|
4962
5153
|
|
|
4963
|
-
LoggerProxy.logger.log(
|
|
5154
|
+
LoggerProxy.logger.log(
|
|
5155
|
+
`Meeting:index#processNextQueuedMediaUpdate --> performing delayed media update type=${mediaUpdateType}`
|
|
5156
|
+
);
|
|
4964
5157
|
switch (mediaUpdateType) {
|
|
4965
5158
|
case MEDIA_UPDATE_TYPE.ALL:
|
|
4966
5159
|
this.updateMedia(options).then(pendingPromiseResolve, pendingPromiseReject);
|
|
@@ -4975,7 +5168,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4975
5168
|
this.updateShare(options).then(pendingPromiseResolve, pendingPromiseReject);
|
|
4976
5169
|
break;
|
|
4977
5170
|
default:
|
|
4978
|
-
LoggerProxy.logger.error(
|
|
5171
|
+
LoggerProxy.logger.error(
|
|
5172
|
+
`Peer-connection-manager:index#processNextQueuedMediaUpdate --> unsupported media update type ${mediaUpdateType} found in the queue`
|
|
5173
|
+
);
|
|
4979
5174
|
break;
|
|
4980
5175
|
}
|
|
4981
5176
|
}
|
|
@@ -5004,9 +5199,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5004
5199
|
if (!this.canUpdateMedia()) {
|
|
5005
5200
|
return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.ALL, options);
|
|
5006
5201
|
}
|
|
5007
|
-
const {
|
|
5008
|
-
localStream, localShare, mediaSettings
|
|
5009
|
-
} = options;
|
|
5202
|
+
const {localStream, localShare, mediaSettings} = options;
|
|
5010
5203
|
|
|
5011
5204
|
const previousSendShareStatus = this.mediaProperties.mediaDirection.sendShare;
|
|
5012
5205
|
|
|
@@ -5016,52 +5209,60 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5016
5209
|
|
|
5017
5210
|
return MeetingUtil.validateOptions(options)
|
|
5018
5211
|
.then(() => this.preMedia(localStream, localShare, mediaSettings))
|
|
5019
|
-
.then(() =>
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5212
|
+
.then(() =>
|
|
5213
|
+
this.mediaProperties.webrtcMediaConnection
|
|
5214
|
+
.updateSendReceiveOptions({
|
|
5215
|
+
send: {
|
|
5216
|
+
audio: this.mediaProperties.mediaDirection.sendAudio
|
|
5217
|
+
? this.mediaProperties.audioTrack
|
|
5218
|
+
: null,
|
|
5219
|
+
video: this.mediaProperties.mediaDirection.sendVideo
|
|
5220
|
+
? this.mediaProperties.videoTrack
|
|
5221
|
+
: null,
|
|
5222
|
+
screenShareVideo: this.mediaProperties.mediaDirection.sendShare
|
|
5223
|
+
? this.mediaProperties.shareTrack
|
|
5224
|
+
: null,
|
|
5225
|
+
},
|
|
5226
|
+
receive: {
|
|
5227
|
+
audio: this.mediaProperties.mediaDirection.receiveAudio,
|
|
5228
|
+
video: this.mediaProperties.mediaDirection.receiveVideo,
|
|
5229
|
+
screenShareVideo: this.mediaProperties.mediaDirection.receiveShare,
|
|
5230
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
|
|
5231
|
+
},
|
|
5232
|
+
})
|
|
5233
|
+
.then(() => {
|
|
5234
|
+
LoggerProxy.logger.info(
|
|
5235
|
+
`${LOG_HEADER} webrtcMediaConnection.updateSendReceiveOptions done`
|
|
5236
|
+
);
|
|
5237
|
+
})
|
|
5238
|
+
.catch((error) => {
|
|
5239
|
+
LoggerProxy.logger.error(`${LOG_HEADER} Error updatedMedia, `, error);
|
|
5037
5240
|
|
|
5038
|
-
|
|
5039
|
-
BEHAVIORAL_METRICS.UPDATE_MEDIA_FAILURE,
|
|
5040
|
-
{
|
|
5241
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.UPDATE_MEDIA_FAILURE, {
|
|
5041
5242
|
correlation_id: this.correlationId,
|
|
5042
5243
|
locus_id: this.locusUrl.split('/').pop(),
|
|
5043
5244
|
reason: error.message,
|
|
5044
|
-
stack: error.stack
|
|
5045
|
-
}
|
|
5046
|
-
);
|
|
5245
|
+
stack: error.stack,
|
|
5246
|
+
});
|
|
5047
5247
|
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5248
|
+
throw error;
|
|
5249
|
+
})
|
|
5250
|
+
// todo: the following code used to be called always after sending the roap message with the new SDP
|
|
5251
|
+
// now it's called independently from the roap message (so might be before it), check if that's OK
|
|
5252
|
+
// if not, ensure it's called after (now it's called after roap message is sent out, but we're not
|
|
5253
|
+
// waiting for sendRoapMediaRequest() to be resolved)
|
|
5254
|
+
.then(() => this.checkForStopShare(mediaSettings.sendShare, previousSendShareStatus))
|
|
5255
|
+
.then((startShare) => {
|
|
5256
|
+
// This is a special case if we do an /floor grant followed by /media
|
|
5257
|
+
// we actually get a OFFER from the server and a GLAR condition happens
|
|
5258
|
+
if (startShare) {
|
|
5259
|
+
// We are assuming that the clients are connected when doing an update
|
|
5260
|
+
return this.requestScreenShareFloor();
|
|
5261
|
+
}
|
|
5062
5262
|
|
|
5063
|
-
|
|
5064
|
-
|
|
5263
|
+
return Promise.resolve();
|
|
5264
|
+
})
|
|
5265
|
+
);
|
|
5065
5266
|
}
|
|
5066
5267
|
|
|
5067
5268
|
/**
|
|
@@ -5077,7 +5278,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5077
5278
|
* @public
|
|
5078
5279
|
* @memberof Meeting
|
|
5079
5280
|
*/
|
|
5080
|
-
public async updateAudio(options: {
|
|
5281
|
+
public async updateAudio(options: {
|
|
5282
|
+
sendAudio: boolean;
|
|
5283
|
+
receiveAudio: boolean;
|
|
5284
|
+
stream: MediaStream;
|
|
5285
|
+
}) {
|
|
5081
5286
|
if (!this.canUpdateMedia()) {
|
|
5082
5287
|
return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.AUDIO, options);
|
|
5083
5288
|
}
|
|
@@ -5095,7 +5300,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5095
5300
|
if (this.effects && this.effects.state) {
|
|
5096
5301
|
const bnrEnabled = this.effects.state.bnr.enabled;
|
|
5097
5302
|
|
|
5098
|
-
if (
|
|
5303
|
+
if (
|
|
5304
|
+
sendAudio &&
|
|
5305
|
+
!this.isAudioMuted() &&
|
|
5306
|
+
(bnrEnabled === BNR_STATUS.ENABLED || bnrEnabled === BNR_STATUS.SHOULD_ENABLE)
|
|
5307
|
+
) {
|
|
5099
5308
|
LoggerProxy.logger.info('Meeting:index#updateAudio. Calling WebRTC enable bnr method');
|
|
5100
5309
|
track = await this.internal_enableBNR(track);
|
|
5101
5310
|
LoggerProxy.logger.info('Meeting:index#updateAudio. WebRTC enable bnr request completed');
|
|
@@ -5103,15 +5312,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5103
5312
|
}
|
|
5104
5313
|
|
|
5105
5314
|
return MeetingUtil.validateOptions({sendAudio, localStream: stream})
|
|
5106
|
-
.then(() =>
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5315
|
+
.then(() =>
|
|
5316
|
+
this.mediaProperties.webrtcMediaConnection.updateSendReceiveOptions({
|
|
5317
|
+
send: {audio: track},
|
|
5318
|
+
receive: {
|
|
5319
|
+
audio: options.receiveAudio,
|
|
5320
|
+
video: this.mediaProperties.mediaDirection.receiveVideo,
|
|
5321
|
+
screenShareVideo: this.mediaProperties.mediaDirection.receiveShare,
|
|
5322
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
|
|
5323
|
+
},
|
|
5324
|
+
})
|
|
5325
|
+
)
|
|
5115
5326
|
.then(() => {
|
|
5116
5327
|
this.setLocalAudioTrack(track);
|
|
5117
5328
|
// todo: maybe this.mediaProperties.mediaDirection could be removed? it's duplicating stuff from webrtcMediaConnection
|
|
@@ -5119,7 +5330,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5119
5330
|
this.mediaProperties.mediaDirection.receiveAudio = receiveAudio;
|
|
5120
5331
|
|
|
5121
5332
|
// audio state could be undefined if you have not sent audio before
|
|
5122
|
-
this.audio =
|
|
5333
|
+
this.audio =
|
|
5334
|
+
this.audio || createMuteState(AUDIO, this, this.mediaProperties.mediaDirection);
|
|
5123
5335
|
});
|
|
5124
5336
|
}
|
|
5125
5337
|
|
|
@@ -5136,7 +5348,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5136
5348
|
* @public
|
|
5137
5349
|
* @memberof Meeting
|
|
5138
5350
|
*/
|
|
5139
|
-
public updateVideo(options: {
|
|
5351
|
+
public updateVideo(options: {sendVideo: boolean; receiveVideo: boolean; stream: MediaStream}) {
|
|
5140
5352
|
if (!this.canUpdateMedia()) {
|
|
5141
5353
|
return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.VIDEO, options);
|
|
5142
5354
|
}
|
|
@@ -5152,22 +5364,25 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5152
5364
|
}
|
|
5153
5365
|
|
|
5154
5366
|
return MeetingUtil.validateOptions({sendVideo, localStream: stream})
|
|
5155
|
-
.then(() =>
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5367
|
+
.then(() =>
|
|
5368
|
+
this.mediaProperties.webrtcMediaConnection.updateSendReceiveOptions({
|
|
5369
|
+
send: {video: track},
|
|
5370
|
+
receive: {
|
|
5371
|
+
audio: this.mediaProperties.mediaDirection.receiveAudio,
|
|
5372
|
+
video: options.receiveVideo,
|
|
5373
|
+
screenShareVideo: this.mediaProperties.mediaDirection.receiveShare,
|
|
5374
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
|
|
5375
|
+
},
|
|
5376
|
+
})
|
|
5377
|
+
)
|
|
5164
5378
|
.then(() => {
|
|
5165
5379
|
this.setLocalVideoTrack(track);
|
|
5166
5380
|
this.mediaProperties.mediaDirection.sendVideo = sendVideo;
|
|
5167
5381
|
this.mediaProperties.mediaDirection.receiveVideo = receiveVideo;
|
|
5168
5382
|
|
|
5169
5383
|
// video state could be undefined if you have not sent video before
|
|
5170
|
-
this.video =
|
|
5384
|
+
this.video =
|
|
5385
|
+
this.video || createMuteState(VIDEO, this, this.mediaProperties.mediaDirection);
|
|
5171
5386
|
});
|
|
5172
5387
|
}
|
|
5173
5388
|
|
|
@@ -5187,8 +5402,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5187
5402
|
|
|
5188
5403
|
if (!sendShare && previousShareStatus) {
|
|
5189
5404
|
// When user stops sharing
|
|
5190
|
-
return this.releaseScreenShareFloor()
|
|
5191
|
-
.then(() => Promise.resolve(false));
|
|
5405
|
+
return this.releaseScreenShareFloor().then(() => Promise.resolve(false));
|
|
5192
5406
|
}
|
|
5193
5407
|
|
|
5194
5408
|
return Promise.resolve();
|
|
@@ -5206,7 +5420,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5206
5420
|
* @public
|
|
5207
5421
|
* @memberof Meeting
|
|
5208
5422
|
*/
|
|
5209
|
-
public updateShare(options: {
|
|
5423
|
+
public updateShare(options: {
|
|
5424
|
+
sendShare?: boolean;
|
|
5425
|
+
receiveShare?: boolean;
|
|
5426
|
+
stream?: any;
|
|
5427
|
+
skipSignalingCheck?: boolean;
|
|
5428
|
+
}) {
|
|
5210
5429
|
if (!options.skipSignalingCheck && !this.canUpdateMedia()) {
|
|
5211
5430
|
return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.SHARE, options);
|
|
5212
5431
|
}
|
|
@@ -5227,22 +5446,25 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5227
5446
|
|
|
5228
5447
|
return MeetingUtil.validateOptions({sendShare, localShare: stream})
|
|
5229
5448
|
.then(() => this.checkForStopShare(sendShare, previousSendShareStatus))
|
|
5230
|
-
.then((startShare) =>
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5449
|
+
.then((startShare) =>
|
|
5450
|
+
this.mediaProperties.webrtcMediaConnection
|
|
5451
|
+
.updateSendReceiveOptions({
|
|
5452
|
+
send: {screenShareVideo: track},
|
|
5453
|
+
receive: {
|
|
5454
|
+
audio: this.mediaProperties.mediaDirection.receiveAudio,
|
|
5455
|
+
video: this.mediaProperties.mediaDirection.receiveVideo,
|
|
5456
|
+
screenShareVideo: options.receiveShare,
|
|
5457
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
|
|
5458
|
+
},
|
|
5459
|
+
})
|
|
5460
|
+
.then(() => {
|
|
5461
|
+
if (startShare) {
|
|
5462
|
+
return this.requestScreenShareFloor();
|
|
5463
|
+
}
|
|
5243
5464
|
|
|
5244
|
-
|
|
5245
|
-
|
|
5465
|
+
return Promise.resolve();
|
|
5466
|
+
})
|
|
5467
|
+
)
|
|
5246
5468
|
.then(() => {
|
|
5247
5469
|
this.mediaProperties.mediaDirection.sendShare = sendShare;
|
|
5248
5470
|
this.mediaProperties.mediaDirection.receiveShare = receiveShare;
|
|
@@ -5292,7 +5514,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5292
5514
|
.acknowledgeMeeting({
|
|
5293
5515
|
locusUrl: this.locusUrl,
|
|
5294
5516
|
deviceUrl: this.deviceUrl,
|
|
5295
|
-
correlationId: this.correlationId
|
|
5517
|
+
correlationId: this.correlationId,
|
|
5296
5518
|
})
|
|
5297
5519
|
.then((response) => Promise.resolve(response))
|
|
5298
5520
|
.then((response) => {
|
|
@@ -5300,14 +5522,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5300
5522
|
Metrics.postEvent({event: eventType.ALERT_DISPLAYED, meeting: this});
|
|
5301
5523
|
|
|
5302
5524
|
return Promise.resolve({
|
|
5303
|
-
response
|
|
5525
|
+
response,
|
|
5304
5526
|
});
|
|
5305
5527
|
});
|
|
5306
5528
|
}
|
|
5307
5529
|
|
|
5308
5530
|
// TODO: outside of 1:1 incoming, and all outgoing calls
|
|
5309
5531
|
return Promise.resolve({
|
|
5310
|
-
message: 'noop'
|
|
5532
|
+
message: 'noop',
|
|
5311
5533
|
});
|
|
5312
5534
|
}
|
|
5313
5535
|
|
|
@@ -5319,15 +5541,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5319
5541
|
* @memberof Meeting
|
|
5320
5542
|
*/
|
|
5321
5543
|
public decline(reason: string) {
|
|
5322
|
-
return MeetingUtil.declineMeeting(this, reason)
|
|
5323
|
-
|
|
5544
|
+
return MeetingUtil.declineMeeting(this, reason)
|
|
5545
|
+
.then((decline) => {
|
|
5546
|
+
this.meetingFiniteStateMachine.decline();
|
|
5324
5547
|
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5548
|
+
return Promise.resolve(decline);
|
|
5549
|
+
})
|
|
5550
|
+
.catch((error) => {
|
|
5551
|
+
this.meetingFiniteStateMachine.fail(error);
|
|
5328
5552
|
|
|
5329
|
-
|
|
5330
|
-
|
|
5553
|
+
return Promise.reject(error);
|
|
5554
|
+
});
|
|
5331
5555
|
}
|
|
5332
5556
|
|
|
5333
5557
|
/**
|
|
@@ -5338,8 +5562,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5338
5562
|
* @public
|
|
5339
5563
|
* @memberof Meeting
|
|
5340
5564
|
*/
|
|
5341
|
-
public leave(options: {
|
|
5342
|
-
Metrics.postEvent({
|
|
5565
|
+
public leave(options: {resourceId?: string; reason?: any} = {} as any) {
|
|
5566
|
+
Metrics.postEvent({
|
|
5567
|
+
event: eventType.LEAVE,
|
|
5568
|
+
meeting: this,
|
|
5569
|
+
data: {trigger: trigger.USER_INTERACTION, canProceed: false},
|
|
5570
|
+
});
|
|
5343
5571
|
const leaveReason = options.reason || MEETING_REMOVED_REASON.CLIENT_LEAVE_REQUEST;
|
|
5344
5572
|
|
|
5345
5573
|
LoggerProxy.logger.log('Meeting:index#leave --> Leaving a meeting');
|
|
@@ -5354,7 +5582,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5354
5582
|
this,
|
|
5355
5583
|
{
|
|
5356
5584
|
file: 'meeting/index',
|
|
5357
|
-
function: 'leave'
|
|
5585
|
+
function: 'leave',
|
|
5358
5586
|
},
|
|
5359
5587
|
EVENTS.REQUEST_UPLOAD_LOGS,
|
|
5360
5588
|
this
|
|
@@ -5367,19 +5595,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5367
5595
|
this,
|
|
5368
5596
|
{
|
|
5369
5597
|
file: 'meeting/index',
|
|
5370
|
-
function: 'leave'
|
|
5598
|
+
function: 'leave',
|
|
5371
5599
|
},
|
|
5372
5600
|
EVENTS.DESTROY_MEETING,
|
|
5373
5601
|
{
|
|
5374
5602
|
reason: options.reason,
|
|
5375
|
-
meetingId: this.id
|
|
5603
|
+
meetingId: this.id,
|
|
5376
5604
|
}
|
|
5377
5605
|
);
|
|
5378
5606
|
}
|
|
5379
5607
|
LoggerProxy.logger.log('Meeting:index#leave --> LEAVE REASON ', leaveReason);
|
|
5380
5608
|
|
|
5381
5609
|
return leave;
|
|
5382
|
-
})
|
|
5610
|
+
})
|
|
5611
|
+
.catch((error) => {
|
|
5383
5612
|
this.meetingFiniteStateMachine.fail(error);
|
|
5384
5613
|
LoggerProxy.logger.error('Meeting:index#leave --> Failed to leave ', error);
|
|
5385
5614
|
// upload logs on leave irrespective of meeting delete
|
|
@@ -5387,21 +5616,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5387
5616
|
this,
|
|
5388
5617
|
{
|
|
5389
5618
|
file: 'meeting/index',
|
|
5390
|
-
function: 'leave'
|
|
5619
|
+
function: 'leave',
|
|
5391
5620
|
},
|
|
5392
5621
|
EVENTS.REQUEST_UPLOAD_LOGS,
|
|
5393
5622
|
this
|
|
5394
5623
|
);
|
|
5395
|
-
Metrics.sendBehavioralMetric(
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
code: error.code
|
|
5403
|
-
}
|
|
5404
|
-
);
|
|
5624
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_LEAVE_FAILURE, {
|
|
5625
|
+
correlation_id: this.correlationId,
|
|
5626
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
5627
|
+
reason: error.message,
|
|
5628
|
+
stack: error.stack,
|
|
5629
|
+
code: error.code,
|
|
5630
|
+
});
|
|
5405
5631
|
|
|
5406
5632
|
return Promise.reject(error);
|
|
5407
5633
|
});
|
|
@@ -5430,14 +5656,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5430
5656
|
personUrl: this.locusInfo.self.url,
|
|
5431
5657
|
deviceUrl: this.deviceUrl,
|
|
5432
5658
|
uri: whiteboard.url,
|
|
5433
|
-
resourceUrl: channelUrl
|
|
5659
|
+
resourceUrl: channelUrl,
|
|
5434
5660
|
};
|
|
5435
5661
|
|
|
5436
5662
|
if (resourceToken) {
|
|
5437
5663
|
body.resourceToken = resourceToken;
|
|
5438
5664
|
}
|
|
5439
5665
|
|
|
5440
|
-
return this.meetingRequest
|
|
5666
|
+
return this.meetingRequest
|
|
5667
|
+
.changeMeetingFloor(body)
|
|
5441
5668
|
.then(() => {
|
|
5442
5669
|
this.isSharing = false;
|
|
5443
5670
|
|
|
@@ -5446,16 +5673,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5446
5673
|
.catch((error) => {
|
|
5447
5674
|
LoggerProxy.logger.error('Meeting:index#startWhiteboardShare --> Error ', error);
|
|
5448
5675
|
|
|
5449
|
-
Metrics.sendBehavioralMetric(
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
board: {channelUrl}
|
|
5457
|
-
}
|
|
5458
|
-
);
|
|
5676
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_START_WHITEBOARD_SHARE_FAILURE, {
|
|
5677
|
+
correlation_id: this.correlationId,
|
|
5678
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
5679
|
+
reason: error.message,
|
|
5680
|
+
stack: error.stack,
|
|
5681
|
+
board: {channelUrl},
|
|
5682
|
+
});
|
|
5459
5683
|
|
|
5460
5684
|
return Promise.reject(error);
|
|
5461
5685
|
});
|
|
@@ -5477,12 +5701,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5477
5701
|
if (whiteboard) {
|
|
5478
5702
|
Metrics.postEvent({event: eventType.WHITEBOARD_SHARE_STOPPED, meeting: this});
|
|
5479
5703
|
|
|
5480
|
-
return this.meetingRequest
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5704
|
+
return this.meetingRequest
|
|
5705
|
+
.changeMeetingFloor({
|
|
5706
|
+
disposition: FLOOR_ACTION.RELEASED,
|
|
5707
|
+
personUrl: this.locusInfo.self.url,
|
|
5708
|
+
deviceUrl: this.deviceUrl,
|
|
5709
|
+
uri: whiteboard.url,
|
|
5710
|
+
})
|
|
5486
5711
|
.catch((error) => {
|
|
5487
5712
|
LoggerProxy.logger.error('Meeting:index#stopWhiteboardShare --> Error ', error);
|
|
5488
5713
|
|
|
@@ -5494,14 +5719,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5494
5719
|
locus_id: this.locusUrl.split('/').pop(),
|
|
5495
5720
|
reason: error.message,
|
|
5496
5721
|
stack: error.stack,
|
|
5497
|
-
board: {channelUrl}
|
|
5722
|
+
board: {channelUrl},
|
|
5498
5723
|
}
|
|
5499
5724
|
);
|
|
5500
5725
|
|
|
5501
5726
|
return Promise.reject(error);
|
|
5502
5727
|
})
|
|
5503
|
-
.finally(() => {
|
|
5504
|
-
});
|
|
5728
|
+
.finally(() => {});
|
|
5505
5729
|
}
|
|
5506
5730
|
|
|
5507
5731
|
return Promise.reject(new ParameterError('Cannot stop share without whiteboard.'));
|
|
@@ -5516,16 +5740,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5516
5740
|
private requestScreenShareFloor() {
|
|
5517
5741
|
const content = this.locusInfo.mediaShares.find((element) => element.name === CONTENT);
|
|
5518
5742
|
|
|
5519
|
-
if (content &&
|
|
5743
|
+
if (content && this.shareStatus !== SHARE_STATUS.LOCAL_SHARE_ACTIVE) {
|
|
5520
5744
|
Metrics.postEvent({event: eventType.SHARE_INITIATED, meeting: this});
|
|
5521
5745
|
|
|
5522
|
-
return this.meetingRequest
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5746
|
+
return this.meetingRequest
|
|
5747
|
+
.changeMeetingFloor({
|
|
5748
|
+
disposition: FLOOR_ACTION.GRANTED,
|
|
5749
|
+
personUrl: this.locusInfo.self.url,
|
|
5750
|
+
deviceUrl: this.deviceUrl,
|
|
5751
|
+
uri: content.url,
|
|
5752
|
+
resourceUrl: this.resourceUrl,
|
|
5753
|
+
})
|
|
5529
5754
|
.then(() => {
|
|
5530
5755
|
this.isSharing = true;
|
|
5531
5756
|
|
|
@@ -5534,15 +5759,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5534
5759
|
.catch((error) => {
|
|
5535
5760
|
LoggerProxy.logger.error('Meeting:index#share --> Error ', error);
|
|
5536
5761
|
|
|
5537
|
-
Metrics.sendBehavioralMetric(
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
stack: error.stack
|
|
5544
|
-
}
|
|
5545
|
-
);
|
|
5762
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_SHARE_FAILURE, {
|
|
5763
|
+
correlation_id: this.correlationId,
|
|
5764
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
5765
|
+
reason: error.message,
|
|
5766
|
+
stack: error.stack,
|
|
5767
|
+
});
|
|
5546
5768
|
|
|
5547
5769
|
return Promise.reject(error);
|
|
5548
5770
|
});
|
|
@@ -5563,7 +5785,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5563
5785
|
return this.updateShare({
|
|
5564
5786
|
sendShare: false,
|
|
5565
5787
|
receiveShare: this.mediaProperties.mediaDirection.receiveShare,
|
|
5566
|
-
...options
|
|
5788
|
+
...options,
|
|
5567
5789
|
});
|
|
5568
5790
|
}
|
|
5569
5791
|
|
|
@@ -5576,7 +5798,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5576
5798
|
private releaseScreenShareFloor() {
|
|
5577
5799
|
const content = this.locusInfo.mediaShares.find((element) => element.name === CONTENT);
|
|
5578
5800
|
|
|
5579
|
-
if (content &&
|
|
5801
|
+
if (content && this.mediaProperties.mediaDirection.sendShare) {
|
|
5580
5802
|
Metrics.postEvent({event: eventType.SHARE_STOPPED, meeting: this});
|
|
5581
5803
|
Media.stopTracks(this.mediaProperties.shareTrack);
|
|
5582
5804
|
|
|
@@ -5587,25 +5809,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5587
5809
|
return Promise.resolve();
|
|
5588
5810
|
}
|
|
5589
5811
|
|
|
5590
|
-
return this.meetingRequest
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5812
|
+
return this.meetingRequest
|
|
5813
|
+
.changeMeetingFloor({
|
|
5814
|
+
disposition: FLOOR_ACTION.RELEASED,
|
|
5815
|
+
personUrl: this.locusInfo.self.url,
|
|
5816
|
+
deviceUrl: this.deviceUrl,
|
|
5817
|
+
uri: content.url,
|
|
5818
|
+
resourceUrl: this.resourceUrl,
|
|
5819
|
+
})
|
|
5597
5820
|
.catch((error) => {
|
|
5598
5821
|
LoggerProxy.logger.error('Meeting:index#releaseScreenShareFloor --> Error ', error);
|
|
5599
5822
|
|
|
5600
|
-
Metrics.sendBehavioralMetric(
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
stack: error.stack
|
|
5607
|
-
}
|
|
5608
|
-
);
|
|
5823
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.STOP_FLOOR_REQUEST_FAILURE, {
|
|
5824
|
+
correlation_id: this.correlationId,
|
|
5825
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
5826
|
+
reason: error.message,
|
|
5827
|
+
stack: error.stack,
|
|
5828
|
+
});
|
|
5609
5829
|
|
|
5610
5830
|
return Promise.reject(error);
|
|
5611
5831
|
})
|
|
@@ -5700,18 +5920,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5700
5920
|
public sendDTMF(tones: string) {
|
|
5701
5921
|
if (this.locusInfo && this.locusInfo.self) {
|
|
5702
5922
|
if (this.locusInfo.self.enableDTMF) {
|
|
5703
|
-
return this.meetingRequest
|
|
5704
|
-
.
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
});
|
|
5923
|
+
return this.meetingRequest.sendDTMF({
|
|
5924
|
+
locusUrl: this.locusInfo.self.url,
|
|
5925
|
+
deviceUrl: this.deviceUrl,
|
|
5926
|
+
tones,
|
|
5927
|
+
});
|
|
5709
5928
|
}
|
|
5710
5929
|
|
|
5711
|
-
return this.rejectWithErrorLog(
|
|
5930
|
+
return this.rejectWithErrorLog(
|
|
5931
|
+
'Meeting:index#sendDTMF --> cannot send DTMF, meeting does not have DTMF enabled'
|
|
5932
|
+
);
|
|
5712
5933
|
}
|
|
5713
5934
|
|
|
5714
|
-
return this.rejectWithErrorLog(
|
|
5935
|
+
return this.rejectWithErrorLog(
|
|
5936
|
+
'Meeting:index#sendDTMF --> cannot send DTMF, meeting does not have a connection to the "locus" call control service. Have you joined?'
|
|
5937
|
+
);
|
|
5715
5938
|
}
|
|
5716
5939
|
|
|
5717
5940
|
/**
|
|
@@ -5748,12 +5971,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5748
5971
|
|
|
5749
5972
|
// TODO: We need a real time value for Audio, Video and Share send indicator
|
|
5750
5973
|
if (mediaDirection.receiveVideo !== true || !remoteVideoTrack) {
|
|
5751
|
-
return this.rejectWithErrorLog(
|
|
5974
|
+
return this.rejectWithErrorLog(
|
|
5975
|
+
'Meeting:index#changeVideoLayout --> cannot change video layout, you are not recieving any video/share stream'
|
|
5976
|
+
);
|
|
5752
5977
|
}
|
|
5753
5978
|
|
|
5754
5979
|
if (layoutType) {
|
|
5755
5980
|
if (!LAYOUT_TYPES.includes(layoutType)) {
|
|
5756
|
-
this.rejectWithErrorLog(
|
|
5981
|
+
this.rejectWithErrorLog(
|
|
5982
|
+
'Meeting:index#changeVideoLayout --> cannot change video layout, invalid layoutType recieved.'
|
|
5983
|
+
);
|
|
5757
5984
|
}
|
|
5758
5985
|
|
|
5759
5986
|
layoutInfo.layoutType = layoutType;
|
|
@@ -5779,15 +6006,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5779
6006
|
const contentHeight = Math.round(content.height);
|
|
5780
6007
|
|
|
5781
6008
|
// Stop any "twitching" caused by very slight size changes
|
|
5782
|
-
if (
|
|
6009
|
+
if (
|
|
6010
|
+
!this.lastVideoLayoutInfo.content ||
|
|
5783
6011
|
Math.abs(this.lastVideoLayoutInfo.content.height - contentHeight) > 2 ||
|
|
5784
6012
|
Math.abs(this.lastVideoLayoutInfo.content.width - contentWidth) > 2
|
|
5785
6013
|
) {
|
|
5786
6014
|
layoutInfo.content = {width: contentWidth, height: contentHeight};
|
|
5787
6015
|
}
|
|
5788
|
-
}
|
|
5789
|
-
|
|
5790
|
-
|
|
6016
|
+
} else {
|
|
6017
|
+
return this.rejectWithErrorLog(
|
|
6018
|
+
'Meeting:index#changeVideoLayout --> unable to send renderInfo for content, you are not receiving remote share'
|
|
6019
|
+
);
|
|
5791
6020
|
}
|
|
5792
6021
|
}
|
|
5793
6022
|
|
|
@@ -5806,7 +6035,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5806
6035
|
},
|
|
5807
6036
|
EVENT_TRIGGERS.MEETING_CONTROLS_LAYOUT_UPDATE,
|
|
5808
6037
|
{
|
|
5809
|
-
layout: envelope.layout
|
|
6038
|
+
layout: envelope.layout,
|
|
5810
6039
|
}
|
|
5811
6040
|
);
|
|
5812
6041
|
});
|
|
@@ -5817,7 +6046,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5817
6046
|
deviceUrl: this.deviceUrl,
|
|
5818
6047
|
layoutType,
|
|
5819
6048
|
main: layoutInfo.main,
|
|
5820
|
-
content: layoutInfo.content
|
|
6049
|
+
content: layoutInfo.content,
|
|
5821
6050
|
})
|
|
5822
6051
|
.then((response) => {
|
|
5823
6052
|
if (response && response.body && response.body.locus) {
|
|
@@ -5844,12 +6073,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5844
6073
|
}
|
|
5845
6074
|
|
|
5846
6075
|
if (!this.mediaProperties.mediaDirection.sendVideo) {
|
|
5847
|
-
return this.rejectWithErrorLog(
|
|
6076
|
+
return this.rejectWithErrorLog(
|
|
6077
|
+
'Meeting:index#setLocalVideoQuality --> unable to change video quality, sendVideo is disabled'
|
|
6078
|
+
);
|
|
5848
6079
|
}
|
|
5849
6080
|
|
|
5850
6081
|
// If level is already the same, don't do anything
|
|
5851
6082
|
if (level === this.mediaProperties.localQualityLevel) {
|
|
5852
|
-
LoggerProxy.logger.warn(
|
|
6083
|
+
LoggerProxy.logger.warn(
|
|
6084
|
+
`Meeting:index#setLocalQualityLevel --> Quality already set to ${level}`
|
|
6085
|
+
);
|
|
5853
6086
|
|
|
5854
6087
|
return Promise.resolve();
|
|
5855
6088
|
}
|
|
@@ -5860,25 +6093,27 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5860
6093
|
const mediaDirection = {
|
|
5861
6094
|
sendAudio: this.mediaProperties.mediaDirection.sendAudio,
|
|
5862
6095
|
sendVideo: this.mediaProperties.mediaDirection.sendVideo,
|
|
5863
|
-
sendShare: this.mediaProperties.mediaDirection.sendShare
|
|
6096
|
+
sendShare: this.mediaProperties.mediaDirection.sendShare,
|
|
5864
6097
|
};
|
|
5865
6098
|
|
|
5866
6099
|
// When changing local video quality level
|
|
5867
6100
|
// Need to stop current track first as chrome doesn't support resolution upscaling(for eg. changing 480p to 720p)
|
|
5868
6101
|
// Without feeding it a new track
|
|
5869
6102
|
// open bug link: https://bugs.chromium.org/p/chromium/issues/detail?id=943469
|
|
5870
|
-
if (isBrowser('chrome') && this.mediaProperties.videoTrack)
|
|
6103
|
+
if (isBrowser('chrome') && this.mediaProperties.videoTrack)
|
|
6104
|
+
Media.stopTracks(this.mediaProperties.videoTrack);
|
|
5871
6105
|
|
|
5872
|
-
return this.getMediaStreams(mediaDirection, VIDEO_RESOLUTIONS[level])
|
|
5873
|
-
|
|
6106
|
+
return this.getMediaStreams(mediaDirection, VIDEO_RESOLUTIONS[level]).then(
|
|
6107
|
+
async ([localStream]) => {
|
|
5874
6108
|
await this.updateVideo({
|
|
5875
6109
|
sendVideo: true,
|
|
5876
6110
|
receiveVideo: true,
|
|
5877
|
-
stream: localStream
|
|
6111
|
+
stream: localStream,
|
|
5878
6112
|
});
|
|
5879
6113
|
|
|
5880
6114
|
return localStream;
|
|
5881
|
-
}
|
|
6115
|
+
}
|
|
6116
|
+
);
|
|
5882
6117
|
}
|
|
5883
6118
|
|
|
5884
6119
|
/**
|
|
@@ -5890,16 +6125,25 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5890
6125
|
LoggerProxy.logger.log(`Meeting:index#setRemoteQualityLevel --> Setting quality to ${level}`);
|
|
5891
6126
|
|
|
5892
6127
|
if (!QUALITY_LEVELS[level]) {
|
|
5893
|
-
return this.rejectWithErrorLog(
|
|
6128
|
+
return this.rejectWithErrorLog(
|
|
6129
|
+
`Meeting:index#setRemoteQualityLevel --> ${level} not defined`
|
|
6130
|
+
);
|
|
5894
6131
|
}
|
|
5895
6132
|
|
|
5896
|
-
if (
|
|
5897
|
-
|
|
6133
|
+
if (
|
|
6134
|
+
!this.mediaProperties.mediaDirection.receiveAudio &&
|
|
6135
|
+
!this.mediaProperties.mediaDirection.receiveVideo
|
|
6136
|
+
) {
|
|
6137
|
+
return this.rejectWithErrorLog(
|
|
6138
|
+
'Meeting:index#setRemoteQualityLevel --> unable to change remote quality, receiveVideo and receiveAudio is disabled'
|
|
6139
|
+
);
|
|
5898
6140
|
}
|
|
5899
6141
|
|
|
5900
6142
|
// If level is already the same, don't do anything
|
|
5901
6143
|
if (level === this.mediaProperties.remoteQualityLevel) {
|
|
5902
|
-
LoggerProxy.logger.warn(
|
|
6144
|
+
LoggerProxy.logger.warn(
|
|
6145
|
+
`Meeting:index#setRemoteQualityLevel --> Quality already set to ${level}`
|
|
6146
|
+
);
|
|
5903
6147
|
|
|
5904
6148
|
return Promise.resolve();
|
|
5905
6149
|
}
|
|
@@ -5925,7 +6169,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5925
6169
|
|
|
5926
6170
|
const previousLevel = {
|
|
5927
6171
|
local: this.mediaProperties.localQualityLevel,
|
|
5928
|
-
remote: this.mediaProperties.remoteQualityLevel
|
|
6172
|
+
remote: this.mediaProperties.remoteQualityLevel,
|
|
5929
6173
|
};
|
|
5930
6174
|
|
|
5931
6175
|
// If level is already the same, don't do anything
|
|
@@ -5933,7 +6177,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5933
6177
|
level === this.mediaProperties.localQualityLevel &&
|
|
5934
6178
|
level === this.mediaProperties.remoteQualityLevel
|
|
5935
6179
|
) {
|
|
5936
|
-
LoggerProxy.logger.warn(
|
|
6180
|
+
LoggerProxy.logger.warn(
|
|
6181
|
+
`Meeting:index#setMeetingQuality --> Quality already set to ${level}`
|
|
6182
|
+
);
|
|
5937
6183
|
|
|
5938
6184
|
return Promise.resolve();
|
|
5939
6185
|
}
|
|
@@ -5943,9 +6189,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5943
6189
|
|
|
5944
6190
|
return (sendVideo ? this.setLocalVideoQuality(level) : Promise.resolve())
|
|
5945
6191
|
.then(() =>
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
Promise.resolve()))
|
|
6192
|
+
receiveAudio || receiveVideo ? this.setRemoteQualityLevel(level) : Promise.resolve()
|
|
6193
|
+
)
|
|
5949
6194
|
.catch((error) => {
|
|
5950
6195
|
// From troubleshooting it seems that the stream itself doesn't change the max-fs if the peer connection isn't stable
|
|
5951
6196
|
this.mediaProperties.setLocalQualityLevel(previousLevel.local);
|
|
@@ -5959,10 +6204,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5959
6204
|
correlation_id: this.correlationId,
|
|
5960
6205
|
locus_id: this.locusUrl.split('/').pop(),
|
|
5961
6206
|
reason: error.message,
|
|
5962
|
-
stack: error.stack
|
|
6207
|
+
stack: error.stack,
|
|
5963
6208
|
},
|
|
5964
6209
|
{
|
|
5965
|
-
type: error.name
|
|
6210
|
+
type: error.name,
|
|
5966
6211
|
}
|
|
5967
6212
|
);
|
|
5968
6213
|
|
|
@@ -5971,23 +6216,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5971
6216
|
}
|
|
5972
6217
|
|
|
5973
6218
|
/**
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
6219
|
+
*
|
|
6220
|
+
* NOTE: this method can only be used with transcoded meetings, for multistream use publishTrack()
|
|
6221
|
+
*
|
|
6222
|
+
* @param {Object} options parameter
|
|
6223
|
+
* @param {Boolean} options.sendAudio send audio from the display share
|
|
6224
|
+
* @param {Boolean} options.sendShare send video from the display share
|
|
6225
|
+
* @param {Object} options.sharePreferences
|
|
6226
|
+
* @param {MediaTrackConstraints} options.sharePreferences.shareConstraints constraints to apply to video
|
|
6227
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints}
|
|
6228
|
+
* @param {Boolean} options.sharePreferences.highFrameRate if shareConstraints isn't provided, set default values based off of this boolean
|
|
6229
|
+
* @returns {Promise}
|
|
6230
|
+
*/
|
|
5986
6231
|
shareScreen(
|
|
5987
6232
|
options: {
|
|
5988
6233
|
sendAudio: boolean;
|
|
5989
6234
|
sendShare: boolean;
|
|
5990
|
-
sharePreferences: {
|
|
6235
|
+
sharePreferences: {shareConstraints: MediaTrackConstraints};
|
|
5991
6236
|
} = {} as any
|
|
5992
6237
|
) {
|
|
5993
6238
|
LoggerProxy.logger.log('Meeting:index#shareScreen --> Getting local share');
|
|
@@ -5995,16 +6240,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5995
6240
|
const shareConstraints = {
|
|
5996
6241
|
sendShare: true,
|
|
5997
6242
|
sendAudio: false,
|
|
5998
|
-
...options
|
|
6243
|
+
...options,
|
|
5999
6244
|
};
|
|
6000
6245
|
|
|
6001
6246
|
// @ts-ignore - config coming from registerPlugin
|
|
6002
6247
|
return Media.getDisplayMedia(shareConstraints, this.config)
|
|
6003
|
-
.then((shareStream) =>
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6248
|
+
.then((shareStream) =>
|
|
6249
|
+
this.updateShare({
|
|
6250
|
+
sendShare: true,
|
|
6251
|
+
receiveShare: this.mediaProperties.mediaDirection.receiveShare,
|
|
6252
|
+
stream: shareStream,
|
|
6253
|
+
})
|
|
6254
|
+
)
|
|
6008
6255
|
.catch((error) => {
|
|
6009
6256
|
// Whenever there is a failure when trying to access a user's display
|
|
6010
6257
|
// report it as an Behavioral metric
|
|
@@ -6018,10 +6265,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6018
6265
|
correlation_id: this.correlationId,
|
|
6019
6266
|
locus_id: this.locusUrl.split('/').pop(),
|
|
6020
6267
|
reason: error.message,
|
|
6021
|
-
stack: error.stack
|
|
6268
|
+
stack: error.stack,
|
|
6022
6269
|
};
|
|
6023
6270
|
const metadata = {
|
|
6024
|
-
type: error.name
|
|
6271
|
+
type: error.name,
|
|
6025
6272
|
};
|
|
6026
6273
|
|
|
6027
6274
|
Metrics.sendBehavioralMetric(metricName, data, metadata);
|
|
@@ -6039,28 +6286,29 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6039
6286
|
private handleShareTrackEnded(localShare: MediaStream) {
|
|
6040
6287
|
if (this.wirelessShare) {
|
|
6041
6288
|
this.leave({reason: MEETING_REMOVED_REASON.USER_ENDED_SHARE_STREAMS});
|
|
6042
|
-
}
|
|
6043
|
-
else {
|
|
6289
|
+
} else {
|
|
6044
6290
|
// Skip checking for a stable peerConnection
|
|
6045
6291
|
// to allow immediately stopping screenshare
|
|
6046
6292
|
this.stopShare({
|
|
6047
|
-
skipSignalingCheck: true
|
|
6048
|
-
})
|
|
6049
|
-
.
|
|
6050
|
-
|
|
6051
|
-
|
|
6293
|
+
skipSignalingCheck: true,
|
|
6294
|
+
}).catch((error) => {
|
|
6295
|
+
LoggerProxy.logger.log(
|
|
6296
|
+
'Meeting:index#handleShareTrackEnded --> Error stopping share: ',
|
|
6297
|
+
error
|
|
6298
|
+
);
|
|
6299
|
+
});
|
|
6052
6300
|
}
|
|
6053
6301
|
|
|
6054
6302
|
Trigger.trigger(
|
|
6055
6303
|
this,
|
|
6056
6304
|
{
|
|
6057
6305
|
file: 'meeting/index',
|
|
6058
|
-
function: 'handleShareTrackEnded'
|
|
6306
|
+
function: 'handleShareTrackEnded',
|
|
6059
6307
|
},
|
|
6060
6308
|
EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
|
|
6061
6309
|
{
|
|
6062
6310
|
type: EVENT_TYPES.LOCAL_SHARE,
|
|
6063
|
-
stream: localShare
|
|
6311
|
+
stream: localShare,
|
|
6064
6312
|
}
|
|
6065
6313
|
);
|
|
6066
6314
|
}
|
|
@@ -6081,12 +6329,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6081
6329
|
this,
|
|
6082
6330
|
{
|
|
6083
6331
|
file: 'meeting/index',
|
|
6084
|
-
function: 'addMedia'
|
|
6332
|
+
function: 'addMedia',
|
|
6085
6333
|
},
|
|
6086
6334
|
EVENT_TRIGGERS.NETWORK_QUALITY,
|
|
6087
6335
|
{
|
|
6088
6336
|
networkQualityScore: res.networkQualityScore,
|
|
6089
|
-
mediaType: res.mediaType
|
|
6337
|
+
mediaType: res.mediaType,
|
|
6090
6338
|
}
|
|
6091
6339
|
);
|
|
6092
6340
|
}
|
|
@@ -6098,7 +6346,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6098
6346
|
* @private
|
|
6099
6347
|
* @returns {undefined}
|
|
6100
6348
|
*/
|
|
6101
|
-
private handleMediaLogging({
|
|
6349
|
+
private handleMediaLogging({audioTrack, videoTrack}: any) {
|
|
6102
6350
|
MeetingUtil.handleVideoLogging(videoTrack);
|
|
6103
6351
|
MeetingUtil.handleAudioLogging(audioTrack);
|
|
6104
6352
|
}
|
|
@@ -6128,7 +6376,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6128
6376
|
const start = this[`startSetupDelay${typeMedia}`];
|
|
6129
6377
|
const end = this[`endSetupDelay${typeMedia}`];
|
|
6130
6378
|
|
|
6131
|
-
return
|
|
6379
|
+
return start && end ? end - start : undefined;
|
|
6132
6380
|
}
|
|
6133
6381
|
|
|
6134
6382
|
/**
|
|
@@ -6156,14 +6404,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6156
6404
|
const start = this[`startSendingMediaDelay${typeMedia}`];
|
|
6157
6405
|
const end = this[`endSendingMediaDelay${typeMedia}`];
|
|
6158
6406
|
|
|
6159
|
-
return
|
|
6407
|
+
return start && end ? end - start : undefined;
|
|
6160
6408
|
}
|
|
6161
6409
|
|
|
6162
6410
|
/**
|
|
6163
6411
|
*
|
|
6164
6412
|
* @returns {undefined}
|
|
6165
6413
|
*/
|
|
6166
|
-
|
|
6414
|
+
setStartLocalSDPGenRemoteSDPRecvDelay() {
|
|
6167
6415
|
if (!this.startLocalSDPGenRemoteSDPRecvDelay) {
|
|
6168
6416
|
this.startLocalSDPGenRemoteSDPRecvDelay = performance.now();
|
|
6169
6417
|
this.endLocalSDPGenRemoteSDPRecvDelay = undefined;
|
|
@@ -6191,9 +6439,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6191
6439
|
if (start && end) {
|
|
6192
6440
|
const calculatedDelay = end - start;
|
|
6193
6441
|
|
|
6194
|
-
return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ?
|
|
6195
|
-
undefined :
|
|
6196
|
-
calculatedDelay;
|
|
6442
|
+
return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ? undefined : calculatedDelay;
|
|
6197
6443
|
}
|
|
6198
6444
|
|
|
6199
6445
|
return undefined;
|
|
@@ -6227,9 +6473,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6227
6473
|
if (start && end) {
|
|
6228
6474
|
const calculatedDelay = end - start;
|
|
6229
6475
|
|
|
6230
|
-
return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ?
|
|
6231
|
-
undefined :
|
|
6232
|
-
calculatedDelay;
|
|
6476
|
+
return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ? undefined : calculatedDelay;
|
|
6233
6477
|
}
|
|
6234
6478
|
|
|
6235
6479
|
return undefined;
|
|
@@ -6263,9 +6507,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6263
6507
|
if (start && end) {
|
|
6264
6508
|
const calculatedDelay = end - start;
|
|
6265
6509
|
|
|
6266
|
-
return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ?
|
|
6267
|
-
undefined :
|
|
6268
|
-
calculatedDelay;
|
|
6510
|
+
return calculatedDelay > METRICS_JOIN_TIMES_MAX_DURATION ? undefined : calculatedDelay;
|
|
6269
6511
|
}
|
|
6270
6512
|
|
|
6271
6513
|
return undefined;
|
|
@@ -6279,10 +6521,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6279
6521
|
const start = this.startCallInitiateJoinReq;
|
|
6280
6522
|
const end = this.endJoinReqResp;
|
|
6281
6523
|
|
|
6282
|
-
return
|
|
6524
|
+
return start && end ? end - start : undefined;
|
|
6283
6525
|
}
|
|
6284
6526
|
|
|
6285
|
-
|
|
6286
6527
|
/**
|
|
6287
6528
|
* End the current meeting for all
|
|
6288
6529
|
* @returns {Promise}
|
|
@@ -6290,16 +6531,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6290
6531
|
* @memberof Meeting
|
|
6291
6532
|
*/
|
|
6292
6533
|
public endMeetingForAll() {
|
|
6293
|
-
Metrics.postEvent({
|
|
6534
|
+
Metrics.postEvent({
|
|
6535
|
+
event: eventType.LEAVE,
|
|
6536
|
+
meeting: this,
|
|
6537
|
+
data: {trigger: trigger.USER_INTERACTION, canProceed: false},
|
|
6538
|
+
});
|
|
6294
6539
|
|
|
6295
6540
|
LoggerProxy.logger.log('Meeting:index#endMeetingForAll --> End meeting for All');
|
|
6296
|
-
Metrics.sendBehavioralMetric(
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
locus_id: this.locusId
|
|
6301
|
-
}
|
|
6302
|
-
);
|
|
6541
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_END_ALL_INITIATED, {
|
|
6542
|
+
correlation_id: this.correlationId,
|
|
6543
|
+
locus_id: this.locusId,
|
|
6544
|
+
});
|
|
6303
6545
|
|
|
6304
6546
|
return MeetingUtil.endMeetingForAll(this)
|
|
6305
6547
|
.then((end) => {
|
|
@@ -6311,36 +6553,37 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6311
6553
|
this,
|
|
6312
6554
|
{
|
|
6313
6555
|
file: 'meeting/index',
|
|
6314
|
-
function: 'endMeetingForAll'
|
|
6556
|
+
function: 'endMeetingForAll',
|
|
6315
6557
|
},
|
|
6316
6558
|
EVENTS.REQUEST_UPLOAD_LOGS,
|
|
6317
6559
|
this
|
|
6318
6560
|
);
|
|
6319
6561
|
|
|
6320
6562
|
return end;
|
|
6321
|
-
})
|
|
6563
|
+
})
|
|
6564
|
+
.catch((error) => {
|
|
6322
6565
|
this.meetingFiniteStateMachine.fail(error);
|
|
6323
|
-
LoggerProxy.logger.error(
|
|
6566
|
+
LoggerProxy.logger.error(
|
|
6567
|
+
'Meeting:index#endMeetingForAll --> Failed to end meeting ',
|
|
6568
|
+
error
|
|
6569
|
+
);
|
|
6324
6570
|
// upload logs on leave irrespective of meeting delete
|
|
6325
6571
|
Trigger.trigger(
|
|
6326
6572
|
this,
|
|
6327
6573
|
{
|
|
6328
6574
|
file: 'meeting/index',
|
|
6329
|
-
function: 'endMeetingForAll'
|
|
6575
|
+
function: 'endMeetingForAll',
|
|
6330
6576
|
},
|
|
6331
6577
|
EVENTS.REQUEST_UPLOAD_LOGS,
|
|
6332
6578
|
this
|
|
6333
6579
|
);
|
|
6334
|
-
Metrics.sendBehavioralMetric(
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
code: error.code
|
|
6342
|
-
}
|
|
6343
|
-
);
|
|
6580
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_END_ALL_FAILURE, {
|
|
6581
|
+
correlation_id: this.correlationId,
|
|
6582
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
6583
|
+
reason: error.message,
|
|
6584
|
+
stack: error.stack,
|
|
6585
|
+
code: error.code,
|
|
6586
|
+
});
|
|
6344
6587
|
|
|
6345
6588
|
return Promise.reject(error);
|
|
6346
6589
|
});
|
|
@@ -6390,11 +6633,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6390
6633
|
LoggerProxy.logger.info('Meeting:index#internal_enableBNR. Internal enable BNR called');
|
|
6391
6634
|
const bnrAudioTrack = await WebRTCMedia.Effects.BNR.enableBNR(audioTrack);
|
|
6392
6635
|
|
|
6393
|
-
LoggerProxy.logger.info(
|
|
6636
|
+
LoggerProxy.logger.info(
|
|
6637
|
+
'Meeting:index#internal_enableBNR. BNR enabled track obtained from WebRTC & returned as stream'
|
|
6638
|
+
);
|
|
6394
6639
|
|
|
6395
6640
|
return bnrAudioTrack;
|
|
6396
|
-
}
|
|
6397
|
-
catch (error) {
|
|
6641
|
+
} catch (error) {
|
|
6398
6642
|
LoggerProxy.logger.error('Meeting:index#internal_enableBNR.', error);
|
|
6399
6643
|
throw error;
|
|
6400
6644
|
}
|
|
@@ -6407,7 +6651,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6407
6651
|
* @memberof Meeting
|
|
6408
6652
|
*/
|
|
6409
6653
|
public enableBNR() {
|
|
6410
|
-
if (
|
|
6654
|
+
if (
|
|
6655
|
+
typeof this.mediaProperties === 'undefined' ||
|
|
6656
|
+
typeof this.mediaProperties.audioTrack === 'undefined'
|
|
6657
|
+
) {
|
|
6411
6658
|
return Promise.reject(new Error("Meeting doesn't have an audioTrack attached"));
|
|
6412
6659
|
}
|
|
6413
6660
|
|
|
@@ -6419,20 +6666,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6419
6666
|
|
|
6420
6667
|
const LOG_HEADER = 'Meeting:index#enableBNR -->';
|
|
6421
6668
|
|
|
6422
|
-
return logRequest(
|
|
6423
|
-
.
|
|
6424
|
-
|
|
6669
|
+
return logRequest(
|
|
6670
|
+
this.effects
|
|
6671
|
+
.handleClientRequest(true, this)
|
|
6672
|
+
.then((res) => {
|
|
6673
|
+
LoggerProxy.logger.info('Meeting:index#enableBNR. Enable bnr completed');
|
|
6425
6674
|
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6675
|
+
return res;
|
|
6676
|
+
})
|
|
6677
|
+
.catch((error) => {
|
|
6678
|
+
throw error;
|
|
6679
|
+
}),
|
|
6680
|
+
{
|
|
6681
|
+
header: `${LOG_HEADER} enable bnr`,
|
|
6682
|
+
success: `${LOG_HEADER} enable bnr success`,
|
|
6683
|
+
failure: `${LOG_HEADER} enable bnr failure, `,
|
|
6684
|
+
}
|
|
6685
|
+
);
|
|
6436
6686
|
}
|
|
6437
6687
|
|
|
6438
6688
|
/**
|
|
@@ -6442,7 +6692,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6442
6692
|
* @memberof Meeting
|
|
6443
6693
|
*/
|
|
6444
6694
|
public disableBNR() {
|
|
6445
|
-
if (
|
|
6695
|
+
if (
|
|
6696
|
+
typeof this.mediaProperties === 'undefined' ||
|
|
6697
|
+
typeof this.mediaProperties.audioTrack === 'undefined'
|
|
6698
|
+
) {
|
|
6446
6699
|
return Promise.reject(new Error("Meeting doesn't have an audioTrack attached"));
|
|
6447
6700
|
}
|
|
6448
6701
|
|
|
@@ -6454,20 +6707,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6454
6707
|
|
|
6455
6708
|
const LOG_HEADER = 'Meeting:index#disableBNR -->';
|
|
6456
6709
|
|
|
6457
|
-
return logRequest(
|
|
6458
|
-
.
|
|
6459
|
-
|
|
6710
|
+
return logRequest(
|
|
6711
|
+
this.effects
|
|
6712
|
+
.handleClientRequest(false, this)
|
|
6713
|
+
.then((res) => {
|
|
6714
|
+
LoggerProxy.logger.info('Meeting:index#disableBNR. Disable bnr completed');
|
|
6460
6715
|
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6716
|
+
return res;
|
|
6717
|
+
})
|
|
6718
|
+
.catch((error) => {
|
|
6719
|
+
throw error;
|
|
6720
|
+
}),
|
|
6721
|
+
{
|
|
6722
|
+
header: `${LOG_HEADER} disable bnr`,
|
|
6723
|
+
success: `${LOG_HEADER} disable bnr success`,
|
|
6724
|
+
failure: `${LOG_HEADER} disable bnr failure, `,
|
|
6725
|
+
}
|
|
6726
|
+
);
|
|
6471
6727
|
}
|
|
6472
6728
|
|
|
6473
6729
|
/**
|
|
@@ -6478,22 +6734,30 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6478
6734
|
*/
|
|
6479
6735
|
startKeepAlive = () => {
|
|
6480
6736
|
if (this.keepAliveTimerId) {
|
|
6481
|
-
LoggerProxy.logger.warn(
|
|
6737
|
+
LoggerProxy.logger.warn(
|
|
6738
|
+
'Meeting:index#startKeepAlive --> keepAlive not started: keepAliveTimerId already exists'
|
|
6739
|
+
);
|
|
6482
6740
|
|
|
6483
6741
|
return;
|
|
6484
6742
|
}
|
|
6485
6743
|
if (!this.joinedWith?.keepAliveUrl) {
|
|
6486
|
-
LoggerProxy.logger.warn(
|
|
6744
|
+
LoggerProxy.logger.warn(
|
|
6745
|
+
'Meeting:index#startKeepAlive --> keepAlive not started: no keepAliveUrl'
|
|
6746
|
+
);
|
|
6487
6747
|
|
|
6488
6748
|
return;
|
|
6489
6749
|
}
|
|
6490
6750
|
if (!this.joinedWith?.keepAliveSecs) {
|
|
6491
|
-
LoggerProxy.logger.warn(
|
|
6751
|
+
LoggerProxy.logger.warn(
|
|
6752
|
+
'Meeting:index#startKeepAlive --> keepAlive not started: no keepAliveSecs'
|
|
6753
|
+
);
|
|
6492
6754
|
|
|
6493
6755
|
return;
|
|
6494
6756
|
}
|
|
6495
6757
|
if (this.joinedWith.keepAliveSecs <= 1) {
|
|
6496
|
-
LoggerProxy.logger.warn(
|
|
6758
|
+
LoggerProxy.logger.warn(
|
|
6759
|
+
'Meeting:index#startKeepAlive --> keepAlive not started: keepAliveSecs <= 1'
|
|
6760
|
+
);
|
|
6497
6761
|
|
|
6498
6762
|
return;
|
|
6499
6763
|
}
|
|
@@ -6501,13 +6765,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6501
6765
|
const keepAliveInterval = (this.joinedWith.keepAliveSecs - 1) * 750; // taken from UCF
|
|
6502
6766
|
|
|
6503
6767
|
this.keepAliveTimerId = setInterval(() => {
|
|
6504
|
-
this.meetingRequest.keepAlive({keepAliveUrl})
|
|
6505
|
-
.
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
});
|
|
6768
|
+
this.meetingRequest.keepAlive({keepAliveUrl}).catch((error) => {
|
|
6769
|
+
LoggerProxy.logger.warn(
|
|
6770
|
+
`Meeting:index#startKeepAlive --> Stopping sending keepAlives to ${keepAliveUrl} after error ${error}`
|
|
6771
|
+
);
|
|
6772
|
+
this.stopKeepAlive();
|
|
6773
|
+
});
|
|
6511
6774
|
}, keepAliveInterval);
|
|
6512
6775
|
};
|
|
6513
6776
|
|
|
@@ -6546,7 +6809,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6546
6809
|
const skinToneData = SkinTones[skinToneType] || SkinTones.normal;
|
|
6547
6810
|
const reaction: Reaction = {
|
|
6548
6811
|
...reactionData,
|
|
6549
|
-
tone: skinToneData
|
|
6812
|
+
tone: skinToneData,
|
|
6550
6813
|
};
|
|
6551
6814
|
|
|
6552
6815
|
if (reactionChannelUrl) {
|
|
@@ -6555,4 +6818,26 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6555
6818
|
|
|
6556
6819
|
return Promise.reject(new Error('Error sending reaction, service url not found.'));
|
|
6557
6820
|
}
|
|
6821
|
+
|
|
6822
|
+
/**
|
|
6823
|
+
* Method to enable or disable reactions inside the meeting.
|
|
6824
|
+
*
|
|
6825
|
+
* @param {boolean} enable - enable or disable reactions
|
|
6826
|
+
* @returns {Promise}
|
|
6827
|
+
* @public
|
|
6828
|
+
* @memberof Meeting
|
|
6829
|
+
*/
|
|
6830
|
+
public toggleReactions(enable: boolean) {
|
|
6831
|
+
const isEnabled = this.locusInfo?.controls?.reactions?.enabled;
|
|
6832
|
+
|
|
6833
|
+
if ((isEnabled && enable) || (!isEnabled && !enable)) {
|
|
6834
|
+
return Promise.resolve(`Reactions are already ${isEnabled ? 'enabled' : 'disabled'}.`);
|
|
6835
|
+
}
|
|
6836
|
+
|
|
6837
|
+
return this.meetingRequest.toggleReactions({
|
|
6838
|
+
enable,
|
|
6839
|
+
locusUrl: this.locusUrl,
|
|
6840
|
+
requestingParticipantId: this.members.selfId,
|
|
6841
|
+
});
|
|
6842
|
+
}
|
|
6558
6843
|
}
|