@webex/plugin-meetings 3.0.0-bnr.5 → 3.0.0-stream-classes.1
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/README.md +46 -8
- package/dist/annotation/annotation.types.js +7 -0
- package/dist/annotation/annotation.types.js.map +1 -0
- package/dist/annotation/constants.js +49 -0
- package/dist/annotation/constants.js.map +1 -0
- package/dist/annotation/index.js +342 -0
- package/dist/annotation/index.js.map +1 -0
- package/dist/breakouts/breakout.js +70 -32
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/events.js +45 -0
- package/dist/breakouts/events.js.map +1 -0
- package/dist/breakouts/index.js +422 -217
- package/dist/breakouts/index.js.map +1 -1
- package/dist/breakouts/utils.js +12 -1
- package/dist/breakouts/utils.js.map +1 -1
- package/dist/common/errors/webex-errors.js +3 -2
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/logs/logger-proxy.js +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.d.ts +1 -1
- package/dist/common/queue.js +24 -9
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +1 -7
- package/dist/config.js.map +1 -1
- package/dist/constants.js +118 -24
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +2 -0
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +19 -14
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/types.js.map +1 -1
- package/dist/controls-options-manager/util.js +80 -11
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/index.js +62 -20
- package/dist/index.js.map +1 -1
- package/dist/interpretation/collection.js +23 -0
- package/dist/interpretation/collection.js.map +1 -0
- package/dist/interpretation/index.js +366 -0
- package/dist/interpretation/index.js.map +1 -0
- package/dist/interpretation/siLanguage.js +25 -0
- package/dist/interpretation/siLanguage.js.map +1 -0
- package/dist/locus-info/controlsUtils.js +71 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +305 -57
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js +7 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js +43 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +219 -63
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js +44 -22
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +57 -104
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +60 -121
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +61 -3
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +2530 -2534
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +292 -0
- package/dist/meeting/locusMediaRequest.js.map +1 -0
- package/dist/meeting/muteState.js +125 -205
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +150 -150
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +568 -438
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/index.js +48 -7
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +94 -38
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +4 -2
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.d.ts +0 -2
- package/dist/meetings/index.js +260 -85
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +7 -0
- package/dist/meetings/meetings.types.js.map +1 -0
- package/dist/meetings/util.js +42 -7
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.d.ts +2 -0
- package/dist/member/index.js +26 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/member.types.d.ts +11 -0
- package/dist/member/member.types.js +18 -0
- package/dist/member/member.types.js.map +1 -0
- package/dist/member/types.js +11 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +60 -23
- package/dist/member/util.js.map +1 -1
- package/dist/members/index.js +4 -1
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +75 -45
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js +308 -317
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/config.js +1 -3
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/constants.js +1 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.d.ts +1 -1
- package/dist/metrics/index.js +1 -451
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +136 -40
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +4 -4
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +60 -3
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +36 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +233 -0
- package/dist/multistream/sendSlotManager.js.map +1 -0
- package/dist/reachability/index.js +18 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +5 -3
- package/dist/reachability/request.js.map +1 -1
- package/dist/reconnection-manager/index.js +181 -153
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/index.js +21 -2
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js +9 -8
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +25 -32
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +42 -51
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +97 -38
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/rtcMetrics/constants.js +12 -0
- package/dist/rtcMetrics/constants.js.map +1 -0
- package/dist/rtcMetrics/index.js +117 -0
- package/dist/rtcMetrics/index.js.map +1 -0
- package/dist/statsAnalyzer/index.js +0 -1
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/types/annotation/annotation.types.d.ts +43 -0
- package/dist/types/annotation/constants.d.ts +31 -0
- package/dist/types/annotation/index.d.ts +124 -0
- package/dist/types/breakouts/events.d.ts +2 -0
- package/dist/types/breakouts/utils.d.ts +7 -0
- package/dist/types/common/errors/webex-errors.d.ts +1 -1
- package/dist/types/config.d.ts +0 -6
- package/dist/types/constants.d.ts +51 -21
- package/dist/types/controls-options-manager/enums.d.ts +2 -0
- package/dist/types/controls-options-manager/index.d.ts +1 -1
- package/dist/types/controls-options-manager/types.d.ts +7 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/interpretation/collection.d.ts +5 -0
- package/dist/types/interpretation/index.d.ts +5 -0
- package/dist/types/interpretation/siLanguage.d.ts +5 -0
- package/dist/types/locus-info/index.d.ts +39 -1
- package/dist/types/media/index.d.ts +2 -0
- package/dist/types/media/properties.d.ts +16 -38
- package/dist/types/meeting/in-meeting-actions.d.ts +46 -2
- package/dist/types/meeting/index.d.ts +179 -379
- package/dist/types/meeting/locusMediaRequest.d.ts +70 -0
- package/dist/types/meeting/muteState.d.ts +39 -40
- package/dist/types/meeting/request.d.ts +25 -26
- package/dist/types/meeting/util.d.ts +74 -1
- package/dist/types/meeting-info/meeting-info-v2.d.ts +14 -3
- package/dist/types/meetings/index.d.ts +49 -1
- package/dist/types/meetings/meetings.types.d.ts +4 -0
- package/dist/types/member/index.d.ts +2 -0
- package/dist/types/members/request.d.ts +56 -11
- package/dist/types/members/util.d.ts +209 -1
- package/dist/types/metrics/config.d.ts +26 -2
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/types/metrics/index.d.ts +17 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +27 -10
- package/dist/types/multistream/receiveSlot.d.ts +3 -3
- package/dist/types/multistream/remoteMedia.d.ts +2 -2
- package/dist/types/multistream/remoteMediaManager.d.ts +14 -0
- package/dist/types/roap/request.d.ts +6 -8
- package/dist/types/roap/turnDiscovery.d.ts +18 -1
- package/package.json +21 -20
- package/src/annotation/annotation.types.ts +50 -0
- package/src/annotation/constants.ts +36 -0
- package/src/annotation/index.ts +328 -0
- package/src/breakouts/README.md +3 -2
- package/src/breakouts/breakout.ts +62 -27
- package/src/breakouts/events.ts +56 -0
- package/src/breakouts/index.ts +244 -64
- package/src/breakouts/utils.ts +13 -0
- package/src/common/errors/webex-errors.ts +6 -2
- package/src/common/logs/logger-proxy.ts +1 -1
- package/src/common/queue.ts +22 -8
- package/src/config.ts +0 -6
- package/src/constants.ts +111 -19
- package/src/controls-options-manager/enums.ts +2 -0
- package/src/controls-options-manager/index.ts +13 -10
- package/src/controls-options-manager/types.ts +10 -0
- package/src/controls-options-manager/util.ts +82 -11
- package/src/index.ts +18 -11
- package/src/interpretation/README.md +60 -0
- package/src/interpretation/collection.ts +19 -0
- package/src/interpretation/index.ts +332 -0
- package/src/interpretation/siLanguage.ts +18 -0
- package/src/locus-info/controlsUtils.ts +81 -0
- package/src/locus-info/index.ts +318 -57
- package/src/locus-info/infoUtils.ts +10 -2
- package/src/locus-info/mediaSharesUtils.ts +48 -0
- package/src/locus-info/parser.ts +224 -39
- package/src/locus-info/selfUtils.ts +32 -20
- package/src/media/index.ts +94 -108
- package/src/media/properties.ts +69 -109
- package/src/meeting/in-meeting-actions.ts +120 -4
- package/src/meeting/index.ts +1967 -2120
- package/src/meeting/locusMediaRequest.ts +314 -0
- package/src/meeting/muteState.ts +119 -194
- package/src/meeting/request.ts +122 -115
- package/src/meeting/util.ts +549 -413
- package/src/meeting-info/index.ts +54 -8
- package/src/meeting-info/meeting-info-v2.ts +89 -24
- package/src/meeting-info/utilv2.ts +6 -2
- package/src/meetings/index.ts +247 -87
- package/src/meetings/meetings.types.ts +12 -0
- package/src/meetings/util.ts +47 -12
- package/src/member/index.ts +28 -1
- package/src/member/types.ts +14 -0
- package/src/member/util.ts +75 -26
- package/src/members/index.ts +7 -1
- package/src/members/request.ts +61 -21
- package/src/members/util.ts +316 -326
- package/src/metrics/constants.ts +1 -0
- package/src/metrics/index.ts +1 -474
- package/src/multistream/mediaRequestManager.ts +183 -67
- package/src/multistream/receiveSlot.ts +4 -4
- package/src/multistream/receiveSlotManager.ts +4 -4
- package/src/multistream/remoteMedia.ts +2 -2
- package/src/multistream/remoteMediaGroup.ts +59 -0
- package/src/multistream/remoteMediaManager.ts +33 -0
- package/src/multistream/sendSlotManager.ts +170 -0
- package/src/reachability/index.ts +15 -4
- package/src/reachability/request.ts +7 -3
- package/src/reconnection-manager/index.ts +36 -29
- package/src/recording-controller/index.ts +20 -3
- package/src/recording-controller/util.ts +26 -9
- package/src/roap/index.ts +25 -30
- package/src/roap/request.ts +44 -51
- package/src/roap/turnDiscovery.ts +51 -25
- package/src/rtcMetrics/constants.ts +3 -0
- package/src/rtcMetrics/index.ts +100 -0
- package/src/statsAnalyzer/index.ts +0 -1
- package/test/integration/spec/converged-space-meetings.js +60 -3
- package/test/integration/spec/journey.js +336 -259
- package/test/integration/spec/space-meeting.js +76 -3
- package/test/unit/spec/annotation/index.ts +418 -0
- package/test/unit/spec/breakouts/breakout.ts +85 -26
- package/test/unit/spec/breakouts/events.ts +89 -0
- package/test/unit/spec/breakouts/index.ts +636 -98
- package/test/unit/spec/breakouts/utils.js +19 -1
- package/test/unit/spec/common/queue.js +31 -2
- package/test/unit/spec/controls-options-manager/index.js +8 -1
- package/test/unit/spec/controls-options-manager/util.js +576 -397
- package/test/unit/spec/fixture/locus.js +1 -0
- package/test/unit/spec/interpretation/collection.ts +15 -0
- package/test/unit/spec/interpretation/index.ts +589 -0
- package/test/unit/spec/interpretation/siLanguage.ts +28 -0
- package/test/unit/spec/locus-info/controlsUtils.js +195 -1
- package/test/unit/spec/locus-info/index.js +950 -45
- package/test/unit/spec/locus-info/infoUtils.js +37 -15
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
- package/test/unit/spec/locus-info/parser.js +62 -22
- package/test/unit/spec/locus-info/selfConstant.js +19 -0
- package/test/unit/spec/locus-info/selfUtils.js +131 -26
- package/test/unit/spec/media/index.ts +82 -79
- package/test/unit/spec/meeting/in-meeting-actions.ts +60 -2
- package/test/unit/spec/meeting/index.js +3208 -1734
- package/test/unit/spec/meeting/locusMediaRequest.ts +443 -0
- package/test/unit/spec/meeting/muteState.js +328 -417
- package/test/unit/spec/meeting/request.js +393 -48
- package/test/unit/spec/meeting/utils.js +552 -76
- package/test/unit/spec/meeting-info/index.js +181 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +258 -20
- package/test/unit/spec/meeting-info/utilv2.js +21 -0
- package/test/unit/spec/meetings/index.js +631 -145
- package/test/unit/spec/meetings/utils.js +164 -9
- package/test/unit/spec/member/index.js +44 -14
- package/test/unit/spec/member/util.js +296 -155
- package/test/unit/spec/members/index.js +23 -3
- package/test/unit/spec/members/request.js +167 -35
- package/test/unit/spec/metrics/index.js +1 -50
- package/test/unit/spec/multistream/mediaRequestManager.ts +366 -8
- package/test/unit/spec/multistream/receiveSlot.ts +1 -1
- package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +123 -0
- package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
- package/test/unit/spec/reachability/index.ts +66 -5
- package/test/unit/spec/reachability/request.js +3 -1
- package/test/unit/spec/reconnection-manager/index.js +55 -5
- package/test/unit/spec/recording-controller/index.js +294 -218
- package/test/unit/spec/recording-controller/util.js +223 -96
- package/test/unit/spec/roap/index.ts +21 -48
- package/test/unit/spec/roap/request.ts +74 -60
- package/test/unit/spec/roap/turnDiscovery.ts +30 -6
- package/test/unit/spec/rtcMetrics/index.ts +68 -0
- package/test/utils/integrationTestUtils.js +46 -0
- package/test/utils/testUtils.js +0 -60
- package/src/metrics/config.ts +0 -487
package/src/meeting/util.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {LocalCameraTrack, LocalMicrophoneTrack} from '@webex/media-helpers';
|
|
1
|
+
import {LocalCameraStream, LocalMicrophoneStream} from '@webex/media-helpers';
|
|
3
2
|
|
|
3
|
+
import {cloneDeep} from 'lodash';
|
|
4
4
|
import {MeetingNotActiveError, UserNotJoinedError} from '../common/errors/webex-errors';
|
|
5
|
-
import Metrics from '../metrics';
|
|
6
|
-
import {eventType, trigger} from '../metrics/config';
|
|
7
|
-
import Media from '../media';
|
|
8
5
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
9
6
|
import {
|
|
10
7
|
INTENT_TO_JOIN,
|
|
@@ -14,6 +11,8 @@ import {
|
|
|
14
11
|
PASSWORD_STATUS,
|
|
15
12
|
DISPLAY_HINTS,
|
|
16
13
|
FULL_STATE,
|
|
14
|
+
SELF_POLICY,
|
|
15
|
+
EVENT_TRIGGERS,
|
|
17
16
|
} from '../constants';
|
|
18
17
|
import IntentToJoinError from '../common/errors/intent-to-join';
|
|
19
18
|
import JoinMeetingError from '../common/errors/join-meeting';
|
|
@@ -21,507 +20,644 @@ import ParameterError from '../common/errors/parameter';
|
|
|
21
20
|
import PermissionError from '../common/errors/permission';
|
|
22
21
|
import PasswordError from '../common/errors/password-error';
|
|
23
22
|
import CaptchaError from '../common/errors/captcha-error';
|
|
23
|
+
import Trigger from '../common/events/trigger-proxy';
|
|
24
|
+
|
|
25
|
+
const MeetingUtil = {
|
|
26
|
+
parseLocusJoin: (response) => {
|
|
27
|
+
const parsed: any = {};
|
|
28
|
+
|
|
29
|
+
// First todo: add check for existance
|
|
30
|
+
parsed.locus = response.body.locus;
|
|
31
|
+
parsed.mediaConnections = response.body.mediaConnections;
|
|
32
|
+
parsed.locusUrl = parsed.locus.url;
|
|
33
|
+
parsed.locusId = parsed.locus.url.split('/').pop();
|
|
34
|
+
parsed.selfId = parsed.locus.self.id;
|
|
35
|
+
|
|
36
|
+
// we need mediaId before making roap calls
|
|
37
|
+
parsed.mediaConnections.forEach((mediaConnection) => {
|
|
38
|
+
if (mediaConnection.mediaId) {
|
|
39
|
+
parsed.mediaId = mediaConnection.mediaId;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
24
42
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
MeetingUtil.parseLocusJoin = (response) => {
|
|
28
|
-
const parsed: any = {};
|
|
43
|
+
return parsed;
|
|
44
|
+
},
|
|
29
45
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
parsed.selfId = parsed.locus.self.id;
|
|
46
|
+
remoteUpdateAudioVideo: (meeting, audioMuted?: boolean, videoMuted?: boolean) => {
|
|
47
|
+
const webex = meeting.getWebexObject();
|
|
48
|
+
if (!meeting) {
|
|
49
|
+
return Promise.reject(new ParameterError('You need a meeting object.'));
|
|
50
|
+
}
|
|
36
51
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
52
|
+
if (!meeting.locusMediaRequest) {
|
|
53
|
+
return Promise.reject(
|
|
54
|
+
new ParameterError(
|
|
55
|
+
'You need a meeting with a media connection, call Meeting.addMedia() first.'
|
|
56
|
+
)
|
|
57
|
+
);
|
|
41
58
|
}
|
|
42
|
-
});
|
|
43
59
|
|
|
44
|
-
|
|
45
|
-
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
webex.internal.newMetrics.submitClientEvent({
|
|
62
|
+
name: 'client.locus.media.request',
|
|
63
|
+
options: {meetingId: meeting.id},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return meeting.locusMediaRequest
|
|
67
|
+
.send({
|
|
68
|
+
type: 'LocalMute',
|
|
69
|
+
selfUrl: meeting.selfUrl,
|
|
70
|
+
mediaId: meeting.mediaId,
|
|
71
|
+
sequence: meeting.locusInfo.sequence,
|
|
72
|
+
muteOptions: {
|
|
73
|
+
audioMuted,
|
|
74
|
+
videoMuted,
|
|
75
|
+
},
|
|
76
|
+
ipVersion: meeting.getWebexObject().meetings.reachability.getIpVersion(),
|
|
77
|
+
})
|
|
78
|
+
.then((response) => {
|
|
79
|
+
// @ts-ignore
|
|
80
|
+
webex.internal.newMetrics.submitClientEvent({
|
|
81
|
+
name: 'client.locus.media.response',
|
|
82
|
+
options: {meetingId: meeting.id},
|
|
83
|
+
});
|
|
46
84
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
const localMedias = Media.generateLocalMedias(meeting.mediaId, audioMuted, videoMuted);
|
|
85
|
+
return response?.body?.locus;
|
|
86
|
+
});
|
|
87
|
+
},
|
|
52
88
|
|
|
53
|
-
|
|
54
|
-
return Promise.reject(
|
|
55
|
-
new ParameterError('You need a media id on the meeting to change remote audio.')
|
|
56
|
-
);
|
|
57
|
-
}
|
|
89
|
+
hasOwner: (info) => info && info.owner,
|
|
58
90
|
|
|
59
|
-
|
|
91
|
+
isOwnerSelf: (owner, selfId) => owner === selfId,
|
|
60
92
|
|
|
61
|
-
|
|
62
|
-
|
|
93
|
+
isPinOrGuest: (err) => err?.body?.errorCode && INTENT_TO_JOIN.includes(err.body.errorCode),
|
|
94
|
+
|
|
95
|
+
joinMeeting: (meeting, options) => {
|
|
96
|
+
if (!meeting) {
|
|
97
|
+
return Promise.reject(new ParameterError('You need a meeting object.'));
|
|
98
|
+
}
|
|
99
|
+
const webex = meeting.getWebexObject();
|
|
100
|
+
|
|
101
|
+
// @ts-ignore
|
|
102
|
+
webex.internal.newMetrics.submitClientEvent({
|
|
103
|
+
name: 'client.locus.join.request',
|
|
104
|
+
options: {meetingId: meeting.id},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// eslint-disable-next-line no-warning-comments
|
|
108
|
+
// TODO: check if the meeting is in JOINING state
|
|
109
|
+
// if Joining state termintate the request as user might click multiple times
|
|
110
|
+
return meeting.meetingRequest
|
|
111
|
+
.joinMeeting({
|
|
112
|
+
inviteeAddress: meeting.meetingJoinUrl || meeting.sipUri,
|
|
113
|
+
meetingNumber: meeting.meetingNumber,
|
|
114
|
+
deviceUrl: meeting.deviceUrl,
|
|
115
|
+
locusUrl: meeting.locusUrl,
|
|
116
|
+
correlationId: meeting.correlationId,
|
|
117
|
+
roapMessage: options.roapMessage,
|
|
118
|
+
permissionToken: meeting.permissionToken,
|
|
119
|
+
resourceId: options.resourceId || null,
|
|
120
|
+
moderator: options.moderator,
|
|
121
|
+
pin: options.pin,
|
|
122
|
+
moveToResource: options.moveToResource,
|
|
123
|
+
preferTranscoding: !meeting.isMultistream,
|
|
124
|
+
asResourceOccupant: options.asResourceOccupant,
|
|
125
|
+
breakoutsSupported: options.breakoutsSupported,
|
|
126
|
+
locale: options.locale,
|
|
127
|
+
deviceCapabilities: options.deviceCapabilities,
|
|
128
|
+
liveAnnotationSupported: options.liveAnnotationSupported,
|
|
129
|
+
ipVersion: meeting.getWebexObject().meetings.reachability.getIpVersion(),
|
|
130
|
+
})
|
|
131
|
+
.then((res) => {
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
webex.internal.newMetrics.submitClientEvent({
|
|
134
|
+
name: 'client.locus.join.response',
|
|
135
|
+
payload: {
|
|
136
|
+
trigger: 'loci-update',
|
|
137
|
+
identifiers: {
|
|
138
|
+
trackingId: res.headers.trackingid,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
options: {
|
|
142
|
+
meetingId: meeting.id,
|
|
143
|
+
mediaConnections: res.body.mediaConnections,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
return MeetingUtil.parseLocusJoin(res);
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
cleanUp: (meeting) => {
|
|
152
|
+
meeting.breakouts.cleanUp();
|
|
153
|
+
meeting.simultaneousInterpretation.cleanUp();
|
|
154
|
+
|
|
155
|
+
// make sure we send last metrics before we close the peerconnection
|
|
156
|
+
const stopStatsAnalyzer = meeting.statsAnalyzer
|
|
157
|
+
? meeting.statsAnalyzer.stopAnalyzer()
|
|
158
|
+
: Promise.resolve();
|
|
159
|
+
|
|
160
|
+
return stopStatsAnalyzer
|
|
161
|
+
.then(() => meeting.closeRemoteStreams())
|
|
162
|
+
.then(() => meeting.closePeerConnections())
|
|
163
|
+
.then(() => {
|
|
164
|
+
meeting.cleanupLocalStreams();
|
|
165
|
+
meeting.unsetRemoteStreams();
|
|
166
|
+
meeting.unsetPeerConnections();
|
|
167
|
+
meeting.reconnectionManager.cleanUp();
|
|
168
|
+
})
|
|
169
|
+
.then(() => meeting.stopKeepAlive())
|
|
170
|
+
.then(() => meeting.updateLLMConnection());
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
disconnectPhoneAudio: (meeting, phoneUrl) => {
|
|
174
|
+
if (meeting.meetingState === FULL_STATE.INACTIVE) {
|
|
175
|
+
return Promise.reject(new MeetingNotActiveError());
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const options = {
|
|
63
179
|
locusUrl: meeting.locusUrl,
|
|
64
180
|
selfId: meeting.selfId,
|
|
65
|
-
localMedias,
|
|
66
|
-
deviceUrl: meeting.deviceUrl,
|
|
67
181
|
correlationId: meeting.correlationId,
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
.then((response) => {
|
|
71
|
-
Metrics.postEvent({event: eventType.MEDIA_RESPONSE, meeting});
|
|
182
|
+
phoneUrl,
|
|
183
|
+
};
|
|
72
184
|
|
|
73
|
-
|
|
185
|
+
return meeting.meetingRequest.disconnectPhoneAudio(options).catch((err) => {
|
|
186
|
+
LoggerProxy.logger.error(
|
|
187
|
+
`Meeting:util#disconnectPhoneAudio --> An error occured while disconnecting phone audio in meeting ${meeting.id}, error: ${err}`
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
return Promise.reject(err);
|
|
74
191
|
});
|
|
75
|
-
}
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Returns options for leaving a meeting.
|
|
196
|
+
* @param {any} meeting
|
|
197
|
+
* @param {any} options
|
|
198
|
+
* @returns {any} leave options
|
|
199
|
+
*/
|
|
200
|
+
prepareLeaveMeetingOptions: (meeting, options: any = {}) => {
|
|
201
|
+
const defaultOptions = {
|
|
202
|
+
locusUrl: meeting.locusUrl,
|
|
203
|
+
selfId: meeting.selfId,
|
|
204
|
+
correlationId: meeting.correlationId,
|
|
205
|
+
resourceId: meeting.resourceId,
|
|
206
|
+
deviceUrl: meeting.deviceUrl,
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
return {...defaultOptions, ...options};
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
// by default will leave on meeting's resourceId
|
|
213
|
+
// if you explicity want it not to leave on resource id, pass
|
|
214
|
+
// {resourceId: null}
|
|
215
|
+
// TODO: chris, you can modify this however you want
|
|
216
|
+
leaveMeeting: (meeting, options: any = {}) => {
|
|
217
|
+
if (meeting.meetingState === FULL_STATE.INACTIVE) {
|
|
218
|
+
// TODO: clean up if the meeting is already inactive
|
|
219
|
+
return Promise.reject(new MeetingNotActiveError());
|
|
220
|
+
}
|
|
76
221
|
|
|
77
|
-
MeetingUtil.
|
|
222
|
+
if (MeetingUtil.isUserInLeftState(meeting.locusInfo)) {
|
|
223
|
+
return Promise.reject(new UserNotJoinedError());
|
|
224
|
+
}
|
|
78
225
|
|
|
79
|
-
|
|
226
|
+
const leaveOptions = MeetingUtil.prepareLeaveMeetingOptions(meeting, options);
|
|
227
|
+
|
|
228
|
+
return meeting.meetingRequest
|
|
229
|
+
.leaveMeeting(leaveOptions)
|
|
230
|
+
.then(() => {
|
|
231
|
+
if (options.moveMeeting) {
|
|
232
|
+
return Promise.resolve();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return MeetingUtil.cleanUp(meeting);
|
|
236
|
+
})
|
|
237
|
+
.catch((err) => {
|
|
238
|
+
// TODO: If the meeting state comes as LEFT or INACTIVE as response then
|
|
239
|
+
// 1) on leave clean up the meeting or simply do a sync on the meeting
|
|
240
|
+
// 2) If the error says meeting is inactive then destroy the meeting object
|
|
241
|
+
LoggerProxy.logger.error(
|
|
242
|
+
`Meeting:util#leaveMeeting --> An error occured while trying to leave meeting with an id of ${meeting.id}, error: ${err}`
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
return Promise.reject(err);
|
|
246
|
+
});
|
|
247
|
+
},
|
|
248
|
+
declineMeeting: (meeting, reason) =>
|
|
249
|
+
meeting.meetingRequest.declineMeeting({
|
|
250
|
+
locusUrl: meeting.locusUrl,
|
|
251
|
+
deviceUrl: meeting.deviceUrl,
|
|
252
|
+
reason,
|
|
253
|
+
}),
|
|
80
254
|
|
|
81
|
-
|
|
82
|
-
err?.body?.errorCode && INTENT_TO_JOIN.includes(err.body.errorCode);
|
|
255
|
+
isUserInLeftState: (locusInfo) => locusInfo.parsedLocus?.self?.state === _LEFT_,
|
|
83
256
|
|
|
84
|
-
|
|
85
|
-
if (!meeting) {
|
|
86
|
-
return Promise.reject(new ParameterError('You need a meeting object.'));
|
|
87
|
-
}
|
|
257
|
+
isUserInIdleState: (locusInfo) => locusInfo.parsedLocus?.self?.state === _IDLE_,
|
|
88
258
|
|
|
89
|
-
|
|
259
|
+
isUserInJoinedState: (locusInfo) => locusInfo.parsedLocus?.self?.state === _JOINED_,
|
|
90
260
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
event: eventType.LOCUS_JOIN_RESPONSE,
|
|
114
|
-
meeting,
|
|
115
|
-
data: {
|
|
116
|
-
trigger: trigger.LOCI_UPDATE,
|
|
117
|
-
locus: res.body.locus,
|
|
118
|
-
mediaConnections: res.body.mediaConnections,
|
|
119
|
-
trackingId: res.headers.trackingid,
|
|
261
|
+
isMediaEstablished: (currentMediaStatus) =>
|
|
262
|
+
currentMediaStatus &&
|
|
263
|
+
(currentMediaStatus.audio || currentMediaStatus.video || currentMediaStatus.share),
|
|
264
|
+
|
|
265
|
+
joinMeetingOptions: (meeting, options: any = {}) => {
|
|
266
|
+
const webex = meeting.getWebexObject();
|
|
267
|
+
|
|
268
|
+
meeting.resourceId = meeting.resourceId || options.resourceId;
|
|
269
|
+
|
|
270
|
+
if (meeting.requiredCaptcha) {
|
|
271
|
+
return Promise.reject(new CaptchaError());
|
|
272
|
+
}
|
|
273
|
+
if (meeting.passwordStatus === PASSWORD_STATUS.REQUIRED) {
|
|
274
|
+
return Promise.reject(new PasswordError());
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (options.pin) {
|
|
278
|
+
// @ts-ignore
|
|
279
|
+
webex.internal.newMetrics.submitClientEvent({
|
|
280
|
+
name: 'client.pin.collected',
|
|
281
|
+
options: {
|
|
282
|
+
meetingId: meeting.id,
|
|
120
283
|
},
|
|
121
284
|
});
|
|
285
|
+
}
|
|
122
286
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
287
|
+
// normal join meeting, scenario A, D
|
|
288
|
+
return MeetingUtil.joinMeeting(meeting, options)
|
|
289
|
+
.then((response) => {
|
|
290
|
+
meeting.setLocus(response);
|
|
291
|
+
|
|
292
|
+
return Promise.resolve(response);
|
|
293
|
+
})
|
|
294
|
+
.catch((err) => {
|
|
295
|
+
// joining a claimed PMR that is not my own, scenario B
|
|
296
|
+
if (MeetingUtil.isPinOrGuest(err)) {
|
|
297
|
+
// @ts-ignore
|
|
298
|
+
webex.internal.newMetrics.submitClientEvent({
|
|
299
|
+
name: 'client.pin.prompt',
|
|
300
|
+
options: {
|
|
301
|
+
meetingId: meeting.id,
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// request host pin or non host for unclaimed PMR, start of Scenario C
|
|
306
|
+
// see https://sqbu-github.cisco.com/WebExSquared/locus/wiki/Locus-Lobby-and--IVR-Feature
|
|
307
|
+
return Promise.reject(new IntentToJoinError('Error Joining Meeting', err));
|
|
308
|
+
}
|
|
309
|
+
LoggerProxy.logger.error(
|
|
310
|
+
'Meeting:util#joinMeetingOptions --> Error joining the call, ',
|
|
311
|
+
err
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
return Promise.reject(new JoinMeetingError(options, 'Error Joining Meeting', err));
|
|
315
|
+
});
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Returns request options for leaving a meeting.
|
|
320
|
+
* @param {any} meeting
|
|
321
|
+
* @param {any} options
|
|
322
|
+
* @returns {any} request options
|
|
323
|
+
*/
|
|
324
|
+
buildLeaveFetchRequestOptions: (meeting, options: any = {}) => {
|
|
325
|
+
const leaveOptions = MeetingUtil.prepareLeaveMeetingOptions(meeting, options);
|
|
326
|
+
|
|
327
|
+
return meeting.meetingRequest.buildLeaveMeetingRequestOptions(leaveOptions);
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
getTrack: (stream) => {
|
|
331
|
+
let audioTrack = null;
|
|
332
|
+
let videoTrack = null;
|
|
333
|
+
let audioTracks = null;
|
|
334
|
+
let videoTracks = null;
|
|
335
|
+
|
|
336
|
+
if (!stream) {
|
|
337
|
+
return {audioTrack: null, videoTrack: null};
|
|
338
|
+
}
|
|
339
|
+
if (stream.getAudioTracks) {
|
|
340
|
+
audioTracks = stream.getAudioTracks();
|
|
341
|
+
}
|
|
342
|
+
if (stream.getVideoTracks) {
|
|
343
|
+
videoTracks = stream.getVideoTracks();
|
|
344
|
+
}
|
|
126
345
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
// make sure we send last metrics before we close the peerconnection
|
|
131
|
-
const stopStatsAnalyzer = meeting.statsAnalyzer
|
|
132
|
-
? meeting.statsAnalyzer.stopAnalyzer()
|
|
133
|
-
: Promise.resolve();
|
|
134
|
-
|
|
135
|
-
return stopStatsAnalyzer
|
|
136
|
-
.then(() => meeting.closeLocalStream())
|
|
137
|
-
.then(() => meeting.closeLocalShare())
|
|
138
|
-
.then(() => meeting.closeRemoteTracks())
|
|
139
|
-
.then(() => meeting.closePeerConnections())
|
|
140
|
-
.then(() => {
|
|
141
|
-
meeting.unsetLocalVideoTrack();
|
|
142
|
-
meeting.unsetLocalShareTrack();
|
|
143
|
-
meeting.unsetRemoteTracks();
|
|
144
|
-
meeting.unsetPeerConnections();
|
|
145
|
-
meeting.reconnectionManager.cleanUp();
|
|
146
|
-
})
|
|
147
|
-
.then(() => meeting.stopKeepAlive())
|
|
148
|
-
.then(() => meeting.updateLLMConnection());
|
|
149
|
-
};
|
|
346
|
+
if (audioTracks && audioTracks.length > 0) {
|
|
347
|
+
[audioTrack] = audioTracks;
|
|
348
|
+
}
|
|
150
349
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const options = {
|
|
157
|
-
locusUrl: meeting.locusUrl,
|
|
158
|
-
selfId: meeting.selfId,
|
|
159
|
-
correlationId: meeting.correlationId,
|
|
160
|
-
phoneUrl,
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
return meeting.meetingRequest
|
|
164
|
-
.disconnectPhoneAudio(options)
|
|
165
|
-
.then((response) => {
|
|
166
|
-
if (response?.body?.locus) {
|
|
167
|
-
meeting.locusInfo.onFullLocus(response.body.locus);
|
|
168
|
-
}
|
|
169
|
-
})
|
|
170
|
-
.catch((err) => {
|
|
171
|
-
LoggerProxy.logger.error(
|
|
172
|
-
`Meeting:util#disconnectPhoneAudio --> An error occured while disconnecting phone audio in meeting ${meeting.id}, error: ${err}`
|
|
173
|
-
);
|
|
350
|
+
if (videoTracks && videoTracks.length > 0) {
|
|
351
|
+
[videoTrack] = videoTracks;
|
|
352
|
+
}
|
|
174
353
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
};
|
|
354
|
+
return {audioTrack, videoTrack};
|
|
355
|
+
},
|
|
178
356
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// TODO: clean up if the meeting is already inactive
|
|
186
|
-
return Promise.reject(new MeetingNotActiveError());
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (MeetingUtil.isUserInLeftState(meeting.locusInfo)) {
|
|
190
|
-
return Promise.reject(new UserNotJoinedError());
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const defaultOptions = {
|
|
194
|
-
locusUrl: meeting.locusUrl,
|
|
195
|
-
selfId: meeting.selfId,
|
|
196
|
-
correlationId: meeting.correlationId,
|
|
197
|
-
resourceId: meeting.resourceId,
|
|
198
|
-
deviceUrl: meeting.deviceUrl,
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
const leaveOptions = {...defaultOptions, ...options};
|
|
202
|
-
|
|
203
|
-
return meeting.meetingRequest
|
|
204
|
-
.leaveMeeting(leaveOptions)
|
|
205
|
-
.then((response) => {
|
|
206
|
-
if (response && response.body && response.body.locus) {
|
|
207
|
-
// && !options.moveMeeting) {
|
|
208
|
-
meeting.locusInfo.onFullLocus(response.body.locus);
|
|
209
|
-
}
|
|
357
|
+
getModeratorFromLocusInfo: (locusInfo) =>
|
|
358
|
+
locusInfo &&
|
|
359
|
+
locusInfo.parsedLocus &&
|
|
360
|
+
locusInfo.parsedLocus.info &&
|
|
361
|
+
locusInfo.parsedLocus.info &&
|
|
362
|
+
locusInfo.parsedLocus.info.moderator,
|
|
210
363
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
364
|
+
getPolicyFromLocusInfo: (locusInfo) =>
|
|
365
|
+
locusInfo &&
|
|
366
|
+
locusInfo.parsedLocus &&
|
|
367
|
+
locusInfo.parsedLocus.info &&
|
|
368
|
+
locusInfo.parsedLocus.info &&
|
|
369
|
+
locusInfo.parsedLocus.info.policy,
|
|
217
370
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
.catch((err) => {
|
|
221
|
-
// TODO: If the meeting state comes as LEFT or INACTIVE as response then
|
|
222
|
-
// 1) on leave clean up the meeting or simply do a sync on the meeting
|
|
223
|
-
// 2) If the error says meeting is inactive then destroy the meeting object
|
|
224
|
-
LoggerProxy.logger.error(
|
|
225
|
-
`Meeting:util#leaveMeeting --> An error occured while trying to leave meeting with an id of ${meeting.id}, error: ${err}`
|
|
226
|
-
);
|
|
371
|
+
getUserDisplayHintsFromLocusInfo: (locusInfo) =>
|
|
372
|
+
locusInfo?.parsedLocus?.info?.userDisplayHints || [],
|
|
227
373
|
|
|
228
|
-
|
|
229
|
-
});
|
|
230
|
-
};
|
|
231
|
-
MeetingUtil.declineMeeting = (meeting, reason) =>
|
|
232
|
-
meeting.meetingRequest.declineMeeting({
|
|
233
|
-
locusUrl: meeting.locusUrl,
|
|
234
|
-
deviceUrl: meeting.deviceUrl,
|
|
235
|
-
reason,
|
|
236
|
-
});
|
|
374
|
+
canInviteNewParticipants: (displayHints) => displayHints.includes(DISPLAY_HINTS.ADD_GUEST),
|
|
237
375
|
|
|
238
|
-
|
|
376
|
+
canAdmitParticipant: (displayHints) =>
|
|
377
|
+
displayHints.includes(DISPLAY_HINTS.ROSTER_WAITING_TO_JOIN),
|
|
239
378
|
|
|
240
|
-
|
|
379
|
+
canUserLock: (displayHints) =>
|
|
380
|
+
displayHints.includes(DISPLAY_HINTS.LOCK_CONTROL_LOCK) &&
|
|
381
|
+
displayHints.includes(DISPLAY_HINTS.LOCK_STATUS_UNLOCKED),
|
|
241
382
|
|
|
242
|
-
|
|
383
|
+
canUserUnlock: (displayHints) =>
|
|
384
|
+
displayHints.includes(DISPLAY_HINTS.LOCK_CONTROL_UNLOCK) &&
|
|
385
|
+
displayHints.includes(DISPLAY_HINTS.LOCK_STATUS_LOCKED),
|
|
243
386
|
|
|
244
|
-
|
|
245
|
-
currentMediaStatus &&
|
|
246
|
-
(currentMediaStatus.audio || currentMediaStatus.video || currentMediaStatus.share);
|
|
387
|
+
canUserRaiseHand: (displayHints) => displayHints.includes(DISPLAY_HINTS.RAISE_HAND),
|
|
247
388
|
|
|
248
|
-
|
|
249
|
-
meeting.resourceId = meeting.resourceId || options.resourceId;
|
|
389
|
+
canUserLowerAllHands: (displayHints) => displayHints.includes(DISPLAY_HINTS.LOWER_ALL_HANDS),
|
|
250
390
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
if (meeting.passwordStatus === PASSWORD_STATUS.REQUIRED) {
|
|
255
|
-
return Promise.reject(new PasswordError());
|
|
256
|
-
}
|
|
391
|
+
canUserLowerSomeoneElsesHand: (displayHints) =>
|
|
392
|
+
displayHints.includes(DISPLAY_HINTS.LOWER_SOMEONE_ELSES_HAND),
|
|
257
393
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
meeting,
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// normal join meeting, scenario A, D
|
|
266
|
-
return MeetingUtil.joinMeeting(meeting, options)
|
|
267
|
-
.then((response) => {
|
|
268
|
-
meeting.setLocus(response);
|
|
269
|
-
|
|
270
|
-
return Promise.resolve(response);
|
|
271
|
-
})
|
|
272
|
-
.catch((err) => {
|
|
273
|
-
// joining a claimed PMR that is not my own, scenario B
|
|
274
|
-
if (MeetingUtil.isPinOrGuest(err)) {
|
|
275
|
-
Metrics.postEvent({
|
|
276
|
-
event: eventType.PIN_PROMPT,
|
|
277
|
-
meeting,
|
|
278
|
-
});
|
|
394
|
+
bothLeaveAndEndMeetingAvailable: (displayHints) =>
|
|
395
|
+
displayHints.includes(DISPLAY_HINTS.LEAVE_TRANSFER_HOST_END_MEETING) ||
|
|
396
|
+
displayHints.includes(DISPLAY_HINTS.LEAVE_END_MEETING),
|
|
279
397
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
LoggerProxy.logger.error('Meeting:util#joinMeetingOptions --> Error joining the call, ', err);
|
|
398
|
+
canManageBreakout: (displayHints) => displayHints.includes(DISPLAY_HINTS.BREAKOUT_MANAGEMENT),
|
|
399
|
+
canBroadcastMessageToBreakout: (displayHints, policies = {}) =>
|
|
400
|
+
displayHints.includes(DISPLAY_HINTS.BROADCAST_MESSAGE_TO_BREAKOUT) &&
|
|
401
|
+
!!policies[SELF_POLICY.SUPPORT_BROADCAST_MESSAGE],
|
|
285
402
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
};
|
|
403
|
+
isSuppressBreakoutSupport: (displayHints) =>
|
|
404
|
+
displayHints.includes(DISPLAY_HINTS.UCF_SUPPRESS_BREAKOUTS_SUPPORT),
|
|
289
405
|
|
|
290
|
-
|
|
291
|
-
|
|
406
|
+
canAdmitLobbyToBreakout: (displayHints) =>
|
|
407
|
+
!displayHints.includes(DISPLAY_HINTS.DISABLE_LOBBY_TO_BREAKOUT),
|
|
292
408
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
409
|
+
isBreakoutPreassignmentsEnabled: (displayHints) =>
|
|
410
|
+
!displayHints.includes(DISPLAY_HINTS.DISABLE_BREAKOUT_PREASSIGNMENTS),
|
|
296
411
|
|
|
297
|
-
|
|
298
|
-
return Promise.reject(new ParameterError('please pass valid audio streams'));
|
|
299
|
-
}
|
|
412
|
+
canUserAskForHelp: (displayHints) => !displayHints.includes(DISPLAY_HINTS.DISABLE_ASK_FOR_HELP),
|
|
300
413
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
414
|
+
lockMeeting: (actions, request, locusUrl) => {
|
|
415
|
+
if (actions && actions.canLock) {
|
|
416
|
+
return request.lockMeeting({locusUrl, lock: true});
|
|
417
|
+
}
|
|
304
418
|
|
|
305
|
-
|
|
306
|
-
}
|
|
419
|
+
return Promise.reject(new PermissionError('Lock not allowed, due to joined property.'));
|
|
420
|
+
},
|
|
307
421
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
let videoTracks = null;
|
|
313
|
-
|
|
314
|
-
if (!stream) {
|
|
315
|
-
return {audioTrack: null, videoTrack: null};
|
|
316
|
-
}
|
|
317
|
-
if (stream.getAudioTracks) {
|
|
318
|
-
audioTracks = stream.getAudioTracks();
|
|
319
|
-
}
|
|
320
|
-
if (stream.getVideoTracks) {
|
|
321
|
-
videoTracks = stream.getVideoTracks();
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (audioTracks && audioTracks.length > 0) {
|
|
325
|
-
[audioTrack] = audioTracks;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (videoTracks && videoTracks.length > 0) {
|
|
329
|
-
[videoTrack] = videoTracks;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
return {audioTrack, videoTrack};
|
|
333
|
-
};
|
|
422
|
+
unlockMeeting: (actions, request, locusUrl) => {
|
|
423
|
+
if (actions && actions.canUnlock) {
|
|
424
|
+
return request.lockMeeting({locusUrl, lock: false});
|
|
425
|
+
}
|
|
334
426
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
locusInfo.parsedLocus &&
|
|
338
|
-
locusInfo.parsedLocus.info &&
|
|
339
|
-
locusInfo.parsedLocus.info &&
|
|
340
|
-
locusInfo.parsedLocus.info.moderator;
|
|
427
|
+
return Promise.reject(new PermissionError('Unlock not allowed, due to joined property.'));
|
|
428
|
+
},
|
|
341
429
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
locusInfo.parsedLocus &&
|
|
345
|
-
locusInfo.parsedLocus.info &&
|
|
346
|
-
locusInfo.parsedLocus.info &&
|
|
347
|
-
locusInfo.parsedLocus.info.policy;
|
|
430
|
+
handleAudioLogging: (audioStream?: LocalMicrophoneStream) => {
|
|
431
|
+
const LOG_HEADER = 'MeetingUtil#handleAudioLogging -->';
|
|
348
432
|
|
|
349
|
-
|
|
350
|
-
|
|
433
|
+
if (audioStream) {
|
|
434
|
+
const settings = audioStream.getSettings();
|
|
435
|
+
const {deviceId} = settings;
|
|
351
436
|
|
|
352
|
-
|
|
353
|
-
|
|
437
|
+
LoggerProxy.logger.log(LOG_HEADER, `deviceId = ${deviceId}`);
|
|
438
|
+
LoggerProxy.logger.log(LOG_HEADER, 'settings =', JSON.stringify(settings));
|
|
439
|
+
}
|
|
440
|
+
},
|
|
354
441
|
|
|
355
|
-
|
|
356
|
-
|
|
442
|
+
handleVideoLogging: (videoStream?: LocalCameraStream) => {
|
|
443
|
+
const LOG_HEADER = 'MeetingUtil#handleVideoLogging -->';
|
|
357
444
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
445
|
+
if (videoStream) {
|
|
446
|
+
const settings = videoStream.getSettings();
|
|
447
|
+
const {deviceId} = settings;
|
|
361
448
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
449
|
+
LoggerProxy.logger.log(LOG_HEADER, `deviceId = ${deviceId}`);
|
|
450
|
+
LoggerProxy.logger.log(LOG_HEADER, 'settings =', JSON.stringify(settings));
|
|
451
|
+
}
|
|
452
|
+
},
|
|
365
453
|
|
|
366
|
-
|
|
454
|
+
handleDeviceLogging: (devices = []) => {
|
|
455
|
+
const LOG_HEADER = 'MeetingUtil#handleDeviceLogging -->';
|
|
367
456
|
|
|
368
|
-
|
|
369
|
-
|
|
457
|
+
devices.forEach((device) => {
|
|
458
|
+
LoggerProxy.logger.log(LOG_HEADER, `deviceId = ${device.deviceId}`);
|
|
459
|
+
LoggerProxy.logger.log(LOG_HEADER, 'settings', JSON.stringify(device));
|
|
460
|
+
});
|
|
461
|
+
},
|
|
370
462
|
|
|
371
|
-
|
|
372
|
-
|
|
463
|
+
endMeetingForAll: (meeting) => {
|
|
464
|
+
if (meeting.meetingState === FULL_STATE.INACTIVE) {
|
|
465
|
+
return Promise.reject(new MeetingNotActiveError());
|
|
466
|
+
}
|
|
373
467
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
468
|
+
const endOptions = {
|
|
469
|
+
locusUrl: meeting.locusUrl,
|
|
470
|
+
};
|
|
377
471
|
|
|
378
|
-
|
|
379
|
-
|
|
472
|
+
return meeting.meetingRequest
|
|
473
|
+
.endMeetingForAll(endOptions)
|
|
474
|
+
.then(() => MeetingUtil.cleanUp(meeting))
|
|
475
|
+
.catch((err) => {
|
|
476
|
+
LoggerProxy.logger.error(
|
|
477
|
+
`Meeting:util#endMeetingForAll An error occured while trying to end meeting for all with an id of ${meeting.id}, error: ${err}`
|
|
478
|
+
);
|
|
380
479
|
|
|
381
|
-
|
|
382
|
-
|
|
480
|
+
return Promise.reject(err);
|
|
481
|
+
});
|
|
482
|
+
},
|
|
383
483
|
|
|
384
|
-
|
|
385
|
-
!displayHints.includes(DISPLAY_HINTS.DISABLE_LOBBY_TO_BREAKOUT);
|
|
484
|
+
canEnableClosedCaption: (displayHints) => displayHints.includes(DISPLAY_HINTS.CAPTION_START),
|
|
386
485
|
|
|
387
|
-
|
|
388
|
-
|
|
486
|
+
isSaveTranscriptsEnabled: (displayHints) =>
|
|
487
|
+
displayHints.includes(DISPLAY_HINTS.SAVE_TRANSCRIPTS_ENABLED),
|
|
389
488
|
|
|
390
|
-
|
|
391
|
-
|
|
489
|
+
canStartTranscribing: (displayHints) =>
|
|
490
|
+
displayHints.includes(DISPLAY_HINTS.TRANSCRIPTION_CONTROL_START),
|
|
392
491
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
return request.lockMeeting({locusUrl, lock: true});
|
|
396
|
-
}
|
|
492
|
+
canStopTranscribing: (displayHints) =>
|
|
493
|
+
displayHints.includes(DISPLAY_HINTS.TRANSCRIPTION_CONTROL_STOP),
|
|
397
494
|
|
|
398
|
-
|
|
399
|
-
|
|
495
|
+
isClosedCaptionActive: (displayHints) =>
|
|
496
|
+
displayHints.includes(DISPLAY_HINTS.CAPTION_STATUS_ACTIVE),
|
|
400
497
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
return request.lockMeeting({locusUrl, lock: false});
|
|
404
|
-
}
|
|
498
|
+
isWebexAssistantActive: (displayHints) =>
|
|
499
|
+
displayHints.includes(DISPLAY_HINTS.WEBEX_ASSISTANT_STATUS_ACTIVE),
|
|
405
500
|
|
|
406
|
-
|
|
407
|
-
};
|
|
501
|
+
canViewCaptionPanel: (displayHints) => displayHints.includes(DISPLAY_HINTS.ENABLE_CAPTION_PANEL),
|
|
408
502
|
|
|
409
|
-
|
|
410
|
-
|
|
503
|
+
isRealTimeTranslationEnabled: (displayHints) =>
|
|
504
|
+
displayHints.includes(DISPLAY_HINTS.DISPLAY_REAL_TIME_TRANSLATION),
|
|
411
505
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const {deviceId} = settings;
|
|
506
|
+
canSelectSpokenLanguages: (displayHints) =>
|
|
507
|
+
displayHints.includes(DISPLAY_HINTS.DISPLAY_NON_ENGLISH_ASR),
|
|
415
508
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
509
|
+
waitingForOthersToJoin: (displayHints) => displayHints.includes(DISPLAY_HINTS.WAITING_FOR_OTHERS),
|
|
510
|
+
|
|
511
|
+
canSendReactions: (originalValue, displayHints) => {
|
|
512
|
+
if (displayHints.includes(DISPLAY_HINTS.REACTIONS_ACTIVE)) {
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
if (displayHints.includes(DISPLAY_HINTS.REACTIONS_INACTIVE)) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
420
518
|
|
|
421
|
-
|
|
422
|
-
|
|
519
|
+
return originalValue;
|
|
520
|
+
},
|
|
521
|
+
canUserRenameSelfAndObserved: (displayHints) =>
|
|
522
|
+
displayHints.includes(DISPLAY_HINTS.CAN_RENAME_SELF_AND_OBSERVED),
|
|
423
523
|
|
|
424
|
-
|
|
425
|
-
const settings = videoTrack.underlyingTrack.getSettings();
|
|
426
|
-
const {deviceId} = settings;
|
|
524
|
+
canUserRenameOthers: (displayHints) => displayHints.includes(DISPLAY_HINTS.CAN_RENAME_OTHERS),
|
|
427
525
|
|
|
428
|
-
|
|
429
|
-
LoggerProxy.logger.log(LOG_HEADER, 'settings =', JSON.stringify(settings));
|
|
430
|
-
}
|
|
431
|
-
};
|
|
526
|
+
canShareWhiteBoard: (displayHints) => displayHints.includes(DISPLAY_HINTS.SHARE_WHITEBOARD),
|
|
432
527
|
|
|
433
|
-
|
|
434
|
-
|
|
528
|
+
/**
|
|
529
|
+
* Adds the current locus sequence information to a request body
|
|
530
|
+
* @param {Object} meeting The meeting object
|
|
531
|
+
* @param {Object} requestBody The body of a request to locus
|
|
532
|
+
* @returns {void}
|
|
533
|
+
*/
|
|
534
|
+
addSequence: (meeting, requestBody) => {
|
|
535
|
+
const sequence = meeting?.locusInfo?.sequence;
|
|
435
536
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
537
|
+
if (!sequence) {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
requestBody.sequence = sequence;
|
|
542
|
+
},
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Updates the locus info for the meeting with the delta locus
|
|
546
|
+
* returned from requests that include the sequence information
|
|
547
|
+
* Returns the original response object
|
|
548
|
+
* @param {Object} meeting The meeting object
|
|
549
|
+
* @param {Object} response The response of the http request
|
|
550
|
+
* @returns {Object}
|
|
551
|
+
*/
|
|
552
|
+
updateLocusWithDelta: (meeting, response) => {
|
|
553
|
+
if (!meeting) {
|
|
554
|
+
return response;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const locus = response?.body?.locus;
|
|
558
|
+
|
|
559
|
+
if (locus) {
|
|
560
|
+
meeting.locusInfo.handleLocusDelta(locus, meeting);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
return response;
|
|
564
|
+
},
|
|
441
565
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
return Promise.reject(new MeetingNotActiveError());
|
|
445
|
-
}
|
|
566
|
+
generateBuildLocusDeltaRequestOptions: (originalMeeting) => {
|
|
567
|
+
const meetingRef = new WeakRef(originalMeeting);
|
|
446
568
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
};
|
|
569
|
+
const buildLocusDeltaRequestOptions = (originalOptions) => {
|
|
570
|
+
const meeting = meetingRef.deref();
|
|
450
571
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
.then((response) => {
|
|
454
|
-
if (response && response.body && response.body.locus) {
|
|
455
|
-
meeting.locusInfo.onFullLocus(response.body.locus);
|
|
572
|
+
if (!meeting) {
|
|
573
|
+
return originalOptions;
|
|
456
574
|
}
|
|
457
575
|
|
|
458
|
-
|
|
459
|
-
})
|
|
460
|
-
.then(() => MeetingUtil.cleanUp(meeting))
|
|
461
|
-
.catch((err) => {
|
|
462
|
-
LoggerProxy.logger.error(
|
|
463
|
-
`Meeting:util#endMeetingForAll An error occured while trying to end meeting for all with an id of ${meeting.id}, error: ${err}`
|
|
464
|
-
);
|
|
576
|
+
const options = cloneDeep(originalOptions);
|
|
465
577
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
}
|
|
578
|
+
if (!options.body) {
|
|
579
|
+
options.body = {};
|
|
580
|
+
}
|
|
469
581
|
|
|
470
|
-
MeetingUtil.
|
|
471
|
-
displayHints.includes(DISPLAY_HINTS.CAPTION_START);
|
|
582
|
+
MeetingUtil.addSequence(meeting, options.body);
|
|
472
583
|
|
|
473
|
-
|
|
474
|
-
|
|
584
|
+
return options;
|
|
585
|
+
};
|
|
475
586
|
|
|
476
|
-
|
|
477
|
-
|
|
587
|
+
return buildLocusDeltaRequestOptions;
|
|
588
|
+
},
|
|
478
589
|
|
|
479
|
-
|
|
480
|
-
|
|
590
|
+
generateLocusDeltaRequest: (originalMeeting) => {
|
|
591
|
+
const meetingRef = new WeakRef(originalMeeting);
|
|
481
592
|
|
|
482
|
-
|
|
483
|
-
|
|
593
|
+
const buildLocusDeltaRequestOptions =
|
|
594
|
+
MeetingUtil.generateBuildLocusDeltaRequestOptions(originalMeeting);
|
|
484
595
|
|
|
485
|
-
|
|
486
|
-
|
|
596
|
+
const locusDeltaRequest = (originalOptions) => {
|
|
597
|
+
const meeting = meetingRef.deref();
|
|
487
598
|
|
|
488
|
-
|
|
489
|
-
|
|
599
|
+
if (!meeting) {
|
|
600
|
+
return Promise.resolve();
|
|
601
|
+
}
|
|
490
602
|
|
|
491
|
-
|
|
492
|
-
displayHints.includes(DISPLAY_HINTS.DISPLAY_REAL_TIME_TRANSLATION);
|
|
603
|
+
const options = buildLocusDeltaRequestOptions(originalOptions);
|
|
493
604
|
|
|
494
|
-
|
|
495
|
-
|
|
605
|
+
return meeting
|
|
606
|
+
.request(options)
|
|
607
|
+
.then((response) => MeetingUtil.updateLocusWithDelta(meeting, response));
|
|
608
|
+
};
|
|
496
609
|
|
|
497
|
-
|
|
498
|
-
|
|
610
|
+
return locusDeltaRequest;
|
|
611
|
+
},
|
|
499
612
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
if (displayHints.includes(DISPLAY_HINTS.DISABLE_REACTIONS)) {
|
|
505
|
-
return false;
|
|
506
|
-
}
|
|
613
|
+
selfSupportsFeature: (feature: SELF_POLICY, userPolicies: Record<SELF_POLICY, boolean>) => {
|
|
614
|
+
if (!userPolicies) {
|
|
615
|
+
return true;
|
|
616
|
+
}
|
|
507
617
|
|
|
508
|
-
|
|
509
|
-
}
|
|
618
|
+
return userPolicies[feature];
|
|
619
|
+
},
|
|
510
620
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
621
|
+
parseInterpretationInfo: (meeting, meetingInfo) => {
|
|
622
|
+
if (!meeting || !meetingInfo) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
const siInfo = meetingInfo.simultaneousInterpretation;
|
|
626
|
+
meeting.simultaneousInterpretation.updateMeetingSIEnabled(
|
|
627
|
+
!!meetingInfo.turnOnSimultaneousInterpretation,
|
|
628
|
+
!!siInfo?.currentSIInterpreter
|
|
629
|
+
);
|
|
630
|
+
const hostSIEnabled = !!(
|
|
631
|
+
meetingInfo.turnOnSimultaneousInterpretation &&
|
|
632
|
+
meetingInfo?.meetingSiteSetting?.enableHostInterpreterControlSI
|
|
633
|
+
);
|
|
634
|
+
meeting.simultaneousInterpretation.updateHostSIEnabled(hostSIEnabled);
|
|
518
635
|
|
|
519
|
-
|
|
636
|
+
function renameKey(obj, oldKey, newKey) {
|
|
637
|
+
if (oldKey in obj) {
|
|
638
|
+
obj[newKey] = obj[oldKey];
|
|
639
|
+
delete obj[oldKey];
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
if (siInfo) {
|
|
643
|
+
const lanuagesInfo = cloneDeep(siInfo.siLanguages);
|
|
644
|
+
for (const language of lanuagesInfo) {
|
|
645
|
+
renameKey(language, 'languageCode', 'languageName');
|
|
646
|
+
renameKey(language, 'languageGroupId', 'languageCode');
|
|
647
|
+
}
|
|
648
|
+
if (!meeting.simultaneousInterpretation?.siLanguages?.length) {
|
|
649
|
+
meeting.simultaneousInterpretation.updateInterpretation({siLanguages: lanuagesInfo});
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
Trigger.trigger(
|
|
653
|
+
meeting,
|
|
654
|
+
{
|
|
655
|
+
file: 'meeting/util',
|
|
656
|
+
function: 'parseInterpretationInfo',
|
|
657
|
+
},
|
|
658
|
+
EVENT_TRIGGERS.MEETING_INTERPRETATION_UPDATE
|
|
659
|
+
);
|
|
660
|
+
},
|
|
520
661
|
};
|
|
521
|
-
MeetingUtil.canUserRenameSelfAndObserved = (displayHints) =>
|
|
522
|
-
displayHints.includes(DISPLAY_HINTS.CAN_RENAME_SELF_AND_OBSERVED);
|
|
523
|
-
|
|
524
|
-
MeetingUtil.canUserRenameOthers = (displayHints) =>
|
|
525
|
-
displayHints.includes(DISPLAY_HINTS.CAN_RENAME_OTHERS);
|
|
526
662
|
|
|
527
663
|
export default MeetingUtil;
|