@webex/plugin-meetings 3.0.0-beta.0 → 3.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/common/browser-detection.js.map +1 -1
- package/dist/common/collection.js.map +1 -1
- package/dist/common/config.js.map +1 -1
- package/dist/common/errors/captcha-error.js +7 -0
- package/dist/common/errors/captcha-error.js.map +1 -1
- package/dist/common/errors/intent-to-join.js +8 -0
- package/dist/common/errors/intent-to-join.js.map +1 -1
- package/dist/common/errors/join-meeting.js +8 -0
- package/dist/common/errors/join-meeting.js.map +1 -1
- package/dist/common/errors/media.js +7 -0
- package/dist/common/errors/media.js.map +1 -1
- package/dist/common/errors/parameter.js.map +1 -1
- package/dist/common/errors/password-error.js +7 -0
- package/dist/common/errors/password-error.js.map +1 -1
- package/dist/common/errors/permission.js +7 -0
- package/dist/common/errors/permission.js.map +1 -1
- package/dist/common/errors/reconnection-in-progress.js.map +1 -1
- package/dist/common/errors/reconnection.js +7 -0
- package/dist/common/errors/reconnection.js.map +1 -1
- package/dist/common/errors/stats.js +7 -0
- package/dist/common/errors/stats.js.map +1 -1
- package/dist/common/errors/webex-errors.js +5 -29
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/errors/webex-meetings-error.js +5 -2
- 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-config.js.map +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.js +3 -0
- package/dist/common/logs/request.js.map +1 -1
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +15 -74
- package/dist/constants.js.map +1 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/embeddedAppsUtils.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 +43 -5
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js +4 -0
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +12 -3
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +71 -210
- package/dist/media/index.js.map +1 -1
- package/dist/media/internal-media-core-wrapper.js +22 -0
- package/dist/media/internal-media-core-wrapper.js.map +1 -0
- package/dist/media/properties.js +32 -25
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.js +0 -27
- package/dist/media/util.js.map +1 -1
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/effectsState.js +8 -1
- package/dist/meeting/effectsState.js.map +1 -1
- package/dist/meeting/index.js +1130 -647
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +6 -0
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +55 -24
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/state.js.map +1 -1
- package/dist/meeting/util.js +5 -44
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/collection.js +4 -1
- package/dist/meeting-info/collection.js.map +1 -1
- package/dist/meeting-info/index.js +5 -0
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +14 -2
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/request.js +3 -0
- package/dist/meeting-info/request.js.map +1 -1
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js +4 -1
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +136 -25
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/request.js +4 -0
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js +24 -1
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +30 -7
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js +2 -1
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js +1 -0
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +82 -1
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +19 -9
- 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 +8 -0
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +133 -0
- package/dist/multistream/mediaRequestManager.js.map +1 -0
- package/dist/multistream/multistreamMedia.js +116 -0
- package/dist/multistream/multistreamMedia.js.map +1 -0
- package/dist/multistream/receiveSlot.js +209 -0
- package/dist/multistream/receiveSlot.js.map +1 -0
- package/dist/multistream/receiveSlotManager.js +195 -0
- package/dist/multistream/receiveSlotManager.js.map +1 -0
- package/dist/multistream/remoteMedia.js +289 -0
- package/dist/multistream/remoteMedia.js.map +1 -0
- package/dist/multistream/remoteMediaGroup.js +243 -0
- package/dist/multistream/remoteMediaGroup.js.map +1 -0
- package/dist/multistream/remoteMediaManager.js +1113 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -0
- package/dist/networkQualityMonitor/index.js +10 -2
- package/dist/networkQualityMonitor/index.js.map +1 -1
- package/dist/personal-meeting-room/index.js +11 -0
- package/dist/personal-meeting-room/index.js.map +1 -1
- package/dist/personal-meeting-room/request.js +2 -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 +17 -7
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +1 -0
- package/dist/reachability/request.js.map +1 -1
- package/dist/reconnection-manager/index.js +130 -132
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.js +58 -231
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +7 -116
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +20 -6
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/statsAnalyzer/global.js +2 -0
- package/dist/statsAnalyzer/global.js.map +1 -1
- package/dist/statsAnalyzer/index.js +58 -37
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +9 -3
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/transcription/index.js +10 -3
- package/dist/transcription/index.js.map +1 -1
- package/package.json +21 -20
- package/src/common/{browser-detection.js → browser-detection.ts} +1 -1
- package/src/common/collection.ts +6 -6
- package/src/common/{config.js → config.ts} +1 -1
- package/src/common/errors/{captcha-error.js → captcha-error.ts} +5 -1
- package/src/common/errors/{intent-to-join.js → intent-to-join.ts} +6 -1
- package/src/common/errors/{join-meeting.js → join-meeting.ts} +6 -1
- package/src/common/errors/{media.js → media.ts} +5 -1
- package/src/common/errors/parameter.ts +3 -2
- package/src/common/errors/{password-error.js → password-error.ts} +5 -1
- package/src/common/errors/{permission.js → permission.ts} +5 -1
- package/src/common/errors/{reconnection-in-progress.js → reconnection-in-progress.ts} +0 -0
- package/src/common/errors/{reconnection.js → reconnection.ts} +5 -1
- package/src/common/errors/{stats.js → stats.ts} +5 -1
- package/src/common/errors/{webex-errors.js → webex-errors.ts} +1 -20
- package/src/common/errors/{webex-meetings-error.js → webex-meetings-error.ts} +3 -1
- package/src/common/events/{events-scope.js → events-scope.ts} +1 -1
- package/src/common/events/{events.js → events.ts} +0 -0
- package/src/common/events/{trigger-proxy.js → trigger-proxy.ts} +1 -2
- package/src/common/events/{util.js → util.ts} +1 -1
- package/src/common/logs/{logger-config.js → logger-config.ts} +1 -2
- package/src/common/logs/{logger-proxy.js → logger-proxy.ts} +1 -1
- package/src/common/logs/{request.js → request.ts} +12 -2
- package/src/common/queue.ts +1 -2
- package/src/{config.js → config.ts} +2 -0
- package/src/constants.ts +139 -179
- package/src/locus-info/{controlsUtils.js → controlsUtils.ts} +4 -4
- package/src/locus-info/{embeddedAppsUtils.js → embeddedAppsUtils.ts} +5 -6
- package/src/locus-info/{fullState.js → fullState.ts} +1 -1
- package/src/locus-info/{hostUtils.js → hostUtils.ts} +5 -5
- package/src/locus-info/{index.js → index.ts} +67 -32
- package/src/locus-info/{infoUtils.js → infoUtils.ts} +7 -4
- package/src/locus-info/{mediaSharesUtils.js → mediaSharesUtils.ts} +13 -13
- package/src/locus-info/{parser.js → parser.ts} +22 -12
- package/src/locus-info/{selfUtils.js → selfUtils.ts} +17 -19
- package/src/media/{index.js → index.ts} +130 -205
- package/src/media/internal-media-core-wrapper.ts +9 -0
- package/src/media/{properties.js → properties.ts} +35 -29
- package/src/media/util.ts +16 -0
- package/src/mediaQualityMetrics/{config.js → config.ts} +1 -1
- package/src/meeting/{effectsState.js → effectsState.ts} +12 -6
- package/src/meeting/{index.js → index.ts} +1016 -550
- package/src/meeting/{muteState.js → muteState.ts} +16 -11
- package/src/meeting/{request.js → request.ts} +125 -36
- package/src/meeting/{state.js → state.ts} +6 -6
- package/src/meeting/{util.js → util.ts} +9 -51
- package/src/meeting-info/{collection.js → collection.ts} +4 -1
- package/src/meeting-info/{index.js → index.ts} +10 -6
- package/src/meeting-info/{meeting-info-v2.js → meeting-info-v2.ts} +28 -10
- package/src/meeting-info/{request.js → request.ts} +6 -2
- package/src/meeting-info/{util.js → util.ts} +6 -5
- package/src/meeting-info/{utilv2.js → utilv2.ts} +8 -7
- package/src/meetings/{collection.js → collection.ts} +5 -2
- package/src/meetings/{index.js → index.ts} +118 -22
- package/src/meetings/{request.js → request.ts} +6 -1
- package/src/meetings/{util.js → util.ts} +28 -5
- package/src/member/{index.js → index.ts} +46 -15
- package/src/member/{util.js → util.ts} +17 -16
- package/src/members/{collection.js → collection.ts} +2 -1
- package/src/members/{index.js → index.ts} +94 -26
- package/src/members/{request.js → request.ts} +16 -5
- package/src/members/{util.js → util.ts} +7 -7
- package/src/metrics/{config.js → config.ts} +0 -2
- package/src/metrics/{constants.js → constants.ts} +0 -0
- package/src/metrics/{index.js → index.ts} +27 -8
- package/src/multistream/mediaRequestManager.ts +166 -0
- package/src/multistream/multistreamMedia.ts +92 -0
- package/src/multistream/receiveSlot.ts +141 -0
- package/src/multistream/receiveSlotManager.ts +142 -0
- package/src/multistream/remoteMedia.ts +228 -0
- package/src/multistream/remoteMediaGroup.ts +224 -0
- package/src/multistream/remoteMediaManager.ts +911 -0
- package/src/networkQualityMonitor/{index.js → index.ts} +18 -3
- package/src/personal-meeting-room/{index.js → index.ts} +17 -4
- package/src/personal-meeting-room/{request.js → request.ts} +3 -1
- package/src/personal-meeting-room/{util.js → util.ts} +1 -1
- package/src/reachability/{index.js → index.ts} +28 -17
- package/src/reachability/request.ts +4 -2
- package/src/reconnection-manager/{index.js → index.ts} +81 -65
- package/src/roap/index.ts +229 -0
- package/src/roap/{request.js → request.ts} +15 -74
- package/src/roap/turnDiscovery.ts +26 -11
- package/src/statsAnalyzer/{global.js → global.ts} +2 -0
- package/src/statsAnalyzer/{index.js → index.ts} +66 -61
- package/src/statsAnalyzer/{mqaUtil.js → mqaUtil.ts} +6 -1
- package/src/transcription/{index.js → index.ts} +16 -11
- package/test/integration/spec/journey.js +1 -1
- package/test/integration/spec/space-meeting.js +1 -2
- package/test/unit/spec/locus-info/infoUtils.js +17 -1
- package/test/unit/spec/media/index.ts +207 -0
- package/test/unit/spec/media/properties.ts +73 -82
- package/test/unit/spec/meeting/effectsState.js +1 -3
- package/test/unit/spec/meeting/index.js +585 -245
- package/test/unit/spec/meeting/muteState.js +7 -0
- package/test/unit/spec/meeting/utils.js +63 -2
- package/test/unit/spec/meetings/index.js +0 -4
- package/test/unit/spec/members/index.js +164 -2
- package/test/unit/spec/multistream/mediaRequestManager.ts +515 -0
- package/test/unit/spec/multistream/receiveSlot.ts +104 -0
- package/test/unit/spec/multistream/receiveSlotManager.ts +173 -0
- package/test/unit/spec/multistream/remoteMedia.ts +225 -0
- package/test/unit/spec/multistream/remoteMediaGroup.ts +396 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +1309 -0
- package/test/unit/spec/reconnection-manager/index.js +68 -2
- package/test/unit/spec/roap/index.ts +63 -35
- package/test/unit/spec/stats-analyzer/index.js +19 -22
- package/dist/peer-connection-manager/index.js +0 -794
- package/dist/peer-connection-manager/index.js.map +0 -1
- package/dist/peer-connection-manager/util.js +0 -124
- package/dist/peer-connection-manager/util.js.map +0 -1
- package/dist/roap/collection.js +0 -73
- package/dist/roap/collection.js.map +0 -1
- package/dist/roap/handler.js +0 -337
- package/dist/roap/handler.js.map +0 -1
- package/dist/roap/state.js +0 -164
- package/dist/roap/state.js.map +0 -1
- package/dist/roap/util.js +0 -102
- package/dist/roap/util.js.map +0 -1
- package/src/media/util.js +0 -38
- package/src/peer-connection-manager/index.js +0 -723
- package/src/peer-connection-manager/util.ts +0 -117
- package/src/roap/collection.js +0 -63
- package/src/roap/handler.js +0 -252
- package/src/roap/index.js +0 -380
- package/src/roap/state.js +0 -149
- package/src/roap/util.js +0 -93
- package/test/unit/spec/peerconnection-manager/index.js +0 -188
- package/test/unit/spec/peerconnection-manager/utils.js +0 -48
- package/test/unit/spec/peerconnection-manager/utils.test-fixtures.ts +0 -389
- package/test/unit/spec/roap/util.js +0 -30
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import uuid from 'uuid';
|
|
2
|
-
import {cloneDeep, isEqual, pick, isString} from 'lodash';
|
|
2
|
+
import {cloneDeep, isEqual, pick, isString, defer} from 'lodash';
|
|
3
|
+
// @ts-ignore - Fix this
|
|
3
4
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
4
|
-
import {Media as WebRTCMedia} from '@webex/internal-media-core';
|
|
5
|
+
import {Media as WebRTCMedia, MediaConnection as MC} from '@webex/internal-media-core';
|
|
5
6
|
|
|
6
7
|
import {
|
|
7
8
|
MeetingNotActiveError, createMeetingsError, UserInLobbyError,
|
|
8
|
-
NoMediaEstablishedYetError, UserNotJoinedError
|
|
9
|
+
NoMediaEstablishedYetError, UserNotJoinedError
|
|
9
10
|
} from '../common/errors/webex-errors';
|
|
10
11
|
import {StatsAnalyzer, EVENTS as StatsAnalyzerEvents} from '../statsAnalyzer';
|
|
11
12
|
import NetworkQualityMonitor from '../networkQualityMonitor';
|
|
@@ -18,9 +19,8 @@ import MeetingStateMachine from '../meeting/state';
|
|
|
18
19
|
import createMuteState from '../meeting/muteState';
|
|
19
20
|
import createEffectsState from '../meeting/effectsState';
|
|
20
21
|
import LocusInfo from '../locus-info';
|
|
21
|
-
import PeerConnectionManager from '../peer-connection-manager';
|
|
22
22
|
import Metrics from '../metrics';
|
|
23
|
-
import {trigger, mediaType, eventType} from '../metrics/config';
|
|
23
|
+
import {trigger, mediaType, error as MetricsError, eventType} from '../metrics/config';
|
|
24
24
|
import ReconnectionManager from '../reconnection-manager';
|
|
25
25
|
import MeetingRequest from '../meeting/request';
|
|
26
26
|
import Members from '../members/index';
|
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
_INCOMING_,
|
|
37
37
|
_JOIN_,
|
|
38
38
|
AUDIO,
|
|
39
|
-
CONNECTION_STATE,
|
|
40
39
|
CONTENT,
|
|
41
40
|
ENDED,
|
|
42
41
|
EVENT_TRIGGERS,
|
|
@@ -45,7 +44,6 @@ import {
|
|
|
45
44
|
FLOOR_ACTION,
|
|
46
45
|
FULL_STATE,
|
|
47
46
|
LAYOUT_TYPES,
|
|
48
|
-
LIVE,
|
|
49
47
|
LOCUSINFO,
|
|
50
48
|
MEETING_INFO_FAILURE_REASON,
|
|
51
49
|
MEETING_REMOVED_REASON,
|
|
@@ -58,13 +56,9 @@ import {
|
|
|
58
56
|
ONLINE,
|
|
59
57
|
OFFLINE,
|
|
60
58
|
PASSWORD_STATUS,
|
|
61
|
-
PC_BAIL_TIMEOUT,
|
|
62
59
|
PSTN_STATUS,
|
|
63
60
|
QUALITY_LEVELS,
|
|
64
61
|
RECORDING_STATE,
|
|
65
|
-
ROAP_SEQ_PRE,
|
|
66
|
-
SDP,
|
|
67
|
-
SENDRECV,
|
|
68
62
|
SHARE_STATUS,
|
|
69
63
|
SHARE_STOPPED_REASON,
|
|
70
64
|
VIDEO_RESOLUTIONS,
|
|
@@ -77,14 +71,17 @@ import ParameterError from '../common/errors/parameter';
|
|
|
77
71
|
import MediaError from '../common/errors/media';
|
|
78
72
|
import {MeetingInfoV2PasswordError, MeetingInfoV2CaptchaError} from '../meeting-info/meeting-info-v2';
|
|
79
73
|
import BrowserDetection from '../common/browser-detection';
|
|
80
|
-
import
|
|
74
|
+
import {ReceiveSlotManager} from '../multistream/receiveSlotManager';
|
|
75
|
+
import {MediaRequestManager} from '../multistream/mediaRequestManager';
|
|
76
|
+
import {RemoteMediaManager, Event as RemoteMediaManagerEvent} from '../multistream/remoteMediaManager';
|
|
77
|
+
import {MultistreamMedia} from '../multistream/multistreamMedia';
|
|
81
78
|
|
|
82
79
|
import InMeetingActions from './in-meeting-actions';
|
|
83
80
|
|
|
84
81
|
|
|
85
82
|
const {isBrowser} = BrowserDetection();
|
|
86
83
|
|
|
87
|
-
const logRequest = (request, {header = '', success = '', failure = ''}) => {
|
|
84
|
+
const logRequest = (request: any, { header = '', success = '', failure = '' }) => {
|
|
88
85
|
LoggerProxy.logger.info(header);
|
|
89
86
|
|
|
90
87
|
return request
|
|
@@ -145,6 +142,7 @@ export const MEDIA_UPDATE_TYPE = {
|
|
|
145
142
|
* @property {String} [meetingQuality.local]
|
|
146
143
|
* @property {String} [meetingQuality.remote]
|
|
147
144
|
* @property {Boolean} [rejoin]
|
|
145
|
+
* @property {Boolean} [enableMultistream]
|
|
148
146
|
*/
|
|
149
147
|
|
|
150
148
|
/**
|
|
@@ -394,6 +392,92 @@ export const MEDIA_UPDATE_TYPE = {
|
|
|
394
392
|
* @class Meeting
|
|
395
393
|
*/
|
|
396
394
|
export default class Meeting extends StatelessWebexPlugin {
|
|
395
|
+
attrs: any;
|
|
396
|
+
audio: any;
|
|
397
|
+
conversationUrl: string;
|
|
398
|
+
correlationId: string;
|
|
399
|
+
destination: string;
|
|
400
|
+
destinationType: string;
|
|
401
|
+
deviceUrl: string;
|
|
402
|
+
effects: any;
|
|
403
|
+
hostId: string;
|
|
404
|
+
id: string;
|
|
405
|
+
isMultistream: boolean;
|
|
406
|
+
locusUrl: string;
|
|
407
|
+
mediaConnections: any[];
|
|
408
|
+
mediaId?: string;
|
|
409
|
+
meetingFiniteStateMachine: any;
|
|
410
|
+
meetingInfo: object;
|
|
411
|
+
meetingRequest: any;
|
|
412
|
+
members: Members;
|
|
413
|
+
options: object;
|
|
414
|
+
orgId: string;
|
|
415
|
+
owner: string;
|
|
416
|
+
partner: any;
|
|
417
|
+
policy: string;
|
|
418
|
+
reconnectionManager: ReconnectionManager;
|
|
419
|
+
resource: string;
|
|
420
|
+
roap: Roap;
|
|
421
|
+
roapSeq: number;
|
|
422
|
+
sipUri: string;
|
|
423
|
+
type: string;
|
|
424
|
+
userId: string;
|
|
425
|
+
video: any;
|
|
426
|
+
callEvents: any[];
|
|
427
|
+
deferJoin: Promise<any>;
|
|
428
|
+
dialInDeviceStatus: string;
|
|
429
|
+
dialInUrl: string;
|
|
430
|
+
dialOutDeviceStatus: string;
|
|
431
|
+
dialOutUrl: string;
|
|
432
|
+
fetchMeetingInfoTimeoutId: NodeJS.Timeout;
|
|
433
|
+
floorGrantPending: boolean;
|
|
434
|
+
hasJoinedOnce: boolean;
|
|
435
|
+
hasWebsocketConnected: boolean;
|
|
436
|
+
inMeetingActions: InMeetingActions;
|
|
437
|
+
isLocalShareLive: boolean;
|
|
438
|
+
isRoapInProgress: boolean;
|
|
439
|
+
isSharing: boolean;
|
|
440
|
+
keepAliveTimerId: NodeJS.Timeout;
|
|
441
|
+
lastVideoLayoutInfo: any;
|
|
442
|
+
locusInfo: any;
|
|
443
|
+
media: MultistreamMedia;
|
|
444
|
+
mediaProperties: MediaProperties;
|
|
445
|
+
mediaRequestManagers: {
|
|
446
|
+
audio: MediaRequestManager;
|
|
447
|
+
video: MediaRequestManager;
|
|
448
|
+
};
|
|
449
|
+
meetingInfoFailureReason: string;
|
|
450
|
+
networkQualityMonitor: NetworkQualityMonitor;
|
|
451
|
+
networkStatus: string;
|
|
452
|
+
passwordStatus: string;
|
|
453
|
+
queuedMediaUpdates: any[];
|
|
454
|
+
recording: any;
|
|
455
|
+
remoteMediaManager: RemoteMediaManager | null;
|
|
456
|
+
requiredCaptcha: any;
|
|
457
|
+
receiveSlotManager: ReceiveSlotManager;
|
|
458
|
+
shareStatus: string;
|
|
459
|
+
statsAnalyzer: StatsAnalyzer;
|
|
460
|
+
transcription: Transcription;
|
|
461
|
+
updateMediaConnections: (mediaConnections: any[]) => void;
|
|
462
|
+
endCallInitiateJoinReq: any;
|
|
463
|
+
endJoinReqResp: any;
|
|
464
|
+
endLocalSDPGenRemoteSDPRecvDelay: any;
|
|
465
|
+
joinedWith: any;
|
|
466
|
+
locusId: any;
|
|
467
|
+
startCallInitiateJoinReq: any;
|
|
468
|
+
startJoinReqResp: any;
|
|
469
|
+
startLocalSDPGenRemoteSDPRecvDelay: any;
|
|
470
|
+
wirelessShare: any;
|
|
471
|
+
guest: any;
|
|
472
|
+
meetingJoinUrl: any;
|
|
473
|
+
meetingNumber: any;
|
|
474
|
+
meetingState: any;
|
|
475
|
+
permissionToken: any;
|
|
476
|
+
resourceId: any;
|
|
477
|
+
resourceUrl: string;
|
|
478
|
+
selfId: string;
|
|
479
|
+
state: any;
|
|
480
|
+
|
|
397
481
|
namespace = MEETINGS;
|
|
398
482
|
|
|
399
483
|
/**
|
|
@@ -402,7 +486,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
402
486
|
* @constructor
|
|
403
487
|
* @memberof Meeting
|
|
404
488
|
*/
|
|
405
|
-
constructor(attrs, options) {
|
|
489
|
+
constructor(attrs: any, options: object) {
|
|
406
490
|
super({}, options);
|
|
407
491
|
/**
|
|
408
492
|
* @instance
|
|
@@ -470,15 +554,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
470
554
|
* @memberof Meeting
|
|
471
555
|
*/
|
|
472
556
|
this.deviceUrl = attrs.deviceUrl;
|
|
473
|
-
/**
|
|
474
|
-
* @description set you -1 as default values is 0 (used to idenfify if 1st roap request was sent)
|
|
475
|
-
* @instance
|
|
476
|
-
* @type {Number}
|
|
477
|
-
* @readonly
|
|
478
|
-
* @private
|
|
479
|
-
* @memberof Meeting
|
|
480
|
-
*/
|
|
481
|
-
this.roapSeq = ROAP_SEQ_PRE;
|
|
482
557
|
/**
|
|
483
558
|
* @instance
|
|
484
559
|
* @type {Object}
|
|
@@ -488,13 +563,44 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
488
563
|
*/
|
|
489
564
|
// TODO: needs to be defined as a class
|
|
490
565
|
this.meetingInfo = {};
|
|
566
|
+
/**
|
|
567
|
+
* helper class for managing receive slots (for multistream media connections)
|
|
568
|
+
*/
|
|
569
|
+
this.receiveSlotManager = new ReceiveSlotManager(this);
|
|
570
|
+
/**
|
|
571
|
+
* Helper class for managing media requests for main video (for multistream media connections)
|
|
572
|
+
* All media requests sent out for main video for this meeting have to go through it.
|
|
573
|
+
*/
|
|
574
|
+
this.mediaRequestManagers = {
|
|
575
|
+
audio: new MediaRequestManager((mediaRequests) => {
|
|
576
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
577
|
+
LoggerProxy.logger.warn('Meeting:index#mediaRequestManager --> trying to send audio media request before media connection was created');
|
|
578
|
+
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
this.mediaProperties.webrtcMediaConnection.requestMedia(MC.MediaType.AudioMain, mediaRequests);
|
|
582
|
+
}),
|
|
583
|
+
video: new MediaRequestManager((mediaRequests) => {
|
|
584
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
585
|
+
LoggerProxy.logger.warn('Meeting:index#mediaRequestManager --> trying to send video media request before media connection was created');
|
|
586
|
+
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
this.mediaProperties.webrtcMediaConnection.requestMedia(MC.MediaType.VideoMain, mediaRequests);
|
|
590
|
+
})
|
|
591
|
+
};
|
|
491
592
|
/**
|
|
492
593
|
* @instance
|
|
493
594
|
* @type {Members}
|
|
494
595
|
* @public
|
|
495
596
|
* @memberof Meeting
|
|
496
597
|
*/
|
|
497
|
-
this.members = new Members({
|
|
598
|
+
this.members = new Members({
|
|
599
|
+
locusUrl: (attrs.locus && attrs.locus.url),
|
|
600
|
+
receiveSlotManager: this.receiveSlotManager,
|
|
601
|
+
mediaRequestManagers: this.mediaRequestManagers,
|
|
602
|
+
// @ts-ignore - Fix type
|
|
603
|
+
}, {parent: this.webex});
|
|
498
604
|
/**
|
|
499
605
|
* @instance
|
|
500
606
|
* @type {Roap}
|
|
@@ -502,7 +608,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
502
608
|
* @private
|
|
503
609
|
* @memberof Meeting
|
|
504
610
|
*/
|
|
611
|
+
// @ts-ignore - Fix type
|
|
505
612
|
this.roap = new Roap({}, {parent: this.webex});
|
|
613
|
+
/**
|
|
614
|
+
* indicates if an SDP exchange is happening
|
|
615
|
+
*
|
|
616
|
+
* @instance
|
|
617
|
+
* @type {Boolean}
|
|
618
|
+
* @readonly
|
|
619
|
+
* @private
|
|
620
|
+
* @memberof Meeting
|
|
621
|
+
*/
|
|
622
|
+
this.isRoapInProgress = false;
|
|
506
623
|
/**
|
|
507
624
|
* created later
|
|
508
625
|
* @instance
|
|
@@ -640,6 +757,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
640
757
|
*/
|
|
641
758
|
this.mediaConnections = null;
|
|
642
759
|
|
|
760
|
+
/**
|
|
761
|
+
* If true, then media is sent over multiple separate streams.
|
|
762
|
+
* If false, then media is transcoded by the server into a single stream.
|
|
763
|
+
*/
|
|
764
|
+
this.isMultistream = false;
|
|
643
765
|
/**
|
|
644
766
|
* Fetching meeting info can be done randomly 2-5 mins before meeting start
|
|
645
767
|
* In case it is done before the timer expires, this timeout id is reset to cancel the timer.
|
|
@@ -658,7 +780,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
658
780
|
* @private
|
|
659
781
|
* @memberof Meeting
|
|
660
782
|
*/
|
|
661
|
-
this.updateMediaConnections = (mediaConnections) => {
|
|
783
|
+
this.updateMediaConnections = (mediaConnections: any[]) => {
|
|
662
784
|
if (!isEqual(this.mediaConnections, mediaConnections)) {
|
|
663
785
|
// grab last/latest item in the new mediaConnections information
|
|
664
786
|
this.mediaConnections = mediaConnections.slice(-1);
|
|
@@ -691,35 +813,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
691
813
|
this.isSharing = false;
|
|
692
814
|
/**
|
|
693
815
|
* @instance
|
|
694
|
-
* @type {
|
|
816
|
+
* @type {string}
|
|
695
817
|
* @readonly
|
|
696
818
|
* @public
|
|
697
819
|
* @memberof Meeting
|
|
698
820
|
*/
|
|
699
821
|
this.shareStatus = SHARE_STATUS.NO_SHARE;
|
|
700
|
-
/**
|
|
701
|
-
* @instance
|
|
702
|
-
* @type {Boolean}
|
|
703
|
-
* @readonly
|
|
704
|
-
* @private
|
|
705
|
-
* @memberof Meeting
|
|
706
|
-
*/
|
|
707
|
-
Object.defineProperty(this, 'isLocalShareLive', {
|
|
708
|
-
get: () => {
|
|
709
|
-
const {shareTransceiver} = this.mediaProperties.peerConnection;
|
|
710
|
-
const shareDirection = shareTransceiver?.direction;
|
|
711
|
-
const trackReadyState = shareTransceiver?.sender?.track?.readyState;
|
|
712
|
-
const activeShare = trackReadyState === LIVE;
|
|
713
|
-
const offersToSendData = shareDirection === SENDRECV;
|
|
714
|
-
|
|
715
|
-
if (activeShare && offersToSendData) {
|
|
716
|
-
return true;
|
|
717
|
-
}
|
|
718
822
|
|
|
719
|
-
return false;
|
|
720
|
-
},
|
|
721
|
-
configurable: true
|
|
722
|
-
});
|
|
723
823
|
/**
|
|
724
824
|
* @instance
|
|
725
825
|
* @type {Array}
|
|
@@ -731,7 +831,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
731
831
|
/**
|
|
732
832
|
* There is a pending floor requested by the user
|
|
733
833
|
* @instance
|
|
734
|
-
* @type {
|
|
834
|
+
* @type {boolean}
|
|
735
835
|
* @private
|
|
736
836
|
* @memberof Meeting
|
|
737
837
|
*/
|
|
@@ -799,6 +899,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
799
899
|
* @private
|
|
800
900
|
* @memberof Meeting
|
|
801
901
|
*/
|
|
902
|
+
// @ts-ignore - Fix type
|
|
802
903
|
this.locusInfo = new LocusInfo(this.updateMeetingObject.bind(this), this.webex, this.id);
|
|
803
904
|
// We had to add listeners first before setting up the locus instance
|
|
804
905
|
/**
|
|
@@ -826,6 +927,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
826
927
|
* @private
|
|
827
928
|
* @memberof Meeting
|
|
828
929
|
*/
|
|
930
|
+
// @ts-ignore - Fix type
|
|
829
931
|
this.hasWebsocketConnected = this.webex.internal.mercury.connected;
|
|
830
932
|
|
|
831
933
|
/**
|
|
@@ -901,6 +1003,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
901
1003
|
this.setUpLocusInfoListeners();
|
|
902
1004
|
this.locusInfo.init(attrs.locus ? attrs.locus : {});
|
|
903
1005
|
this.hasJoinedOnce = false;
|
|
1006
|
+
|
|
1007
|
+
this.media = new MultistreamMedia(this);
|
|
1008
|
+
|
|
1009
|
+
/**
|
|
1010
|
+
* helper class for managing remote streams
|
|
1011
|
+
*/
|
|
1012
|
+
this.remoteMediaManager = null;
|
|
904
1013
|
}
|
|
905
1014
|
|
|
906
1015
|
/**
|
|
@@ -912,9 +1021,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
912
1021
|
* @memberof Meeting
|
|
913
1022
|
* @returns {Promise}
|
|
914
1023
|
*/
|
|
915
|
-
async fetchMeetingInfo({
|
|
916
|
-
password = null, captchaCode = null
|
|
917
|
-
}) {
|
|
1024
|
+
public async fetchMeetingInfo({ password = null, captchaCode = null }: { password?: string; captchaCode?: string }) {
|
|
918
1025
|
// when fetch meeting info is called directly by the client, we want to clear out the random timer for sdk to do it
|
|
919
1026
|
if (this.fetchMeetingInfoTimeoutId) {
|
|
920
1027
|
clearTimeout(this.fetchMeetingInfoTimeoutId);
|
|
@@ -956,6 +1063,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
956
1063
|
}
|
|
957
1064
|
catch (err) {
|
|
958
1065
|
if (err instanceof MeetingInfoV2PasswordError) {
|
|
1066
|
+
// @ts-ignore
|
|
959
1067
|
LoggerProxy.logger.info(`Meeting:index#fetchMeetingInfo --> Info Unable to fetch meeting info for ${this.destination} - password required (code=${err?.body?.code}).`);
|
|
960
1068
|
|
|
961
1069
|
// when wbxappapi requires password it still populates partial meeting info in the response
|
|
@@ -974,6 +1082,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
974
1082
|
throw (new PasswordError());
|
|
975
1083
|
}
|
|
976
1084
|
else if (err instanceof MeetingInfoV2CaptchaError) {
|
|
1085
|
+
// @ts-ignore
|
|
977
1086
|
LoggerProxy.logger.info(`Meeting:index#fetchMeetingInfo --> Info Unable to fetch meeting info for ${this.destination} - captcha required (code=${err?.body?.code}).`);
|
|
978
1087
|
|
|
979
1088
|
this.meetingInfoFailureReason = (this.requiredCaptcha) ?
|
|
@@ -1003,7 +1112,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1003
1112
|
* @memberof Meeting
|
|
1004
1113
|
* @returns {Promise<{isPasswordValid: boolean, requiredCaptcha: boolean, failureReason: MEETING_INFO_FAILURE_REASON}>}
|
|
1005
1114
|
*/
|
|
1006
|
-
verifyPassword(password, captchaCode) {
|
|
1115
|
+
public verifyPassword(password: string, captchaCode: string) {
|
|
1007
1116
|
return this.fetchMeetingInfo({
|
|
1008
1117
|
password, captchaCode
|
|
1009
1118
|
})
|
|
@@ -1033,7 +1142,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1033
1142
|
* @memberof Meeting
|
|
1034
1143
|
* @returns {Promise}
|
|
1035
1144
|
*/
|
|
1036
|
-
refreshCaptcha() {
|
|
1145
|
+
public refreshCaptcha() {
|
|
1037
1146
|
if (!this.requiredCaptcha) {
|
|
1038
1147
|
return Promise.reject(new Error('There is no captcha to refresh'));
|
|
1039
1148
|
}
|
|
@@ -1063,7 +1172,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1063
1172
|
* @private
|
|
1064
1173
|
* @memberof Meeting
|
|
1065
1174
|
*/
|
|
1066
|
-
setUpLocusInfoListeners() {
|
|
1175
|
+
private setUpLocusInfoListeners() {
|
|
1067
1176
|
// meeting update listeners
|
|
1068
1177
|
this.setUpLocusInfoSelfListener();
|
|
1069
1178
|
this.setUpLocusInfoMeetingListener();
|
|
@@ -1081,14 +1190,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1081
1190
|
this.setUpLocusInfoMediaInactiveListener();
|
|
1082
1191
|
}
|
|
1083
1192
|
|
|
1084
|
-
|
|
1085
1193
|
/**
|
|
1086
1194
|
* Set up the locus info listener for meetings disconnected due to inactivity
|
|
1087
1195
|
* @returns {undefined}
|
|
1088
1196
|
* @private
|
|
1089
1197
|
* @memberof Meeting
|
|
1090
1198
|
*/
|
|
1091
|
-
setUpLocusInfoMediaInactiveListener() {
|
|
1199
|
+
private setUpLocusInfoMediaInactiveListener() {
|
|
1092
1200
|
// User gets kicked off the meeting due to inactivity or user did a refresh
|
|
1093
1201
|
this.locusInfo.on(EVENTS.DISCONNECT_DUE_TO_INACTIVITY, (res) => {
|
|
1094
1202
|
// https:// jira-eng-gpk2.cisco.com/jira/browse/SPARK-240520
|
|
@@ -1116,6 +1224,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1116
1224
|
|
|
1117
1225
|
LoggerProxy.logger.error(`Meeting:index#setUpLocusInfoMediaInactiveListener --> Meeting disconnected due to inactivity: ${res.reason}`);
|
|
1118
1226
|
|
|
1227
|
+
// @ts-ignore - config coming from registerPlugin
|
|
1119
1228
|
if (this.config.reconnection.autoRejoin) {
|
|
1120
1229
|
this.reconnect();
|
|
1121
1230
|
}
|
|
@@ -1139,7 +1248,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1139
1248
|
* @private
|
|
1140
1249
|
* @memberof Meeting
|
|
1141
1250
|
*/
|
|
1142
|
-
setUpLocusInfoAssignHostListener() {
|
|
1251
|
+
private setUpLocusInfoAssignHostListener() {
|
|
1143
1252
|
this.locusInfo.on(EVENTS.LOCUS_INFO_CAN_ASSIGN_HOST, (payload) => {
|
|
1144
1253
|
const changed = this.inMeetingActions.set({
|
|
1145
1254
|
canAssignHost: payload.canAssignHost,
|
|
@@ -1165,7 +1274,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1165
1274
|
* @private
|
|
1166
1275
|
* @memberof Meeting
|
|
1167
1276
|
*/
|
|
1168
|
-
setUpLocusFullStateListener() {
|
|
1277
|
+
private setUpLocusFullStateListener() {
|
|
1169
1278
|
this.locusInfo.on(LOCUSINFO.EVENTS.FULL_STATE_MEETING_STATE_CHANGE, (payload) => {
|
|
1170
1279
|
Trigger.trigger(
|
|
1171
1280
|
this,
|
|
@@ -1196,7 +1305,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1196
1305
|
* @returns {Object}
|
|
1197
1306
|
* @memberof Meeting
|
|
1198
1307
|
*/
|
|
1199
|
-
getAnalyzerMetricsPrePayload(options
|
|
1308
|
+
getAnalyzerMetricsPrePayload(options: {
|
|
1309
|
+
event: string;
|
|
1310
|
+
trackingId: string;
|
|
1311
|
+
locus: object;
|
|
1312
|
+
mediaConnections: Array<any>;
|
|
1313
|
+
errors: object;
|
|
1314
|
+
} | any) {
|
|
1200
1315
|
if (options) {
|
|
1201
1316
|
const {
|
|
1202
1317
|
event,
|
|
@@ -1210,11 +1325,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1210
1325
|
return null;
|
|
1211
1326
|
}
|
|
1212
1327
|
|
|
1213
|
-
const identifiers = {
|
|
1328
|
+
const identifiers: any = {
|
|
1214
1329
|
correlationId: this.correlationId,
|
|
1215
1330
|
userId: this.userId,
|
|
1216
1331
|
deviceId: this.deviceUrl,
|
|
1217
1332
|
orgId: this.orgId,
|
|
1333
|
+
// @ts-ignore fix type
|
|
1218
1334
|
locusUrl: this.webex.internal.services.get('locus')
|
|
1219
1335
|
};
|
|
1220
1336
|
|
|
@@ -1336,12 +1452,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1336
1452
|
* @private
|
|
1337
1453
|
* @memberof Meeting
|
|
1338
1454
|
*/
|
|
1339
|
-
sendCallAnalyzerMetrics(options) {
|
|
1455
|
+
private sendCallAnalyzerMetrics(options: { event: string; trackingId: string; locus: object; errors: object }) {
|
|
1340
1456
|
const payload = this.getAnalyzerMetricsPrePayload({
|
|
1457
|
+
// @ts-ignore - config coming from registerPlugin
|
|
1341
1458
|
...pick(this.config.metrics, ['clientType', 'subClientType']),
|
|
1342
1459
|
...options
|
|
1343
1460
|
});
|
|
1344
1461
|
|
|
1462
|
+
// @ts-ignore - fix type
|
|
1345
1463
|
return this.webex.internal.metrics.submitCallDiagnosticEvents(payload);
|
|
1346
1464
|
}
|
|
1347
1465
|
|
|
@@ -1355,13 +1473,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1355
1473
|
* @private
|
|
1356
1474
|
* @memberof Meeting
|
|
1357
1475
|
*/
|
|
1358
|
-
sendMediaQualityAnalyzerMetrics(options) {
|
|
1476
|
+
private sendMediaQualityAnalyzerMetrics(options: { event: string; trackingId: string; locus: object }) {
|
|
1359
1477
|
const payload = this.getAnalyzerMetricsPrePayload({
|
|
1360
1478
|
type: MQA_STATS.CA_TYPE,
|
|
1479
|
+
// @ts-ignore - config coming from registerPlugin
|
|
1361
1480
|
...pick(this.config.metrics, ['clientType', 'subClientType']),
|
|
1362
1481
|
...options
|
|
1363
1482
|
});
|
|
1364
1483
|
|
|
1484
|
+
// @ts-ignore
|
|
1365
1485
|
return this.webex.internal.metrics.submitCallDiagnosticEvents(payload);
|
|
1366
1486
|
}
|
|
1367
1487
|
|
|
@@ -1372,7 +1492,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1372
1492
|
* @returns {undefined}
|
|
1373
1493
|
* @memberof Meeting
|
|
1374
1494
|
*/
|
|
1375
|
-
setNetworkStatus(networkStatus) {
|
|
1495
|
+
private setNetworkStatus(networkStatus: string) {
|
|
1376
1496
|
if (networkStatus === NETWORK_STATUS.DISCONNECTED) {
|
|
1377
1497
|
Trigger.trigger(
|
|
1378
1498
|
this,
|
|
@@ -1405,14 +1525,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1405
1525
|
* @private
|
|
1406
1526
|
* @memberof Meeting
|
|
1407
1527
|
*/
|
|
1408
|
-
setUpLocusSelfListener() {
|
|
1528
|
+
private setUpLocusSelfListener() {
|
|
1409
1529
|
this.locusInfo.on(EVENTS.LOCUS_INFO_UPDATE_SELF, (payload) => {
|
|
1410
1530
|
this.members.locusSelfUpdate(payload);
|
|
1411
1531
|
this.pstnUpdate(payload);
|
|
1412
1532
|
|
|
1413
1533
|
// If user moved to a JOINED state and there is a pending floor grant trigger it
|
|
1414
1534
|
if (this.floorGrantPending && payload.newSelf.state === MEETING_STATE.STATES.JOINED) {
|
|
1415
|
-
this.
|
|
1535
|
+
this.requestScreenShareFloor()
|
|
1416
1536
|
.then(() => { this.floorGrantPending = false; });
|
|
1417
1537
|
}
|
|
1418
1538
|
});
|
|
@@ -1425,7 +1545,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1425
1545
|
* @private
|
|
1426
1546
|
* @memberof Meeting
|
|
1427
1547
|
*/
|
|
1428
|
-
pstnUpdate(payload) {
|
|
1548
|
+
private pstnUpdate(payload: any) {
|
|
1429
1549
|
if (this.locusInfo.self) {
|
|
1430
1550
|
const dialInPstnDevice = payload.newSelf?.pstnDevices.find((device) => device.url === this.dialInUrl);
|
|
1431
1551
|
const dialOutPstnDevice = payload.newSelf?.pstnDevices.find((device) => device.url === this.dialOutUrl);
|
|
@@ -1480,7 +1600,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1480
1600
|
* @private
|
|
1481
1601
|
* @memberof Meeting
|
|
1482
1602
|
*/
|
|
1483
|
-
setUpLocusHostListener() {
|
|
1603
|
+
private setUpLocusHostListener() {
|
|
1484
1604
|
this.locusInfo.on(EVENTS.LOCUS_INFO_UPDATE_HOST, (payload) => {
|
|
1485
1605
|
this.members.locusHostUpdate(payload);
|
|
1486
1606
|
});
|
|
@@ -1494,13 +1614,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1494
1614
|
* @private
|
|
1495
1615
|
* @memberof Meeting
|
|
1496
1616
|
*/
|
|
1497
|
-
setUpLocusParticipantsListener() {
|
|
1617
|
+
private setUpLocusParticipantsListener() {
|
|
1498
1618
|
this.locusInfo.on(EVENTS.LOCUS_INFO_UPDATE_PARTICIPANTS, (payload) => {
|
|
1499
1619
|
this.members.locusParticipantsUpdate(payload);
|
|
1500
1620
|
});
|
|
1501
1621
|
}
|
|
1502
1622
|
|
|
1503
|
-
|
|
1504
1623
|
/**
|
|
1505
1624
|
* Set up the locus info recording update listener
|
|
1506
1625
|
* update recording value for the meeting
|
|
@@ -1519,7 +1638,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1519
1638
|
* @private
|
|
1520
1639
|
* @memberof Meeting
|
|
1521
1640
|
*/
|
|
1522
|
-
|
|
1641
|
+
private setupLocusControlsListener() {
|
|
1523
1642
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_RECORDING_UPDATED,
|
|
1524
1643
|
({state, modifiedBy, lastModified}) => {
|
|
1525
1644
|
let event;
|
|
@@ -1575,6 +1694,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1575
1694
|
|
|
1576
1695
|
this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIBE_UPDATED,
|
|
1577
1696
|
({caption, transcribing}) => {
|
|
1697
|
+
|
|
1698
|
+
// @ts-ignore - config coming from registerPlugin
|
|
1578
1699
|
if (transcribing && this.transcription && this.config.receiveTranscription) {
|
|
1579
1700
|
this.receiveTranscription();
|
|
1580
1701
|
}
|
|
@@ -1613,7 +1734,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1613
1734
|
* @private
|
|
1614
1735
|
* @memberof Meeting
|
|
1615
1736
|
*/
|
|
1616
|
-
|
|
1737
|
+
private setUpLocusMediaSharesListener() {
|
|
1617
1738
|
// Will get triggered on local and remote share
|
|
1618
1739
|
this.locusInfo.on(EVENTS.LOCUS_INFO_UPDATE_MEDIA_SHARES, (payload) => {
|
|
1619
1740
|
const {content: contentShare, whiteboard: whiteboardShare} = payload.current;
|
|
@@ -1701,7 +1822,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1701
1822
|
this,
|
|
1702
1823
|
{
|
|
1703
1824
|
file: 'meeting/index',
|
|
1704
|
-
function: '
|
|
1825
|
+
function: 'localShare'
|
|
1705
1826
|
},
|
|
1706
1827
|
EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
|
|
1707
1828
|
{
|
|
@@ -1844,7 +1965,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1844
1965
|
* @private
|
|
1845
1966
|
* @memberof Meeting
|
|
1846
1967
|
*/
|
|
1847
|
-
setUpLocusUrlListener() {
|
|
1968
|
+
private setUpLocusUrlListener() {
|
|
1848
1969
|
this.locusInfo.on(EVENTS.LOCUS_INFO_UPDATE_URL, (payload) => {
|
|
1849
1970
|
this.members.locusUrlUpdate(payload);
|
|
1850
1971
|
this.locusUrl = payload;
|
|
@@ -1858,7 +1979,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1858
1979
|
* @private
|
|
1859
1980
|
* @memberof meeting
|
|
1860
1981
|
*/
|
|
1861
|
-
setUpLocusInfoMeetingInfoListener() {
|
|
1982
|
+
private setUpLocusInfoMeetingInfoListener() {
|
|
1862
1983
|
this.locusInfo.on(LOCUSINFO.EVENTS.MEETING_LOCKED, (payload) => {
|
|
1863
1984
|
if (payload) {
|
|
1864
1985
|
Trigger.trigger(
|
|
@@ -1926,17 +2047,34 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1926
2047
|
this.inMeetingActions.get()
|
|
1927
2048
|
);
|
|
1928
2049
|
}
|
|
2050
|
+
|
|
2051
|
+
this.handleDataChannelUrlChange(payload.info.datachannelUrl);
|
|
1929
2052
|
}
|
|
1930
2053
|
});
|
|
1931
2054
|
}
|
|
1932
2055
|
|
|
2056
|
+
/**
|
|
2057
|
+
* Handles a data channel URL change
|
|
2058
|
+
* @param {String} datachannelUrl
|
|
2059
|
+
* @returns {void}
|
|
2060
|
+
*/
|
|
2061
|
+
handleDataChannelUrlChange(datachannelUrl) {
|
|
2062
|
+
if (datachannelUrl && this.config.enableAutomaticLLM) {
|
|
2063
|
+
// Defer this as updateLLMConnection relies upon this.locusInfo.url which is only set
|
|
2064
|
+
// after the MEETING_INFO_UPDATED callback finishes
|
|
2065
|
+
defer(() => {
|
|
2066
|
+
this.updateLLMConnection();
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
|
|
1933
2071
|
/**
|
|
1934
2072
|
* Set up the locus info embedded apps listener
|
|
1935
2073
|
* @returns {undefined}
|
|
1936
2074
|
* @private
|
|
1937
2075
|
* @memberof meeting
|
|
1938
2076
|
*/
|
|
1939
|
-
setUpLocusEmbeddedAppsListener() {
|
|
2077
|
+
private setUpLocusEmbeddedAppsListener() {
|
|
1940
2078
|
this.locusInfo.on(LOCUSINFO.EVENTS.EMBEDDED_APPS_UPDATED, (embeddedApps) => {
|
|
1941
2079
|
if (embeddedApps) {
|
|
1942
2080
|
Trigger.trigger(
|
|
@@ -1958,7 +2096,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1958
2096
|
* @private
|
|
1959
2097
|
* @memberof Meeting
|
|
1960
2098
|
*/
|
|
1961
|
-
setUpLocusInfoSelfListener() {
|
|
2099
|
+
private setUpLocusInfoSelfListener() {
|
|
1962
2100
|
this.locusInfo.on(LOCUSINFO.EVENTS.LOCAL_UNMUTE_REQUIRED, (payload) => {
|
|
1963
2101
|
if (this.audio) {
|
|
1964
2102
|
this.audio.handleServerLocalUnmuteRequired(this);
|
|
@@ -2056,6 +2194,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2056
2194
|
}
|
|
2057
2195
|
});
|
|
2058
2196
|
|
|
2197
|
+
// @ts-ignore - check if MEDIA_INACTIVITY exists
|
|
2059
2198
|
this.locusInfo.on(LOCUSINFO.EVENTS.MEDIA_INACTIVITY, () => {
|
|
2060
2199
|
Metrics.sendBehavioralMetric(
|
|
2061
2200
|
BEHAVIORAL_METRICS.MEETING_MEDIA_INACTIVE,
|
|
@@ -2122,7 +2261,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2122
2261
|
* @private
|
|
2123
2262
|
* @memberof Meeting
|
|
2124
2263
|
*/
|
|
2125
|
-
setUpLocusInfoMeetingListener() {
|
|
2264
|
+
private setUpLocusInfoMeetingListener() {
|
|
2126
2265
|
this.locusInfo.on(EVENTS.REMOTE_RESPONSE, (payload) => {
|
|
2127
2266
|
this.meetingFiniteStateMachine.remote(payload);
|
|
2128
2267
|
|
|
@@ -2130,6 +2269,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2130
2269
|
this.leave({reason: payload.reason}).then(() => {
|
|
2131
2270
|
LoggerProxy.logger.info('Meeting:index#setUpLocusInfoMeetingListener --> REMOTE_RESPONSE. Attempting to leave meeting.');
|
|
2132
2271
|
}).catch((error) => {
|
|
2272
|
+
// @ts-ignore
|
|
2133
2273
|
LoggerProxy.logger.error(`Meeting:index#setUpLocusInfoMeetingListener --> REMOTE_RESPONSE. Issue with leave for meeting, meeting still in collection: ${this.meeting}, error: ${error}`);
|
|
2134
2274
|
});
|
|
2135
2275
|
}
|
|
@@ -2158,6 +2298,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2158
2298
|
this.leave({reason: payload.reason}).then(() => {
|
|
2159
2299
|
LoggerProxy.logger.warn('Meeting:index#setUpLocusInfoMeetingListener --> DESTROY_MEETING. The meeting has been left, but has not been destroyed, you should see a later event for leave.');
|
|
2160
2300
|
}).catch((error) => {
|
|
2301
|
+
// @ts-ignore
|
|
2161
2302
|
LoggerProxy.logger.error(`Meeting:index#setUpLocusInfoMeetingListener --> DESTROY_MEETING. Issue with leave for meeting, meeting still in collection: ${this.meeting}, error: ${error}`);
|
|
2162
2303
|
});
|
|
2163
2304
|
}
|
|
@@ -2189,7 +2330,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2189
2330
|
* @memberof Meeting
|
|
2190
2331
|
* // TODO: is this function necessary?
|
|
2191
2332
|
*/
|
|
2192
|
-
updateMeetingObject(object) {
|
|
2333
|
+
private updateMeetingObject(object: object) {
|
|
2193
2334
|
// Validate if these are valid meeting object property
|
|
2194
2335
|
// TODO: add a check to make sure the value passed in the constructor
|
|
2195
2336
|
// is not changed by any delta event
|
|
@@ -2211,7 +2352,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2211
2352
|
* @public
|
|
2212
2353
|
* @memberof Meeting
|
|
2213
2354
|
*/
|
|
2214
|
-
invite(
|
|
2355
|
+
public invite(
|
|
2356
|
+
invitee: {
|
|
2357
|
+
emailAddress: string;
|
|
2358
|
+
email: string;
|
|
2359
|
+
phoneNumber: string;
|
|
2360
|
+
},
|
|
2361
|
+
alertIfActive: boolean = true
|
|
2362
|
+
) {
|
|
2215
2363
|
return this.members.addMember(invitee, alertIfActive);
|
|
2216
2364
|
}
|
|
2217
2365
|
|
|
@@ -2223,7 +2371,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2223
2371
|
* @public
|
|
2224
2372
|
* @memberof Meeting
|
|
2225
2373
|
*/
|
|
2226
|
-
cancelPhoneInvite(invitee) {
|
|
2374
|
+
public cancelPhoneInvite(invitee: { phoneNumber: string }) {
|
|
2227
2375
|
return this.members.cancelPhoneInvite(invitee);
|
|
2228
2376
|
}
|
|
2229
2377
|
|
|
@@ -2234,7 +2382,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2234
2382
|
* @public
|
|
2235
2383
|
* @memberof Meeting
|
|
2236
2384
|
*/
|
|
2237
|
-
admit(memberIds) {
|
|
2385
|
+
public admit(memberIds: Array<any>) {
|
|
2238
2386
|
return this.members.admitMembers(memberIds);
|
|
2239
2387
|
}
|
|
2240
2388
|
|
|
@@ -2245,7 +2393,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2245
2393
|
* @public
|
|
2246
2394
|
* @memberof Meeting
|
|
2247
2395
|
*/
|
|
2248
|
-
remove(memberId) {
|
|
2396
|
+
public remove(memberId: string) {
|
|
2249
2397
|
return this.members.removeMember(memberId);
|
|
2250
2398
|
}
|
|
2251
2399
|
|
|
@@ -2257,7 +2405,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2257
2405
|
* @public
|
|
2258
2406
|
* @memberof Meeting
|
|
2259
2407
|
*/
|
|
2260
|
-
mute(memberId, mute = true) {
|
|
2408
|
+
public mute(memberId: string, mute: boolean = true) {
|
|
2261
2409
|
return this.members.muteMember(memberId, mute);
|
|
2262
2410
|
}
|
|
2263
2411
|
|
|
@@ -2269,7 +2417,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2269
2417
|
* @public
|
|
2270
2418
|
* @memberof Meeting
|
|
2271
2419
|
*/
|
|
2272
|
-
transfer(memberId, moderator = true) {
|
|
2420
|
+
public transfer(memberId: string, moderator: boolean = true) {
|
|
2273
2421
|
return this.members.transferHostToMember(memberId, moderator);
|
|
2274
2422
|
}
|
|
2275
2423
|
|
|
@@ -2279,7 +2427,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2279
2427
|
* @public
|
|
2280
2428
|
* @memberof Meeting
|
|
2281
2429
|
*/
|
|
2282
|
-
getMembers() {
|
|
2430
|
+
public getMembers() {
|
|
2283
2431
|
return this.members;
|
|
2284
2432
|
}
|
|
2285
2433
|
|
|
@@ -2289,7 +2437,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2289
2437
|
* @public
|
|
2290
2438
|
* @memberof Meeting
|
|
2291
2439
|
*/
|
|
2292
|
-
isAudioConnected() {
|
|
2440
|
+
public isAudioConnected() {
|
|
2293
2441
|
return !!this.audio;
|
|
2294
2442
|
}
|
|
2295
2443
|
|
|
@@ -2299,7 +2447,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2299
2447
|
* @public
|
|
2300
2448
|
* @memberof Meeting
|
|
2301
2449
|
*/
|
|
2302
|
-
isAudioMuted() {
|
|
2450
|
+
public isAudioMuted() {
|
|
2303
2451
|
return this.audio && this.audio.isMuted();
|
|
2304
2452
|
}
|
|
2305
2453
|
|
|
@@ -2309,7 +2457,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2309
2457
|
* @public
|
|
2310
2458
|
* @memberof Meeting
|
|
2311
2459
|
*/
|
|
2312
|
-
isAudioSelf() {
|
|
2460
|
+
public isAudioSelf() {
|
|
2313
2461
|
return this.audio && this.audio.isSelf();
|
|
2314
2462
|
}
|
|
2315
2463
|
|
|
@@ -2319,7 +2467,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2319
2467
|
* @public
|
|
2320
2468
|
* @memberof Meeting
|
|
2321
2469
|
*/
|
|
2322
|
-
isVideoConnected() {
|
|
2470
|
+
public isVideoConnected() {
|
|
2323
2471
|
return !!this.video;
|
|
2324
2472
|
}
|
|
2325
2473
|
|
|
@@ -2329,7 +2477,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2329
2477
|
* @public
|
|
2330
2478
|
* @memberof Meeting
|
|
2331
2479
|
*/
|
|
2332
|
-
isVideoMuted() {
|
|
2480
|
+
public isVideoMuted() {
|
|
2333
2481
|
return this.video && this.video.isMuted();
|
|
2334
2482
|
}
|
|
2335
2483
|
|
|
@@ -2339,7 +2487,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2339
2487
|
* @public
|
|
2340
2488
|
* @memberof Meeting
|
|
2341
2489
|
*/
|
|
2342
|
-
isVideoSelf() {
|
|
2490
|
+
public isVideoSelf() {
|
|
2343
2491
|
return this.video && this.video.isSelf();
|
|
2344
2492
|
}
|
|
2345
2493
|
|
|
@@ -2356,7 +2504,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2356
2504
|
* @private
|
|
2357
2505
|
* @memberof Meeting
|
|
2358
2506
|
*/
|
|
2359
|
-
parseMeetingInfo(
|
|
2507
|
+
parseMeetingInfo(
|
|
2508
|
+
meetingInfo: {
|
|
2509
|
+
body: {
|
|
2510
|
+
conversationUrl: string;
|
|
2511
|
+
locusUrl: string;
|
|
2512
|
+
sipUri: string;
|
|
2513
|
+
owner: object;
|
|
2514
|
+
};
|
|
2515
|
+
} | any,
|
|
2516
|
+
destination: object | string | null = null
|
|
2517
|
+
) {
|
|
2360
2518
|
const webexMeetingInfo = meetingInfo?.body;
|
|
2361
2519
|
// We try to use as much info from Locus meeting object, stored in destination
|
|
2362
2520
|
|
|
@@ -2370,7 +2528,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2370
2528
|
if (locusMeetingObject || (webexMeetingInfo && !(meetingInfo?.errors && meetingInfo?.errors.length > 0))) {
|
|
2371
2529
|
this.conversationUrl = locusMeetingObject?.conversationUrl || webexMeetingInfo?.conversationUrl || this.conversationUrl;
|
|
2372
2530
|
this.locusUrl = locusMeetingObject?.url || webexMeetingInfo?.locusUrl || this.locusUrl;
|
|
2531
|
+
// @ts-ignore - config coming from registerPlugin
|
|
2373
2532
|
this.setSipUri(this.config.experimental.enableUnifiedMeetings ? locusMeetingObject?.info.sipUri || webexMeetingInfo?.sipUrl : locusMeetingObject?.info.sipUri || webexMeetingInfo?.sipMeetingUri || this.sipUri);
|
|
2533
|
+
// @ts-ignore - config coming from registerPlugin
|
|
2374
2534
|
if (this.config.experimental.enableUnifiedMeetings) {
|
|
2375
2535
|
this.meetingNumber = locusMeetingObject?.info.webExMeetingId || webexMeetingInfo?.meetingNumber;
|
|
2376
2536
|
this.meetingJoinUrl = webexMeetingInfo?.meetingJoinUrl;
|
|
@@ -2390,7 +2550,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2390
2550
|
* @private
|
|
2391
2551
|
* @memberof Meeting
|
|
2392
2552
|
*/
|
|
2393
|
-
parseLocus(locus) {
|
|
2553
|
+
private parseLocus(locus: { url: string; participants: Array<any>; self: object }) {
|
|
2394
2554
|
if (locus) {
|
|
2395
2555
|
this.locusUrl = locus.url;
|
|
2396
2556
|
// TODO: move this to parse participants module
|
|
@@ -2417,24 +2577,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2417
2577
|
* @private
|
|
2418
2578
|
* @memberof Meeting
|
|
2419
2579
|
*/
|
|
2420
|
-
setSipUri(sipUri) {
|
|
2580
|
+
setSipUri(sipUri: string) {
|
|
2421
2581
|
// This can be tel no, device id or a sip uri, user Id
|
|
2422
2582
|
this.sipUri = sipUri;
|
|
2423
2583
|
}
|
|
2424
2584
|
|
|
2425
|
-
/**
|
|
2426
|
-
* Set the roap seq on the class instance
|
|
2427
|
-
* @param {Number} seq
|
|
2428
|
-
* @returns {undefined}
|
|
2429
|
-
* @private
|
|
2430
|
-
* @memberof Meeting
|
|
2431
|
-
*/
|
|
2432
|
-
setRoapSeq(seq) {
|
|
2433
|
-
if (seq >= 0) {
|
|
2434
|
-
this.roapSeq = seq;
|
|
2435
|
-
}
|
|
2436
|
-
}
|
|
2437
|
-
|
|
2438
2585
|
/**
|
|
2439
2586
|
* Set the locus info the class instance
|
|
2440
2587
|
* @param {Object} locus
|
|
@@ -2448,8 +2595,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2448
2595
|
* @private
|
|
2449
2596
|
* @memberof Meeting
|
|
2450
2597
|
*/
|
|
2451
|
-
setLocus(locus
|
|
2452
|
-
|
|
2598
|
+
private setLocus(locus: {
|
|
2599
|
+
mediaConnections: Array<any>;
|
|
2600
|
+
locusUrl: string;
|
|
2601
|
+
locusId: string;
|
|
2602
|
+
mediaId: string;
|
|
2603
|
+
host: object;
|
|
2604
|
+
} | any) {
|
|
2605
|
+
const mtgLocus: any = locus.locus || locus;
|
|
2453
2606
|
|
|
2454
2607
|
// LocusInfo object saves the locus object
|
|
2455
2608
|
// this.locus = mtgLocus;
|
|
@@ -2462,111 +2615,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2462
2615
|
this.locusInfo.initialSetup(mtgLocus);
|
|
2463
2616
|
}
|
|
2464
2617
|
|
|
2465
|
-
/**
|
|
2466
|
-
* Sets the remote stream on the class instance and emits and
|
|
2467
|
-
* event to developers
|
|
2468
|
-
* @param {Object} pc The remote stream peer connection
|
|
2469
|
-
* @returns {undefined}
|
|
2470
|
-
* @public
|
|
2471
|
-
* @memberof Meeting
|
|
2472
|
-
*/
|
|
2473
|
-
setRemoteStream(pc) {
|
|
2474
|
-
if (!pc) {
|
|
2475
|
-
return;
|
|
2476
|
-
}
|
|
2477
|
-
// eslint-disable-next-line no-param-reassign
|
|
2478
|
-
pc.ontrack = (event) => {
|
|
2479
|
-
// eslint-disable-next-line no-warning-comments
|
|
2480
|
-
// TODO: It's possible for media to not be present
|
|
2481
|
-
// so we might need to either
|
|
2482
|
-
// A) wait until we have media flowing
|
|
2483
|
-
// B) trigger a second event when video is flowing
|
|
2484
|
-
LoggerProxy.logger.log(`Meeting:index#setRemoteStream --> ontrack event received for peerConnection: ${event}`);
|
|
2485
|
-
|
|
2486
|
-
const MEDIA_ID = {
|
|
2487
|
-
AUDIO_TRACK: '0',
|
|
2488
|
-
VIDEO_TRACK: '1',
|
|
2489
|
-
SHARE_TRACK: '2'
|
|
2490
|
-
};
|
|
2491
|
-
let eventType = null;
|
|
2492
|
-
const mediaTrack = event.track;
|
|
2493
|
-
let trackMediaID = null;
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
// In case of safari some time the transceiver is not present for specific os version
|
|
2497
|
-
// sdk tries to determine the transceive using the track id present
|
|
2498
|
-
if (event.transceiver && event.transceiver.mid) {
|
|
2499
|
-
trackMediaID = event.transceiver.mid;
|
|
2500
|
-
}
|
|
2501
|
-
else {
|
|
2502
|
-
const {audioTransceiver, videoTransceiver, shareTransceiver} = event.target;
|
|
2503
|
-
|
|
2504
|
-
// audio kind indicates its a audio stream
|
|
2505
|
-
if (mediaTrack.id === audioTransceiver.receiver.track.id) {
|
|
2506
|
-
trackMediaID = '0';
|
|
2507
|
-
}
|
|
2508
|
-
else
|
|
2509
|
-
if (mediaTrack.id === videoTransceiver.receiver.track.id) {
|
|
2510
|
-
trackMediaID = '1';
|
|
2511
|
-
}
|
|
2512
|
-
else
|
|
2513
|
-
if (mediaTrack.id === shareTransceiver.receiver.track.id) {
|
|
2514
|
-
trackMediaID = '2';
|
|
2515
|
-
}
|
|
2516
|
-
else {
|
|
2517
|
-
trackMediaID = null;
|
|
2518
|
-
Metrics.sendBehavioralMetric(
|
|
2519
|
-
BEHAVIORAL_METRICS.MUTE_AUDIO_FAILURE,
|
|
2520
|
-
{
|
|
2521
|
-
correlation_id: this.correlationId,
|
|
2522
|
-
locus_id: this.locusUrl.split('/').pop()
|
|
2523
|
-
}
|
|
2524
|
-
);
|
|
2525
|
-
}
|
|
2526
|
-
}
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
switch (trackMediaID) {
|
|
2530
|
-
case MEDIA_ID.AUDIO_TRACK:
|
|
2531
|
-
eventType = EVENT_TYPES.REMOTE_AUDIO;
|
|
2532
|
-
this.mediaProperties.setRemoteAudioTrack(mediaTrack);
|
|
2533
|
-
break;
|
|
2534
|
-
case MEDIA_ID.VIDEO_TRACK:
|
|
2535
|
-
eventType = EVENT_TYPES.REMOTE_VIDEO;
|
|
2536
|
-
this.mediaProperties.setRemoteVideoTrack(mediaTrack);
|
|
2537
|
-
break;
|
|
2538
|
-
case MEDIA_ID.SHARE_TRACK:
|
|
2539
|
-
if (event.track) {
|
|
2540
|
-
eventType = EVENT_TYPES.REMOTE_SHARE;
|
|
2541
|
-
this.mediaProperties.setRemoteShare(mediaTrack);
|
|
2542
|
-
}
|
|
2543
|
-
break;
|
|
2544
|
-
default: {
|
|
2545
|
-
LoggerProxy.logger.log('Meeting:index#setRemoteStream --> no matching media track id');
|
|
2546
|
-
}
|
|
2547
|
-
}
|
|
2548
|
-
|
|
2549
|
-
// start stats here the stats are coming null if you dont receive streams
|
|
2550
|
-
|
|
2551
|
-
this.statsAnalyzer.startAnalyzer(this.mediaProperties.peerConnection);
|
|
2552
|
-
|
|
2553
|
-
if (eventType && mediaTrack) {
|
|
2554
|
-
Trigger.trigger(
|
|
2555
|
-
this,
|
|
2556
|
-
{
|
|
2557
|
-
file: 'meeting/index',
|
|
2558
|
-
function: 'setRemoteStream:pc.ontrack'
|
|
2559
|
-
},
|
|
2560
|
-
EVENT_TRIGGERS.MEDIA_READY,
|
|
2561
|
-
{
|
|
2562
|
-
type: eventType,
|
|
2563
|
-
stream: MediaUtil.createMediaStream([mediaTrack])
|
|
2564
|
-
}
|
|
2565
|
-
);
|
|
2566
|
-
}
|
|
2567
|
-
};
|
|
2568
|
-
}
|
|
2569
|
-
|
|
2570
2618
|
/**
|
|
2571
2619
|
* Upload logs for the current meeting
|
|
2572
2620
|
* @param {object} options file name and function name
|
|
@@ -2574,7 +2622,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2574
2622
|
* @public
|
|
2575
2623
|
* @memberof Meeting
|
|
2576
2624
|
*/
|
|
2577
|
-
uploadLogs(options = {file: 'meeting/index', function: 'uploadLogs'}) {
|
|
2625
|
+
public uploadLogs(options: object = { file: 'meeting/index', function: 'uploadLogs' }) {
|
|
2578
2626
|
Trigger.trigger(
|
|
2579
2627
|
this,
|
|
2580
2628
|
options,
|
|
@@ -2583,7 +2631,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2583
2631
|
);
|
|
2584
2632
|
}
|
|
2585
2633
|
|
|
2586
|
-
|
|
2587
2634
|
/**
|
|
2588
2635
|
* Removes remote audio and video stream on the class instance and triggers an event
|
|
2589
2636
|
* to developers
|
|
@@ -2592,7 +2639,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2592
2639
|
* @memberof Meeting
|
|
2593
2640
|
* @deprecated after v1.89.3
|
|
2594
2641
|
*/
|
|
2595
|
-
unsetRemoteStream() {
|
|
2642
|
+
public unsetRemoteStream() {
|
|
2596
2643
|
LoggerProxy.logger.warn('Meeting:index#unsetRemoteStream --> [DEPRECATION WARNING]: unsetRemoteStream has been deprecated after v1.89.3');
|
|
2597
2644
|
this.mediaProperties.unsetRemoteMedia();
|
|
2598
2645
|
}
|
|
@@ -2613,7 +2660,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2613
2660
|
* @memberof Meeting
|
|
2614
2661
|
* @deprecated after v1.89.3
|
|
2615
2662
|
*/
|
|
2616
|
-
closeRemoteStream() {
|
|
2663
|
+
public closeRemoteStream() {
|
|
2617
2664
|
LoggerProxy.logger.warn('Meeting:index#closeRemoteStream --> [DEPRECATION WARNING]: closeRemoteStream has been deprecated after v1.89.3');
|
|
2618
2665
|
this.closeRemoteTracks();
|
|
2619
2666
|
}
|
|
@@ -2637,7 +2684,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2637
2684
|
* @returns {void}
|
|
2638
2685
|
* @inner
|
|
2639
2686
|
*/
|
|
2640
|
-
const triggerMediaStoppedEvent = (mediaType) => {
|
|
2687
|
+
const triggerMediaStoppedEvent = (mediaType: string) => {
|
|
2641
2688
|
Trigger.trigger(
|
|
2642
2689
|
this,
|
|
2643
2690
|
{
|
|
@@ -2659,7 +2706,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2659
2706
|
* @inner
|
|
2660
2707
|
*/
|
|
2661
2708
|
// eslint-disable-next-line arrow-body-style
|
|
2662
|
-
const stopTrack = (track, type) => {
|
|
2709
|
+
const stopTrack = (track: MediaStreamTrack, type: string) => {
|
|
2663
2710
|
return Media.stopTracks(track)
|
|
2664
2711
|
.then(() => {
|
|
2665
2712
|
const isTrackStopped = track && track.readyState === ENDED;
|
|
@@ -2687,7 +2734,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2687
2734
|
* @private
|
|
2688
2735
|
* @memberof Meeting
|
|
2689
2736
|
*/
|
|
2690
|
-
sendLocalMediaReadyEvent() {
|
|
2737
|
+
private sendLocalMediaReadyEvent() {
|
|
2691
2738
|
Trigger.trigger(
|
|
2692
2739
|
this,
|
|
2693
2740
|
{
|
|
@@ -2710,7 +2757,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2710
2757
|
* @private
|
|
2711
2758
|
* @memberof Meeting
|
|
2712
2759
|
*/
|
|
2713
|
-
setLocalAudioTrack(audioTrack, emitEvent = true) {
|
|
2760
|
+
private setLocalAudioTrack(audioTrack: MediaStreamTrack, emitEvent: boolean = true) {
|
|
2714
2761
|
if (audioTrack) {
|
|
2715
2762
|
const settings = audioTrack.getSettings();
|
|
2716
2763
|
|
|
@@ -2737,7 +2784,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2737
2784
|
* @private
|
|
2738
2785
|
* @memberof Meeting
|
|
2739
2786
|
*/
|
|
2740
|
-
setLocalVideoTrack(videoTrack, emitEvent = true) {
|
|
2787
|
+
private setLocalVideoTrack(videoTrack: MediaStreamTrack, emitEvent: boolean = true) {
|
|
2741
2788
|
if (videoTrack) {
|
|
2742
2789
|
const {
|
|
2743
2790
|
aspectRatio, frameRate, height, width, deviceId
|
|
@@ -2777,7 +2824,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2777
2824
|
* @public
|
|
2778
2825
|
* @memberof Meeting
|
|
2779
2826
|
*/
|
|
2780
|
-
setLocalTracks(localStream) {
|
|
2827
|
+
public setLocalTracks(localStream: any) {
|
|
2781
2828
|
if (localStream) {
|
|
2782
2829
|
const {audioTrack, videoTrack} = MeetingUtil.getTrack(localStream);
|
|
2783
2830
|
|
|
@@ -2790,12 +2837,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2790
2837
|
|
|
2791
2838
|
/**
|
|
2792
2839
|
* Sets the local media stream on the class and emits an event to the developer
|
|
2793
|
-
* @param {
|
|
2840
|
+
* @param {MediaStream} localShare the local media stream
|
|
2794
2841
|
* @returns {undefined}
|
|
2795
2842
|
* @public
|
|
2796
2843
|
* @memberof Meeting
|
|
2797
2844
|
*/
|
|
2798
|
-
setLocalShareTrack(localShare) {
|
|
2845
|
+
public setLocalShareTrack(localShare: MediaStream) {
|
|
2799
2846
|
let settings = null;
|
|
2800
2847
|
|
|
2801
2848
|
if (localShare) {
|
|
@@ -2839,7 +2886,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2839
2886
|
* @public
|
|
2840
2887
|
* @memberof Meeting
|
|
2841
2888
|
*/
|
|
2842
|
-
closeLocalStream() {
|
|
2889
|
+
public closeLocalStream() {
|
|
2843
2890
|
const {audioTrack, videoTrack} = this.mediaProperties;
|
|
2844
2891
|
|
|
2845
2892
|
return Media.stopTracks(audioTrack)
|
|
@@ -2874,7 +2921,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2874
2921
|
* @public
|
|
2875
2922
|
* @memberof Meeting
|
|
2876
2923
|
*/
|
|
2877
|
-
closeLocalShare() {
|
|
2924
|
+
public closeLocalShare() {
|
|
2878
2925
|
const track = this.mediaProperties.shareTrack;
|
|
2879
2926
|
|
|
2880
2927
|
return Media.stopTracks(track).then(() => {
|
|
@@ -2903,7 +2950,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2903
2950
|
* @public
|
|
2904
2951
|
* @memberof Meeting
|
|
2905
2952
|
*/
|
|
2906
|
-
unsetLocalVideoTrack() {
|
|
2953
|
+
public unsetLocalVideoTrack() {
|
|
2907
2954
|
this.mediaProperties.unsetLocalVideoTrack();
|
|
2908
2955
|
}
|
|
2909
2956
|
|
|
@@ -2913,7 +2960,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2913
2960
|
* @public
|
|
2914
2961
|
* @memberof Meeting
|
|
2915
2962
|
*/
|
|
2916
|
-
unsetLocalShareTrack() {
|
|
2963
|
+
public unsetLocalShareTrack() {
|
|
2917
2964
|
this.mediaProperties.unsetLocalShareTrack();
|
|
2918
2965
|
}
|
|
2919
2966
|
|
|
@@ -2923,9 +2970,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2923
2970
|
* @public
|
|
2924
2971
|
* @memberof Meeting
|
|
2925
2972
|
*/
|
|
2926
|
-
setMercuryListener() {
|
|
2973
|
+
public setMercuryListener() {
|
|
2927
2974
|
// Client will have a socket manager and handle reconnecting to mercury, when we reconnect to mercury
|
|
2928
2975
|
// if the meeting has active peer connections, it should try to reconnect.
|
|
2976
|
+
// @ts-ignore
|
|
2929
2977
|
this.webex.internal.mercury.on(ONLINE, () => {
|
|
2930
2978
|
LoggerProxy.logger.info('Meeting:index#setMercuryListener --> Web socket online');
|
|
2931
2979
|
|
|
@@ -2945,6 +2993,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2945
2993
|
this.hasWebsocketConnected = true;
|
|
2946
2994
|
});
|
|
2947
2995
|
|
|
2996
|
+
// @ts-ignore
|
|
2948
2997
|
this.webex.internal.mercury.on(OFFLINE, () => {
|
|
2949
2998
|
LoggerProxy.logger.error('Meeting:index#setMercuryListener --> Web socket offline');
|
|
2950
2999
|
Metrics.postEvent({
|
|
@@ -2961,27 +3010,41 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2961
3010
|
}
|
|
2962
3011
|
|
|
2963
3012
|
/**
|
|
2964
|
-
* Close the peer connections and remove them from the class.
|
|
2965
|
-
*
|
|
2966
|
-
*
|
|
3013
|
+
* Close the peer connections and remove them from the class.
|
|
3014
|
+
* Cleanup any media connection related things.
|
|
3015
|
+
*
|
|
3016
|
+
* @returns {Promise}
|
|
2967
3017
|
* @public
|
|
2968
3018
|
* @memberof Meeting
|
|
2969
3019
|
*/
|
|
2970
|
-
closePeerConnections() {
|
|
2971
|
-
|
|
3020
|
+
public closePeerConnections() {
|
|
3021
|
+
if (this.mediaProperties.webrtcMediaConnection) {
|
|
3022
|
+
if (this.remoteMediaManager) {
|
|
3023
|
+
this.remoteMediaManager.stop();
|
|
3024
|
+
this.remoteMediaManager = null;
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3027
|
+
Object.values(this.mediaRequestManagers).forEach((mediaRequestManager) => mediaRequestManager.reset());
|
|
3028
|
+
|
|
3029
|
+
this.receiveSlotManager.reset();
|
|
3030
|
+
this.mediaProperties.webrtcMediaConnection.close();
|
|
3031
|
+
}
|
|
3032
|
+
|
|
3033
|
+
return Promise.resolve();
|
|
2972
3034
|
}
|
|
2973
3035
|
|
|
2974
3036
|
/**
|
|
2975
3037
|
* Unsets the peer connections on the class
|
|
2976
3038
|
* warning DO NOT CALL WITHOUT CLOSING PEER CONNECTIONS FIRST
|
|
2977
|
-
* @param {PeerConnection} peerConnection
|
|
2978
3039
|
* @returns {undefined}
|
|
2979
3040
|
* @public
|
|
2980
3041
|
* @memberof Meeting
|
|
2981
3042
|
*/
|
|
2982
|
-
unsetPeerConnections() {
|
|
3043
|
+
public unsetPeerConnections() {
|
|
2983
3044
|
this.mediaProperties.unsetPeerConnection();
|
|
3045
|
+
// @ts-ignore - config coming from registerPlugin
|
|
2984
3046
|
if (this.config.reconnection.detection) {
|
|
3047
|
+
// @ts-ignore
|
|
2985
3048
|
this.webex.internal.mercury.off(ONLINE);
|
|
2986
3049
|
}
|
|
2987
3050
|
}
|
|
@@ -2993,7 +3056,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2993
3056
|
* @private
|
|
2994
3057
|
* @memberof Meeting
|
|
2995
3058
|
*/
|
|
2996
|
-
setCorrelationId(id) {
|
|
3059
|
+
private setCorrelationId(id: string) {
|
|
2997
3060
|
this.correlationId = id;
|
|
2998
3061
|
}
|
|
2999
3062
|
|
|
@@ -3003,11 +3066,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3003
3066
|
* @public
|
|
3004
3067
|
* @memberof Meeting
|
|
3005
3068
|
*/
|
|
3006
|
-
muteAudio() {
|
|
3069
|
+
public muteAudio() {
|
|
3007
3070
|
if (!MeetingUtil.isUserInJoinedState(this.locusInfo)) {
|
|
3008
3071
|
return Promise.reject(new UserNotJoinedError());
|
|
3009
3072
|
}
|
|
3010
3073
|
|
|
3074
|
+
// @ts-ignore
|
|
3011
3075
|
if (!this.mediaId) {
|
|
3012
3076
|
// Happens when addMedia and mute are triggered in succession
|
|
3013
3077
|
return Promise.reject(new NoMediaEstablishedYetError());
|
|
@@ -3054,11 +3118,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3054
3118
|
* @public
|
|
3055
3119
|
* @memberof Meeting
|
|
3056
3120
|
*/
|
|
3057
|
-
unmuteAudio() {
|
|
3121
|
+
public unmuteAudio() {
|
|
3058
3122
|
if (!MeetingUtil.isUserInJoinedState(this.locusInfo)) {
|
|
3059
3123
|
return Promise.reject(new UserNotJoinedError());
|
|
3060
3124
|
}
|
|
3061
3125
|
|
|
3126
|
+
// @ts-ignore
|
|
3062
3127
|
if (!this.mediaId) {
|
|
3063
3128
|
// Happens when addMedia and mute are triggered in succession
|
|
3064
3129
|
return Promise.reject(new NoMediaEstablishedYetError());
|
|
@@ -3105,11 +3170,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3105
3170
|
* @public
|
|
3106
3171
|
* @memberof Meeting
|
|
3107
3172
|
*/
|
|
3108
|
-
muteVideo() {
|
|
3173
|
+
public muteVideo() {
|
|
3109
3174
|
if (!MeetingUtil.isUserInJoinedState(this.locusInfo)) {
|
|
3110
3175
|
return Promise.reject(new UserNotJoinedError());
|
|
3111
3176
|
}
|
|
3112
3177
|
|
|
3178
|
+
// @ts-ignore
|
|
3113
3179
|
if (!this.mediaId) {
|
|
3114
3180
|
// Happens when addMedia and mute are triggered in succession
|
|
3115
3181
|
return Promise.reject(new NoMediaEstablishedYetError());
|
|
@@ -3155,11 +3221,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3155
3221
|
* @public
|
|
3156
3222
|
* @memberof Meeting
|
|
3157
3223
|
*/
|
|
3158
|
-
unmuteVideo() {
|
|
3224
|
+
public unmuteVideo() {
|
|
3159
3225
|
if (!MeetingUtil.isUserInJoinedState(this.locusInfo)) {
|
|
3160
3226
|
return Promise.reject(new UserNotJoinedError());
|
|
3161
3227
|
}
|
|
3162
3228
|
|
|
3229
|
+
// @ts-ignore
|
|
3163
3230
|
if (!this.mediaId) {
|
|
3164
3231
|
// Happens when addMedia and mute are triggered in succession
|
|
3165
3232
|
return Promise.reject(new NoMediaEstablishedYetError());
|
|
@@ -3224,7 +3291,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3224
3291
|
* video: 'videoDeviceId'
|
|
3225
3292
|
* }})
|
|
3226
3293
|
*/
|
|
3227
|
-
joinWithMedia(
|
|
3294
|
+
public joinWithMedia(
|
|
3295
|
+
options: {
|
|
3296
|
+
joinOptions?: any;
|
|
3297
|
+
mediaSettings: any;
|
|
3298
|
+
audioVideoOptions?: any;
|
|
3299
|
+
} = {} as any
|
|
3300
|
+
) {
|
|
3228
3301
|
// TODO: add validations for parameters
|
|
3229
3302
|
const {mediaSettings, joinOptions, audioVideoOptions} = options;
|
|
3230
3303
|
|
|
@@ -3268,19 +3341,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3268
3341
|
* @public
|
|
3269
3342
|
* @memberof Meeting
|
|
3270
3343
|
*/
|
|
3271
|
-
reconnect(options) {
|
|
3344
|
+
public reconnect(options?: object) {
|
|
3272
3345
|
LoggerProxy.logger.log(`Meeting:index#reconnect --> attempting to reconnect meeting ${this.id}`);
|
|
3273
3346
|
|
|
3274
3347
|
if (!this.reconnectionManager || !this.reconnectionManager.reconnect) {
|
|
3275
3348
|
return Promise.reject(new ParameterError('Cannot reconnect, ReconnectionManager must first be defined.'));
|
|
3276
3349
|
}
|
|
3277
3350
|
|
|
3351
|
+
// @ts-ignore - currentMediaStatus coming from SelfUtil
|
|
3278
3352
|
if (!MeetingUtil.isMediaEstablished(this.currentMediaStatus)) {
|
|
3279
3353
|
return Promise.reject(new ParameterError('Cannot reconnect, Media has not established to reconnect'));
|
|
3280
3354
|
}
|
|
3281
3355
|
|
|
3282
3356
|
try {
|
|
3283
3357
|
LoggerProxy.logger.info('Meeting:index#reconnect --> Validating reconnect ability.');
|
|
3358
|
+
// @ts-ignore
|
|
3284
3359
|
this.reconnectionManager.validate();
|
|
3285
3360
|
}
|
|
3286
3361
|
catch (error) {
|
|
@@ -3304,7 +3379,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3304
3379
|
EVENT_TRIGGERS.MEETING_RECONNECTION_STARTING
|
|
3305
3380
|
);
|
|
3306
3381
|
|
|
3307
|
-
|
|
3308
3382
|
return this.reconnectionManager
|
|
3309
3383
|
.reconnect(options)
|
|
3310
3384
|
.then(() => {
|
|
@@ -3377,7 +3451,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3377
3451
|
* @private
|
|
3378
3452
|
* @returns {void}
|
|
3379
3453
|
*/
|
|
3380
|
-
monitorTranscriptionSocketConnection() {
|
|
3454
|
+
private monitorTranscriptionSocketConnection() {
|
|
3381
3455
|
this.transcription.onCloseSocket((event) => {
|
|
3382
3456
|
LoggerProxy.logger.info(
|
|
3383
3457
|
`Meeting:index#onCloseSocket -->
|
|
@@ -3415,7 +3489,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3415
3489
|
* @private
|
|
3416
3490
|
* @returns {Promise<void>} a promise to open the WebSocket connection
|
|
3417
3491
|
*/
|
|
3418
|
-
async receiveTranscription() {
|
|
3492
|
+
private async receiveTranscription() {
|
|
3419
3493
|
LoggerProxy.logger.info(
|
|
3420
3494
|
`Meeting:index#receiveTranscription -->
|
|
3421
3495
|
Attempting to generate a web socket url.`
|
|
@@ -3423,6 +3497,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3423
3497
|
|
|
3424
3498
|
try {
|
|
3425
3499
|
const {datachannelUrl} = this.locusInfo.info;
|
|
3500
|
+
// @ts-ignore - fix type
|
|
3426
3501
|
const {body: {webSocketUrl}} = await this.request({
|
|
3427
3502
|
method: HTTP_VERBS.POST,
|
|
3428
3503
|
uri: datachannelUrl,
|
|
@@ -3436,6 +3511,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3436
3511
|
|
|
3437
3512
|
this.transcription = new Transcription(
|
|
3438
3513
|
webSocketUrl,
|
|
3514
|
+
// @ts-ignore - fix type
|
|
3439
3515
|
this.webex.sessionId,
|
|
3440
3516
|
this.members,
|
|
3441
3517
|
);
|
|
@@ -3459,6 +3535,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3459
3535
|
});
|
|
3460
3536
|
|
|
3461
3537
|
this.monitorTranscriptionSocketConnection();
|
|
3538
|
+
// @ts-ignore - fix type
|
|
3462
3539
|
this.transcription.connect(this.webex.credentials.supertoken.access_token);
|
|
3463
3540
|
}
|
|
3464
3541
|
catch (error) {
|
|
@@ -3491,12 +3568,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3491
3568
|
* @private
|
|
3492
3569
|
* @returns{void}
|
|
3493
3570
|
*/
|
|
3494
|
-
triggerStopReceivingTranscriptionEvent() {
|
|
3571
|
+
private triggerStopReceivingTranscriptionEvent() {
|
|
3495
3572
|
LoggerProxy.logger.info(`
|
|
3496
3573
|
Meeting:index#stopReceivingTranscription -->
|
|
3497
3574
|
closed transcription LLM web socket connection successfully.`);
|
|
3498
3575
|
|
|
3499
|
-
|
|
3500
3576
|
Trigger.trigger(
|
|
3501
3577
|
this,
|
|
3502
3578
|
{
|
|
@@ -3519,7 +3595,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3519
3595
|
* if joining as host on second loop, pass pin and pass moderator if joining as guest on second loop
|
|
3520
3596
|
* Scenario D: Joining any other way (sip, pstn, conversationUrl, link just need to specify resourceId)
|
|
3521
3597
|
*/
|
|
3522
|
-
join(options = {}) {
|
|
3598
|
+
public join(options: any = {}) {
|
|
3599
|
+
// @ts-ignore - fix type
|
|
3523
3600
|
if (!this.webex.meetings.registered) {
|
|
3524
3601
|
const errorMessage = 'Meeting:index#join --> Device not registered';
|
|
3525
3602
|
const error = new Error(errorMessage);
|
|
@@ -3625,6 +3702,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3625
3702
|
}
|
|
3626
3703
|
}
|
|
3627
3704
|
|
|
3705
|
+
this.isMultistream = !!options.enableMultistream;
|
|
3706
|
+
|
|
3628
3707
|
return MeetingUtil.joinMeetingOptions(this, options)
|
|
3629
3708
|
.then((join) => {
|
|
3630
3709
|
this.meetingFiniteStateMachine.join();
|
|
@@ -3643,8 +3722,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3643
3722
|
);
|
|
3644
3723
|
|
|
3645
3724
|
return join;
|
|
3646
|
-
})
|
|
3725
|
+
})
|
|
3726
|
+
.then(async (join) => {
|
|
3727
|
+
if (this.config.enableAutomaticLLM) {
|
|
3728
|
+
await this.updateLLMConnection();
|
|
3729
|
+
}
|
|
3730
|
+
|
|
3731
|
+
return join;
|
|
3732
|
+
})
|
|
3733
|
+
.then(async (join) => {
|
|
3647
3734
|
if (isBrowser) {
|
|
3735
|
+
// @ts-ignore - config coming from registerPlugin
|
|
3648
3736
|
if (this.config.receiveTranscription || options.receiveTranscription) {
|
|
3649
3737
|
if (this.isTranscriptionSupported()) {
|
|
3650
3738
|
await this.receiveTranscription();
|
|
@@ -3656,7 +3744,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3656
3744
|
LoggerProxy.logger.error('Meeting:index#join --> Receving transcription is not supported on this platform');
|
|
3657
3745
|
}
|
|
3658
3746
|
|
|
3659
|
-
|
|
3660
3747
|
return join;
|
|
3661
3748
|
})
|
|
3662
3749
|
.catch((error) => {
|
|
@@ -3702,6 +3789,31 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3702
3789
|
});
|
|
3703
3790
|
}
|
|
3704
3791
|
|
|
3792
|
+
/**
|
|
3793
|
+
* Connects to low latency mercury and reconnects if the address has changed
|
|
3794
|
+
* It will also disconnect if called when the meeting has ended
|
|
3795
|
+
* @param {String} datachannelUrl
|
|
3796
|
+
* @returns {Promise}
|
|
3797
|
+
*/
|
|
3798
|
+
async updateLLMConnection() {
|
|
3799
|
+
const {url, info: {datachannelUrl} = {}} = this.locusInfo;
|
|
3800
|
+
|
|
3801
|
+
const isJoined = this.joinedWith && this.joinedWith.state === 'JOINED';
|
|
3802
|
+
|
|
3803
|
+
if (this.webex.internal.llm.isConnected()) {
|
|
3804
|
+
if (url === this.webex.internal.llm.getLocusUrl() && isJoined) {
|
|
3805
|
+
return undefined;
|
|
3806
|
+
}
|
|
3807
|
+
await this.webex.internal.llm.disconnectLLM();
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
if (!isJoined) {
|
|
3811
|
+
return undefined;
|
|
3812
|
+
}
|
|
3813
|
+
|
|
3814
|
+
return this.webex.internal.llm.registerAndConnect(url, datachannelUrl);
|
|
3815
|
+
}
|
|
3816
|
+
|
|
3705
3817
|
/**
|
|
3706
3818
|
* Use phone for meeting audio
|
|
3707
3819
|
* @param {String} phoneNumber If provided, it will dial-out using this number. If not provided, dial-in will be used
|
|
@@ -3709,7 +3821,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3709
3821
|
* @public
|
|
3710
3822
|
* @memberof Meeting
|
|
3711
3823
|
*/
|
|
3712
|
-
usePhoneAudio(phoneNumber) {
|
|
3824
|
+
public usePhoneAudio(phoneNumber: string) {
|
|
3713
3825
|
if (!phoneNumber) {
|
|
3714
3826
|
return this.dialInPstn();
|
|
3715
3827
|
}
|
|
@@ -3724,7 +3836,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3724
3836
|
* @private
|
|
3725
3837
|
* @memberof Meeting
|
|
3726
3838
|
*/
|
|
3727
|
-
isPhoneProvisioned(pstnStatus) {
|
|
3839
|
+
private isPhoneProvisioned(pstnStatus: string) {
|
|
3728
3840
|
return [PSTN_STATUS.JOINED, PSTN_STATUS.CONNECTED, PSTN_STATUS.SUCCESS].includes(pstnStatus);
|
|
3729
3841
|
}
|
|
3730
3842
|
|
|
@@ -3734,7 +3846,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3734
3846
|
* @private
|
|
3735
3847
|
* @memberof Meeting
|
|
3736
3848
|
*/
|
|
3737
|
-
dialInPstn() {
|
|
3849
|
+
private dialInPstn() {
|
|
3738
3850
|
if (this.isPhoneProvisioned(this.dialInDeviceStatus)) return Promise.resolve(); // prevent multiple dial in devices from being provisioned
|
|
3739
3851
|
|
|
3740
3852
|
const {correlationId, locusUrl} = this;
|
|
@@ -3772,7 +3884,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3772
3884
|
* @private
|
|
3773
3885
|
* @memberof Meeting
|
|
3774
3886
|
*/
|
|
3775
|
-
dialOutPstn(phoneNumber) {
|
|
3887
|
+
private dialOutPstn(phoneNumber: string) {
|
|
3776
3888
|
if (this.isPhoneProvisioned(this.dialOutDeviceStatus)) return Promise.resolve(); // prevent multiple dial out devices from being provisioned
|
|
3777
3889
|
|
|
3778
3890
|
const {correlationId, locusUrl} = this;
|
|
@@ -3811,7 +3923,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3811
3923
|
* @memberof Meeting
|
|
3812
3924
|
* @returns {Promise}
|
|
3813
3925
|
*/
|
|
3814
|
-
disconnectPhoneAudio() {
|
|
3926
|
+
public disconnectPhoneAudio() {
|
|
3815
3927
|
return Promise.all([
|
|
3816
3928
|
this.isPhoneProvisioned(this.dialInDeviceStatus) ?
|
|
3817
3929
|
MeetingUtil.disconnectPhoneAudio(this, this.dialInUrl) :
|
|
@@ -3829,7 +3941,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3829
3941
|
* @public
|
|
3830
3942
|
* @memberof Meeting
|
|
3831
3943
|
*/
|
|
3832
|
-
moveTo(resourceId) {
|
|
3944
|
+
public moveTo(resourceId: string) {
|
|
3833
3945
|
if (!resourceId) {
|
|
3834
3946
|
throw new ParameterError('Cannot move call without a resourceId.');
|
|
3835
3947
|
}
|
|
@@ -3864,7 +3976,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3864
3976
|
|
|
3865
3977
|
try {
|
|
3866
3978
|
if (this.isSharing) {
|
|
3867
|
-
await this.
|
|
3979
|
+
await this.releaseScreenShareFloor();
|
|
3868
3980
|
}
|
|
3869
3981
|
const mediaSettings = {
|
|
3870
3982
|
mediaDirection: {
|
|
@@ -3889,6 +4001,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3889
4001
|
|
|
3890
4002
|
// 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
|
|
3891
4003
|
// once the DX answers we establish connection back the media server with only receiveShare enabled
|
|
4004
|
+
// @ts-ignore - reconnectMedia does not accept any argument
|
|
3892
4005
|
await this.reconnectionManager.reconnectMedia(mediaSettings)
|
|
3893
4006
|
.then(() => {
|
|
3894
4007
|
Metrics.sendBehavioralMetric(
|
|
@@ -3938,7 +4051,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3938
4051
|
* @public
|
|
3939
4052
|
* @memberof Meeting
|
|
3940
4053
|
*/
|
|
3941
|
-
moveFrom(resourceId) {
|
|
4054
|
+
public moveFrom(resourceId: string) {
|
|
3942
4055
|
// On moveFrom ask the developer to re capture it moveFrom then updateMedia
|
|
3943
4056
|
if (!resourceId) {
|
|
3944
4057
|
throw new ParameterError('Cannot move call without a resourceId.');
|
|
@@ -3976,6 +4089,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3976
4089
|
|
|
3977
4090
|
/**
|
|
3978
4091
|
* Get local media streams based on options passed
|
|
4092
|
+
*
|
|
4093
|
+
* NOTE: this method can only be used with transcoded meetings, not with multistream meetings
|
|
4094
|
+
*
|
|
3979
4095
|
* @param {MediaDirection} mediaDirection A configurable options object for joining a meeting
|
|
3980
4096
|
* @param {AudioVideo} [audioVideo] audio/video object to set audioinput and videoinput devices, see #Media.getUserMedia
|
|
3981
4097
|
* @param {SharePreferences} [sharePreferences] audio/video object to set audioinput and videoinput devices, see #Media.getUserMedia
|
|
@@ -3985,10 +4101,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3985
4101
|
* @memberof Meeting
|
|
3986
4102
|
*/
|
|
3987
4103
|
getMediaStreams = (
|
|
3988
|
-
mediaDirection,
|
|
4104
|
+
mediaDirection: any,
|
|
3989
4105
|
// This return an OBJECT {video: {height, widght}}
|
|
3990
|
-
audioVideo = VIDEO_RESOLUTIONS[this.mediaProperties.localQualityLevel],
|
|
3991
|
-
sharePreferences
|
|
4106
|
+
audioVideo: any = VIDEO_RESOLUTIONS[this.mediaProperties.localQualityLevel],
|
|
4107
|
+
sharePreferences?: any
|
|
3992
4108
|
) => {
|
|
3993
4109
|
if (
|
|
3994
4110
|
mediaDirection &&
|
|
@@ -4065,6 +4181,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4065
4181
|
},
|
|
4066
4182
|
audioVideo,
|
|
4067
4183
|
sharePreferences,
|
|
4184
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4068
4185
|
this.config
|
|
4069
4186
|
)
|
|
4070
4187
|
.catch((error) => {
|
|
@@ -4102,7 +4219,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4102
4219
|
* @returns {Object}
|
|
4103
4220
|
* @memberof Meetings
|
|
4104
4221
|
*/
|
|
4105
|
-
getSupportedDevices = ({sendAudio = true, sendVideo = true}) => Media.getSupportedDevice({sendAudio, sendVideo});
|
|
4222
|
+
getSupportedDevices = ({ sendAudio = true, sendVideo = true }: { sendAudio: boolean; sendVideo: boolean }) => Media.getSupportedDevice({ sendAudio, sendVideo });
|
|
4106
4223
|
|
|
4107
4224
|
/**
|
|
4108
4225
|
* Get the devices from the Media module
|
|
@@ -4111,6 +4228,344 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4111
4228
|
*/
|
|
4112
4229
|
getDevices = () => Media.getDevices();
|
|
4113
4230
|
|
|
4231
|
+
/**
|
|
4232
|
+
* Handles ROAP_FAILURE event from the webrtc media connection
|
|
4233
|
+
*
|
|
4234
|
+
* @param {Error} error
|
|
4235
|
+
* @returns {void}
|
|
4236
|
+
*/
|
|
4237
|
+
handleRoapFailure = (error) => {
|
|
4238
|
+
const sendBehavioralMetric = (metricName, error, correlationId) => {
|
|
4239
|
+
const data = {
|
|
4240
|
+
code: error.code,
|
|
4241
|
+
correlation_id: correlationId,
|
|
4242
|
+
reason: error.message,
|
|
4243
|
+
stack: error.stack
|
|
4244
|
+
};
|
|
4245
|
+
const metadata = {
|
|
4246
|
+
type: error.cause?.name || error.name
|
|
4247
|
+
};
|
|
4248
|
+
|
|
4249
|
+
Metrics.sendBehavioralMetric(metricName, data, metadata);
|
|
4250
|
+
};
|
|
4251
|
+
|
|
4252
|
+
|
|
4253
|
+
if (error instanceof MC.Errors.SdpOfferCreationError) {
|
|
4254
|
+
sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.id);
|
|
4255
|
+
|
|
4256
|
+
Metrics.postEvent({
|
|
4257
|
+
event: eventType.LOCAL_SDP_GENERATED,
|
|
4258
|
+
meetingId: this.id,
|
|
4259
|
+
data: {
|
|
4260
|
+
canProceed: false,
|
|
4261
|
+
errors: [
|
|
4262
|
+
Metrics.generateErrorPayload(2001, true, MetricsError.name.MEDIA_ENGINE, undefined)]
|
|
4263
|
+
}
|
|
4264
|
+
});
|
|
4265
|
+
}
|
|
4266
|
+
else if ((error instanceof MC.Errors.SdpOfferHandlingError) || (error instanceof MC.Errors.SdpAnswerHandlingError)) {
|
|
4267
|
+
sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.id);
|
|
4268
|
+
|
|
4269
|
+
Metrics.postEvent({
|
|
4270
|
+
event: eventType.REMOTE_SDP_RECEIVED,
|
|
4271
|
+
meetingId: this.id,
|
|
4272
|
+
data: {
|
|
4273
|
+
canProceed: false,
|
|
4274
|
+
errors: [Metrics.generateErrorPayload(2001, true, MetricsError.name.MEDIA_ENGINE, undefined)]
|
|
4275
|
+
}
|
|
4276
|
+
});
|
|
4277
|
+
}
|
|
4278
|
+
else if (error instanceof MC.Errors.SdpError) { // this covers also the case of MC.Errors.IceGatheringError which extends MC.Errors.SdpError
|
|
4279
|
+
sendBehavioralMetric(BEHAVIORAL_METRICS.INVALID_ICE_CANDIDATE, error, this.id);
|
|
4280
|
+
|
|
4281
|
+
Metrics.postEvent({
|
|
4282
|
+
event: eventType.LOCAL_SDP_GENERATED,
|
|
4283
|
+
meetingId: this.id,
|
|
4284
|
+
data: {
|
|
4285
|
+
canProceed: false,
|
|
4286
|
+
errors: [
|
|
4287
|
+
Metrics.generateErrorPayload(2001, true, MetricsError.name.MEDIA_ENGINE, undefined)]
|
|
4288
|
+
}
|
|
4289
|
+
});
|
|
4290
|
+
}
|
|
4291
|
+
};
|
|
4292
|
+
|
|
4293
|
+
setupMediaConnectionListeners = () => {
|
|
4294
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_STARTED, () => {
|
|
4295
|
+
this.isRoapInProgress = true;
|
|
4296
|
+
});
|
|
4297
|
+
|
|
4298
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_DONE, () => {
|
|
4299
|
+
this.mediaNegotiatedEvent();
|
|
4300
|
+
this.isRoapInProgress = false;
|
|
4301
|
+
this.processNextQueuedMediaUpdate();
|
|
4302
|
+
});
|
|
4303
|
+
|
|
4304
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_FAILURE, this.handleRoapFailure);
|
|
4305
|
+
|
|
4306
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.ROAP_MESSAGE_TO_SEND, (event) => {
|
|
4307
|
+
const LOG_HEADER = 'Meeting:index#setupMediaConnectionListeners.ROAP_MESSAGE_TO_SEND -->';
|
|
4308
|
+
|
|
4309
|
+
switch (event.roapMessage.messageType) {
|
|
4310
|
+
case 'OK':
|
|
4311
|
+
Metrics.postEvent({
|
|
4312
|
+
event: eventType.REMOTE_SDP_RECEIVED,
|
|
4313
|
+
meetingId: this.id,
|
|
4314
|
+
});
|
|
4315
|
+
|
|
4316
|
+
logRequest(this.roap.sendRoapOK({
|
|
4317
|
+
seq: event.roapMessage.seq,
|
|
4318
|
+
mediaId: this.mediaId,
|
|
4319
|
+
correlationId: this.correlationId
|
|
4320
|
+
}), {
|
|
4321
|
+
header: `${LOG_HEADER} Send Roap OK`,
|
|
4322
|
+
success: `${LOG_HEADER} Successfully send roap OK`,
|
|
4323
|
+
failure: `${LOG_HEADER} Error joining the call on send roap OK, `
|
|
4324
|
+
});
|
|
4325
|
+
break;
|
|
4326
|
+
|
|
4327
|
+
case 'OFFER':
|
|
4328
|
+
Metrics.postEvent({
|
|
4329
|
+
event: eventType.LOCAL_SDP_GENERATED,
|
|
4330
|
+
meetingId: this.id,
|
|
4331
|
+
});
|
|
4332
|
+
|
|
4333
|
+
logRequest(this.roap
|
|
4334
|
+
.sendRoapMediaRequest({
|
|
4335
|
+
sdp: event.roapMessage.sdp,
|
|
4336
|
+
seq: event.roapMessage.seq,
|
|
4337
|
+
tieBreaker: event.roapMessage.tieBreaker,
|
|
4338
|
+
meeting: this, // or can pass meeting ID
|
|
4339
|
+
reconnect: this.reconnectionManager.isReconnectInProgress()
|
|
4340
|
+
}), {
|
|
4341
|
+
header: `${LOG_HEADER} Send Roap Offer`,
|
|
4342
|
+
success: `${LOG_HEADER} Successfully send roap offer`,
|
|
4343
|
+
failure: `${LOG_HEADER} Error joining the call on send roap offer, `
|
|
4344
|
+
});
|
|
4345
|
+
break;
|
|
4346
|
+
|
|
4347
|
+
case 'ANSWER':
|
|
4348
|
+
Metrics.postEvent({
|
|
4349
|
+
event: eventType.REMOTE_SDP_RECEIVED,
|
|
4350
|
+
meetingId: this.id,
|
|
4351
|
+
});
|
|
4352
|
+
|
|
4353
|
+
logRequest(this.roap.sendRoapAnswer({
|
|
4354
|
+
sdp: event.roapMessage.sdp,
|
|
4355
|
+
seq: event.roapMessage.seq,
|
|
4356
|
+
mediaId: this.mediaId,
|
|
4357
|
+
correlationId: this.correlationId
|
|
4358
|
+
}), {
|
|
4359
|
+
header: `${LOG_HEADER} Send Roap Answer.`,
|
|
4360
|
+
success: `${LOG_HEADER} Successfully send roap answer`,
|
|
4361
|
+
failure: `${LOG_HEADER} Error joining the call on send roap answer, `
|
|
4362
|
+
})
|
|
4363
|
+
.catch((error) => {
|
|
4364
|
+
const metricName = BEHAVIORAL_METRICS.ROAP_ANSWER_FAILURE;
|
|
4365
|
+
const data = {
|
|
4366
|
+
correlation_id: this.correlationId,
|
|
4367
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4368
|
+
reason: error.message,
|
|
4369
|
+
stack: error.stack
|
|
4370
|
+
};
|
|
4371
|
+
const metadata = {
|
|
4372
|
+
type: error.name
|
|
4373
|
+
};
|
|
4374
|
+
|
|
4375
|
+
Metrics.sendBehavioralMetric(metricName, data, metadata);
|
|
4376
|
+
});
|
|
4377
|
+
break;
|
|
4378
|
+
|
|
4379
|
+
case 'ERROR':
|
|
4380
|
+
if (event.roapMessage.errorType === MC.ErrorType.CONFLICT || event.roapMessage.errorType === MC.ErrorType.DOUBLECONFLICT) {
|
|
4381
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_GLARE_CONDITION, {
|
|
4382
|
+
correlation_id: this.correlationId,
|
|
4383
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4384
|
+
sequence: event.roapMessage.seq
|
|
4385
|
+
});
|
|
4386
|
+
}
|
|
4387
|
+
logRequest(this.roap.sendRoapError({
|
|
4388
|
+
seq: event.roapMessage.seq,
|
|
4389
|
+
errorType: event.roapMessage.errorType,
|
|
4390
|
+
mediaId: this.mediaId,
|
|
4391
|
+
correlationId: this.correlationId
|
|
4392
|
+
}), {
|
|
4393
|
+
header: `${LOG_HEADER} Send Roap Error.`,
|
|
4394
|
+
success: `${LOG_HEADER} Successfully send roap error`,
|
|
4395
|
+
failure: `${LOG_HEADER} Failed to send roap error, `
|
|
4396
|
+
});
|
|
4397
|
+
break;
|
|
4398
|
+
|
|
4399
|
+
default:
|
|
4400
|
+
LoggerProxy.logger.error(`${LOG_HEADER} Unsupported message type: ${event.roapMessage.messageType}`);
|
|
4401
|
+
break;
|
|
4402
|
+
}
|
|
4403
|
+
});
|
|
4404
|
+
|
|
4405
|
+
// eslint-disable-next-line no-param-reassign
|
|
4406
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.REMOTE_TRACK_ADDED, (event) => {
|
|
4407
|
+
LoggerProxy.logger.log(`Meeting:index#setupMediaConnectionListeners --> REMOTE_TRACK_ADDED event received for webrtcMediaConnection: ${JSON.stringify(event)}`);
|
|
4408
|
+
|
|
4409
|
+
const mediaTrack = event.track;
|
|
4410
|
+
|
|
4411
|
+
let eventType;
|
|
4412
|
+
|
|
4413
|
+
switch (event.type) {
|
|
4414
|
+
case MC.RemoteTrackType.AUDIO:
|
|
4415
|
+
eventType = EVENT_TYPES.REMOTE_AUDIO;
|
|
4416
|
+
this.mediaProperties.setRemoteAudioTrack(event.track);
|
|
4417
|
+
break;
|
|
4418
|
+
case MC.RemoteTrackType.VIDEO:
|
|
4419
|
+
eventType = EVENT_TYPES.REMOTE_VIDEO;
|
|
4420
|
+
this.mediaProperties.setRemoteVideoTrack(event.track);
|
|
4421
|
+
break;
|
|
4422
|
+
case MC.RemoteTrackType.SCREENSHARE_VIDEO:
|
|
4423
|
+
if (event.track) {
|
|
4424
|
+
eventType = EVENT_TYPES.REMOTE_SHARE;
|
|
4425
|
+
this.mediaProperties.setRemoteShare(event.track);
|
|
4426
|
+
}
|
|
4427
|
+
break;
|
|
4428
|
+
default: {
|
|
4429
|
+
LoggerProxy.logger.log('Meeting:index#setupMediaConnectionListeners --> unexpected track');
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
|
|
4433
|
+
// start stats here the stats are coming null if you dont receive streams
|
|
4434
|
+
|
|
4435
|
+
this.statsAnalyzer.startAnalyzer(this.mediaProperties.webrtcMediaConnection);
|
|
4436
|
+
|
|
4437
|
+
if (eventType && mediaTrack) {
|
|
4438
|
+
Trigger.trigger(
|
|
4439
|
+
this,
|
|
4440
|
+
{
|
|
4441
|
+
file: 'meeting/index',
|
|
4442
|
+
function: 'setupRemoteTrackListener:Event.REMOTE_TRACK_ADDED'
|
|
4443
|
+
},
|
|
4444
|
+
EVENT_TRIGGERS.MEDIA_READY,
|
|
4445
|
+
{
|
|
4446
|
+
type: eventType,
|
|
4447
|
+
stream: MediaUtil.createMediaStream([mediaTrack])
|
|
4448
|
+
}
|
|
4449
|
+
);
|
|
4450
|
+
}
|
|
4451
|
+
});
|
|
4452
|
+
|
|
4453
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.CONNECTION_STATE_CHANGED, (event) => {
|
|
4454
|
+
const connectionFailed = () => {
|
|
4455
|
+
// we know the media connection failed and browser will not attempt to recover it any more
|
|
4456
|
+
// so reset the timer as it's not needed anymore, we want to reconnect immediately
|
|
4457
|
+
this.reconnectionManager.resetReconnectionTimer();
|
|
4458
|
+
|
|
4459
|
+
this.reconnect({networkDisconnect: true});
|
|
4460
|
+
Metrics.postEvent({
|
|
4461
|
+
event: eventType.ICE_END,
|
|
4462
|
+
meeting: this,
|
|
4463
|
+
data: {
|
|
4464
|
+
canProceed: false,
|
|
4465
|
+
errors: [
|
|
4466
|
+
Metrics.generateErrorPayload(
|
|
4467
|
+
2004, false, MetricsError.name.MEDIA_ENGINE, undefined
|
|
4468
|
+
)]
|
|
4469
|
+
}
|
|
4470
|
+
});
|
|
4471
|
+
|
|
4472
|
+
this.uploadLogs({
|
|
4473
|
+
file: 'peer-connection-manager/index',
|
|
4474
|
+
function: 'connectionFailed'
|
|
4475
|
+
});
|
|
4476
|
+
|
|
4477
|
+
Metrics.sendBehavioralMetric(
|
|
4478
|
+
BEHAVIORAL_METRICS.CONNECTION_FAILURE,
|
|
4479
|
+
{
|
|
4480
|
+
correlation_id: this.correlationId,
|
|
4481
|
+
locus_id: this.locusId
|
|
4482
|
+
}
|
|
4483
|
+
);
|
|
4484
|
+
};
|
|
4485
|
+
|
|
4486
|
+
LoggerProxy.logger.info(`Meeting:index#setupMediaConnectionListeners --> connection state changed to ${event.state}`);
|
|
4487
|
+
switch (event.state) {
|
|
4488
|
+
case MC.ConnectionState.Connecting:
|
|
4489
|
+
Metrics.postEvent({event: eventType.ICE_START, meeting: this});
|
|
4490
|
+
break;
|
|
4491
|
+
case MC.ConnectionState.Connected:
|
|
4492
|
+
Metrics.postEvent({event: eventType.ICE_END, meeting: this});
|
|
4493
|
+
Metrics.sendBehavioralMetric(
|
|
4494
|
+
BEHAVIORAL_METRICS.CONNECTION_SUCCESS,
|
|
4495
|
+
{
|
|
4496
|
+
correlation_id: this.correlationId,
|
|
4497
|
+
locus_id: this.locusId
|
|
4498
|
+
}
|
|
4499
|
+
);
|
|
4500
|
+
this.setNetworkStatus(NETWORK_STATUS.CONNECTED);
|
|
4501
|
+
this.reconnectionManager.iceReconnected();
|
|
4502
|
+
break;
|
|
4503
|
+
case MC.ConnectionState.Disconnected:
|
|
4504
|
+
this.setNetworkStatus(NETWORK_STATUS.DISCONNECTED);
|
|
4505
|
+
this.reconnectionManager.waitForIceReconnect()
|
|
4506
|
+
.catch(() => {
|
|
4507
|
+
LoggerProxy.logger.info('Meeting:index#setupMediaConnectionListeners --> state DISCONNECTED, automatic reconnection timed out.');
|
|
4508
|
+
|
|
4509
|
+
connectionFailed();
|
|
4510
|
+
});
|
|
4511
|
+
break;
|
|
4512
|
+
case MC.ConnectionState.Failed:
|
|
4513
|
+
connectionFailed();
|
|
4514
|
+
break;
|
|
4515
|
+
default:
|
|
4516
|
+
break;
|
|
4517
|
+
}
|
|
4518
|
+
});
|
|
4519
|
+
|
|
4520
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.ACTIVE_SPEAKERS_CHANGED,
|
|
4521
|
+
(msg) => {
|
|
4522
|
+
Trigger.trigger(
|
|
4523
|
+
this,
|
|
4524
|
+
{
|
|
4525
|
+
file: 'meeting/index',
|
|
4526
|
+
function: 'setupMediaConnectionListeners'
|
|
4527
|
+
},
|
|
4528
|
+
EVENT_TRIGGERS.ACTIVE_SPEAKER_CHANGED,
|
|
4529
|
+
{
|
|
4530
|
+
seqNum: msg.seqNum,
|
|
4531
|
+
memberIds: msg.csis.map((csi) => this.members.findMemberByCsi(csi)?.id).filter((item) => (item !== undefined))
|
|
4532
|
+
}
|
|
4533
|
+
);
|
|
4534
|
+
});
|
|
4535
|
+
|
|
4536
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.VIDEO_SOURCES_COUNT_CHANGED,
|
|
4537
|
+
(numTotalSources, numLiveSources) => {
|
|
4538
|
+
Trigger.trigger(
|
|
4539
|
+
this,
|
|
4540
|
+
{
|
|
4541
|
+
file: 'meeting/index',
|
|
4542
|
+
function: 'setupMediaConnectionListeners'
|
|
4543
|
+
},
|
|
4544
|
+
EVENT_TRIGGERS.REMOTE_VIDEO_SOURCE_COUNT_CHANGED,
|
|
4545
|
+
{
|
|
4546
|
+
numTotalSources,
|
|
4547
|
+
numLiveSources
|
|
4548
|
+
}
|
|
4549
|
+
);
|
|
4550
|
+
});
|
|
4551
|
+
|
|
4552
|
+
this.mediaProperties.webrtcMediaConnection.on(MC.Event.AUDIO_SOURCES_COUNT_CHANGED,
|
|
4553
|
+
(numTotalSources, numLiveSources) => {
|
|
4554
|
+
Trigger.trigger(
|
|
4555
|
+
this,
|
|
4556
|
+
{
|
|
4557
|
+
file: 'meeting/index',
|
|
4558
|
+
function: 'setupMediaConnectionListeners'
|
|
4559
|
+
},
|
|
4560
|
+
EVENT_TRIGGERS.REMOTE_AUDIO_SOURCE_COUNT_CHANGED,
|
|
4561
|
+
{
|
|
4562
|
+
numTotalSources,
|
|
4563
|
+
numLiveSources
|
|
4564
|
+
}
|
|
4565
|
+
);
|
|
4566
|
+
});
|
|
4567
|
+
};
|
|
4568
|
+
|
|
4114
4569
|
/**
|
|
4115
4570
|
* Registers for all required StatsAnalyzer events
|
|
4116
4571
|
* @private
|
|
@@ -4121,6 +4576,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4121
4576
|
this.statsAnalyzer.on(StatsAnalyzerEvents.MEDIA_QUALITY, (options) => {
|
|
4122
4577
|
// TODO: might have to send the same event to the developer
|
|
4123
4578
|
// Add ip address info if geo hint is present
|
|
4579
|
+
// @ts-ignore fix type
|
|
4124
4580
|
options.data.intervalMetadata.peerReflexiveIP = this.webex.meetings.geoHintInfo?.clientAddress || options.data.intervalMetadata.peerReflexiveIP || MQA_STATS.DEFAULT_IP;
|
|
4125
4581
|
Metrics.postEvent({event: eventType.MEDIA_QUALITY, meeting: this, data: {intervalData: options.data, networkType: options.networkType}});
|
|
4126
4582
|
});
|
|
@@ -4180,6 +4636,52 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4180
4636
|
});
|
|
4181
4637
|
};
|
|
4182
4638
|
|
|
4639
|
+
getMediaConnectionDebugId() {
|
|
4640
|
+
return `MC-${this.id.substring(0, 4)}`;
|
|
4641
|
+
}
|
|
4642
|
+
|
|
4643
|
+
createMediaConnection(turnServerInfo) {
|
|
4644
|
+
const mc = Media.createMediaConnection(
|
|
4645
|
+
this.isMultistream,
|
|
4646
|
+
this.getMediaConnectionDebugId(),
|
|
4647
|
+
{
|
|
4648
|
+
mediaProperties: this.mediaProperties,
|
|
4649
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
|
|
4650
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4651
|
+
enableRtx: this.config.enableRtx,
|
|
4652
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4653
|
+
enableExtmap: this.config.enableExtmap,
|
|
4654
|
+
turnServerInfo
|
|
4655
|
+
}
|
|
4656
|
+
);
|
|
4657
|
+
|
|
4658
|
+
this.mediaProperties.setMediaPeerConnection(mc);
|
|
4659
|
+
this.setupMediaConnectionListeners();
|
|
4660
|
+
|
|
4661
|
+
return mc;
|
|
4662
|
+
}
|
|
4663
|
+
|
|
4664
|
+
/**
|
|
4665
|
+
* Listens for an event emitted by eventEmitter and emits it from the meeting object
|
|
4666
|
+
*
|
|
4667
|
+
* @private
|
|
4668
|
+
* @param {*} eventEmitter object from which to forward the event
|
|
4669
|
+
* @param {*} eventTypeToForward which event type to listen on and to forward
|
|
4670
|
+
* @param {string} meetingEventType event type to be used in the event emitted from the meeting object
|
|
4671
|
+
* @returns {void}
|
|
4672
|
+
*/
|
|
4673
|
+
forwardEvent(eventEmitter, eventTypeToForward, meetingEventType) {
|
|
4674
|
+
eventEmitter.on(eventTypeToForward, (data) => Trigger.trigger(
|
|
4675
|
+
this,
|
|
4676
|
+
{
|
|
4677
|
+
file: 'meetings',
|
|
4678
|
+
function: 'addMedia'
|
|
4679
|
+
},
|
|
4680
|
+
meetingEventType,
|
|
4681
|
+
data
|
|
4682
|
+
));
|
|
4683
|
+
}
|
|
4684
|
+
|
|
4183
4685
|
/**
|
|
4184
4686
|
* Specify joining via audio (option: pstn), video, screenshare
|
|
4185
4687
|
* @param {Object} options A configurable options object for joining a meeting
|
|
@@ -4187,11 +4689,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4187
4689
|
* @param {MediaDirection} options.mediaSettings pass media options
|
|
4188
4690
|
* @param {MediaStream} options.localStream
|
|
4189
4691
|
* @param {MediaStream} options.localShare
|
|
4692
|
+
* @param {RemoteMediaManagerConfig} options.remoteMediaManagerConfig only applies if multistream is enabled
|
|
4190
4693
|
* @returns {Promise}
|
|
4191
4694
|
* @public
|
|
4192
4695
|
* @memberof Meeting
|
|
4193
4696
|
*/
|
|
4194
|
-
addMedia(options = {}) {
|
|
4697
|
+
addMedia(options: any = {}) {
|
|
4195
4698
|
const LOG_HEADER = 'Meeting:index#addMedia -->';
|
|
4196
4699
|
|
|
4197
4700
|
let turnDiscoverySkippedReason;
|
|
@@ -4205,11 +4708,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4205
4708
|
return Promise.reject(new UserNotJoinedError());
|
|
4206
4709
|
}
|
|
4207
4710
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
|
4711
|
+
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
|
4208
4712
|
if (this.isUserUnadmitted && !this.wirelessShare) {
|
|
4209
4713
|
return Promise.reject(new UserInLobbyError());
|
|
4210
4714
|
}
|
|
4211
4715
|
|
|
4212
|
-
const {
|
|
4716
|
+
const {
|
|
4717
|
+
localStream, localShare, mediaSettings, remoteMediaManagerConfig
|
|
4718
|
+
} = options;
|
|
4213
4719
|
|
|
4214
4720
|
LoggerProxy.logger.info(`${LOG_HEADER} Adding Media.`);
|
|
4215
4721
|
|
|
@@ -4244,145 +4750,112 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4244
4750
|
|
|
4245
4751
|
const {turnServerInfo} = turnDiscoveryObject;
|
|
4246
4752
|
|
|
4247
|
-
this.
|
|
4248
|
-
this.setMercuryListener();
|
|
4249
|
-
PeerConnectionManager.setPeerConnectionEvents(this);
|
|
4753
|
+
this.preMedia(localStream, localShare, mediaSettings);
|
|
4250
4754
|
|
|
4251
|
-
|
|
4252
|
-
})
|
|
4253
|
-
.then(() => Media.attachMedia(this.mediaProperties, {
|
|
4254
|
-
meetingId: this.id,
|
|
4255
|
-
remoteQualityLevel: this.mediaProperties.remoteQualityLevel,
|
|
4256
|
-
enableRtx: this.config.enableRtx,
|
|
4257
|
-
enableExtmap: this.config.enableExtmap,
|
|
4258
|
-
setStartLocalSDPGenRemoteSDPRecvDelay: this.setStartLocalSDPGenRemoteSDPRecvDelay.bind(this)
|
|
4259
|
-
})
|
|
4260
|
-
.then((peerConnection) => this.getDevices().then((devices) => {
|
|
4261
|
-
MeetingUtil.handleDeviceLogging(devices);
|
|
4262
|
-
|
|
4263
|
-
return peerConnection;
|
|
4264
|
-
}))
|
|
4265
|
-
.then((peerConnection) => {
|
|
4266
|
-
this.handleMediaLogging(this.mediaProperties);
|
|
4267
|
-
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection Received from attachMedia `);
|
|
4268
|
-
|
|
4269
|
-
this.setRemoteStream(peerConnection);
|
|
4270
|
-
if (this.config.stats.enableStatsAnalyzer) {
|
|
4271
|
-
// TODO: ** Dont re create StatsAnalyzer on reconnect or rejoin
|
|
4272
|
-
this.networkQualityMonitor = new NetworkQualityMonitor(this.config.stats);
|
|
4273
|
-
this.statsAnalyzer = new StatsAnalyzer(this.config.stats, this.networkQualityMonitor);
|
|
4274
|
-
this.setupStatsAnalyzerEventHandlers();
|
|
4275
|
-
this.networkQualityMonitor.on(EVENT_TRIGGERS.NETWORK_QUALITY, this.sendNetworkQualityEvent.bind(this));
|
|
4276
|
-
}
|
|
4277
|
-
})
|
|
4278
|
-
.catch((error) => {
|
|
4279
|
-
LoggerProxy.logger.error(`${LOG_HEADER} Error adding media , setting up peerconnection, `, error);
|
|
4755
|
+
const mc = this.createMediaConnection(turnServerInfo);
|
|
4280
4756
|
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
reason: error.message,
|
|
4287
|
-
stack: error.stack,
|
|
4288
|
-
turnDiscoverySkippedReason,
|
|
4289
|
-
turnServerUsed
|
|
4290
|
-
}
|
|
4757
|
+
if (this.isMultistream) {
|
|
4758
|
+
this.remoteMediaManager = new RemoteMediaManager(
|
|
4759
|
+
this.receiveSlotManager,
|
|
4760
|
+
this.mediaRequestManagers,
|
|
4761
|
+
remoteMediaManagerConfig
|
|
4291
4762
|
);
|
|
4292
4763
|
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
let timerCount = 0;
|
|
4297
|
-
|
|
4298
|
-
// eslint-disable-next-line func-names
|
|
4299
|
-
// eslint-disable-next-line prefer-arrow-callback
|
|
4300
|
-
if (this.type === _CALL_) {
|
|
4301
|
-
resolve();
|
|
4302
|
-
}
|
|
4303
|
-
const joiningTimer = setInterval(() => {
|
|
4304
|
-
timerCount += 1;
|
|
4305
|
-
if (this.meetingState === FULL_STATE.ACTIVE) {
|
|
4306
|
-
clearInterval(joiningTimer);
|
|
4307
|
-
resolve();
|
|
4308
|
-
}
|
|
4764
|
+
this.forwardEvent(this.remoteMediaManager, RemoteMediaManagerEvent.AudioCreated, EVENT_TRIGGERS.REMOTE_MEDIA_AUDIO_CREATED);
|
|
4765
|
+
this.forwardEvent(this.remoteMediaManager, RemoteMediaManagerEvent.ScreenShareAudioCreated, EVENT_TRIGGERS.REMOTE_MEDIA_SCREEN_SHARE_AUDIO_CREATED);
|
|
4766
|
+
this.forwardEvent(this.remoteMediaManager, RemoteMediaManagerEvent.VideoLayoutChanged, EVENT_TRIGGERS.REMOTE_MEDIA_VIDEO_LAYOUT_CHANGED);
|
|
4309
4767
|
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
}
|
|
4314
|
-
}, 1000);
|
|
4315
|
-
}))
|
|
4316
|
-
.then(() =>
|
|
4317
|
-
logRequest(this.roap
|
|
4318
|
-
.sendRoapMediaRequest({
|
|
4319
|
-
sdp: this.mediaProperties.peerConnection.sdp,
|
|
4320
|
-
roapSeq: this.roapSeq,
|
|
4321
|
-
meeting: this // or can pass meeting ID
|
|
4322
|
-
}), {
|
|
4323
|
-
header: `${LOG_HEADER} Send Roap Media Request.`,
|
|
4324
|
-
success: `${LOG_HEADER} Successfully send roap media request`,
|
|
4325
|
-
failure: `${LOG_HEADER} Error joining the call on send roap media request, `
|
|
4326
|
-
}))
|
|
4327
|
-
.then(() => {
|
|
4328
|
-
const {peerConnection} = this.mediaProperties;
|
|
4329
|
-
|
|
4330
|
-
return new Promise((resolve, reject) => {
|
|
4331
|
-
if (peerConnection.connectionState === CONNECTION_STATE.CONNECTED) {
|
|
4332
|
-
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection CONNECTED`);
|
|
4768
|
+
return this.remoteMediaManager.start()
|
|
4769
|
+
.then(() => mc.initiateOffer());
|
|
4770
|
+
}
|
|
4333
4771
|
|
|
4334
|
-
|
|
4772
|
+
return mc.initiateOffer();
|
|
4773
|
+
})
|
|
4774
|
+
.then(() => {
|
|
4775
|
+
this.setMercuryListener();
|
|
4776
|
+
})
|
|
4777
|
+
.then(() => this.getDevices().then((devices) => {
|
|
4778
|
+
MeetingUtil.handleDeviceLogging(devices);
|
|
4779
|
+
}))
|
|
4780
|
+
.then(() => {
|
|
4781
|
+
this.handleMediaLogging(this.mediaProperties);
|
|
4782
|
+
LoggerProxy.logger.info(`${LOG_HEADER} media connection created`);
|
|
4783
|
+
|
|
4784
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4785
|
+
if (this.config.stats.enableStatsAnalyzer) {
|
|
4786
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4787
|
+
this.networkQualityMonitor = new NetworkQualityMonitor(this.config.stats);
|
|
4788
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4789
|
+
this.statsAnalyzer = new StatsAnalyzer(this.config.stats, this.networkQualityMonitor);
|
|
4790
|
+
this.setupStatsAnalyzerEventHandlers();
|
|
4791
|
+
this.networkQualityMonitor.on(EVENT_TRIGGERS.NETWORK_QUALITY, this.sendNetworkQualityEvent.bind(this));
|
|
4792
|
+
}
|
|
4793
|
+
})
|
|
4794
|
+
.catch((error) => {
|
|
4795
|
+
LoggerProxy.logger.error(`${LOG_HEADER} Error adding media , setting up peerconnection, `, error);
|
|
4335
4796
|
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
if (peerConnection.connectionState !== CONNECTION_STATE.CONNECTED) {
|
|
4341
|
-
// TODO: Fix this after the error code pr goes in
|
|
4342
|
-
reject(createMeetingsError(30202, 'Meeting connection failed'));
|
|
4343
|
-
}
|
|
4344
|
-
else {
|
|
4345
|
-
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection CONNECTED`);
|
|
4346
|
-
resolve(peerConnection);
|
|
4347
|
-
}
|
|
4348
|
-
}, PC_BAIL_TIMEOUT);
|
|
4797
|
+
throw error;
|
|
4798
|
+
})
|
|
4799
|
+
.then(() => new Promise<void>((resolve, reject) => {
|
|
4800
|
+
let timerCount = 0;
|
|
4349
4801
|
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
}
|
|
4802
|
+
// eslint-disable-next-line func-names
|
|
4803
|
+
// eslint-disable-next-line prefer-arrow-callback
|
|
4804
|
+
if (this.type === _CALL_) {
|
|
4805
|
+
resolve();
|
|
4806
|
+
}
|
|
4807
|
+
const joiningTimer = setInterval(() => {
|
|
4808
|
+
timerCount += 1;
|
|
4809
|
+
if (this.meetingState === FULL_STATE.ACTIVE) {
|
|
4810
|
+
clearInterval(joiningTimer);
|
|
4811
|
+
resolve();
|
|
4812
|
+
}
|
|
4362
4813
|
|
|
4363
|
-
|
|
4364
|
-
|
|
4814
|
+
if (timerCount === 4) {
|
|
4815
|
+
clearInterval(joiningTimer);
|
|
4816
|
+
reject(new Error('Meeting is still not active '));
|
|
4817
|
+
}
|
|
4818
|
+
}, 1000);
|
|
4819
|
+
}))
|
|
4820
|
+
.then(
|
|
4821
|
+
() => this.mediaProperties.waitForMediaConnectionConnected()
|
|
4822
|
+
.catch(() => {
|
|
4823
|
+
throw createMeetingsError(30202, 'Meeting connection failed');
|
|
4824
|
+
})
|
|
4825
|
+
)
|
|
4826
|
+
.then(() => {
|
|
4827
|
+
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection CONNECTED`);
|
|
4828
|
+
if (mediaSettings && mediaSettings.sendShare && localShare) {
|
|
4829
|
+
if (this.state === MEETING_STATE.STATES.JOINED) {
|
|
4830
|
+
return this.requestScreenShareFloor();
|
|
4365
4831
|
}
|
|
4366
4832
|
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
correlation_id: this.correlationId,
|
|
4371
|
-
locus_id: this.locusUrl.split('/').pop()
|
|
4372
|
-
}
|
|
4373
|
-
);
|
|
4833
|
+
// When the self state changes to JOINED then request the floor
|
|
4834
|
+
this.floorGrantPending = true;
|
|
4835
|
+
}
|
|
4374
4836
|
|
|
4375
|
-
|
|
4376
|
-
|
|
4837
|
+
return {};
|
|
4838
|
+
})
|
|
4839
|
+
.then(() => this.mediaProperties.getCurrentConnectionType())
|
|
4840
|
+
.then((connectionType) => {
|
|
4841
|
+
Metrics.sendBehavioralMetric(
|
|
4842
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS,
|
|
4843
|
+
{
|
|
4844
|
+
correlation_id: this.correlationId,
|
|
4845
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4846
|
+
connectionType
|
|
4847
|
+
}
|
|
4848
|
+
);
|
|
4849
|
+
})
|
|
4377
4850
|
.catch((error) => {
|
|
4378
4851
|
// Clean up stats analyzer, peer connection, and turn off listeners
|
|
4379
4852
|
const stopStatsAnalyzer = (this.statsAnalyzer) ? this.statsAnalyzer.stopAnalyzer() : Promise.resolve();
|
|
4380
4853
|
|
|
4381
|
-
stopStatsAnalyzer
|
|
4854
|
+
return stopStatsAnalyzer
|
|
4382
4855
|
.then(() => {
|
|
4383
4856
|
this.statsAnalyzer = null;
|
|
4384
4857
|
|
|
4385
|
-
if (this.mediaProperties.
|
|
4858
|
+
if (this.mediaProperties.webrtcMediaConnection) {
|
|
4386
4859
|
this.closePeerConnections();
|
|
4387
4860
|
this.unsetPeerConnections();
|
|
4388
4861
|
}
|
|
@@ -4413,10 +4886,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4413
4886
|
this
|
|
4414
4887
|
);
|
|
4415
4888
|
|
|
4416
|
-
|
|
4417
|
-
// leave the meeting with reson connection failed as meeting anyways will end
|
|
4418
|
-
// and cannot be connected unless network condition is checked for firewall
|
|
4419
|
-
if (error.code === InvalidSdpError.CODE) {
|
|
4889
|
+
if (error instanceof MC.Errors.SdpError) {
|
|
4420
4890
|
this.leave({reason: MEETING_REMOVED_REASON.MEETING_CONNECTION_FAILED});
|
|
4421
4891
|
}
|
|
4422
4892
|
|
|
@@ -4430,7 +4900,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4430
4900
|
* @returns {Boolean}
|
|
4431
4901
|
*/
|
|
4432
4902
|
canUpdateMedia() {
|
|
4433
|
-
|
|
4903
|
+
// in theory we shouldn't need this as RoapMediaConnection handles multiple updates, glare, etc,
|
|
4904
|
+
// but there are some server issues, like https://jira-eng-gpk2.cisco.com/jira/browse/WEBEX-248394
|
|
4905
|
+
// so for now it's better to keep queuing any media updates at SDK meeting level
|
|
4906
|
+
return !this.isRoapInProgress;
|
|
4434
4907
|
}
|
|
4435
4908
|
|
|
4436
4909
|
/**
|
|
@@ -4441,7 +4914,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4441
4914
|
* @private
|
|
4442
4915
|
* @memberof Meeting
|
|
4443
4916
|
*/
|
|
4444
|
-
enqueueMediaUpdate(mediaUpdateType, options) {
|
|
4917
|
+
private enqueueMediaUpdate(mediaUpdateType: string, options: object) {
|
|
4445
4918
|
return new Promise((resolve, reject) => {
|
|
4446
4919
|
const queueItem = {
|
|
4447
4920
|
pendingPromiseResolve: resolve, pendingPromiseReject: reject, mediaUpdateType, options
|
|
@@ -4459,6 +4932,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4459
4932
|
* @memberof Meeting
|
|
4460
4933
|
*/
|
|
4461
4934
|
mediaNegotiatedEvent = () => {
|
|
4935
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4462
4936
|
if (this.config.experimental.enableMediaNegotiatedEvent) {
|
|
4463
4937
|
LoggerProxy.logger.info('Meeting:mediaNegotiatedEvent --> Media server negotiated');
|
|
4464
4938
|
Trigger.trigger(
|
|
@@ -4514,11 +4988,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4514
4988
|
* @param {MediaStream} options.localShare
|
|
4515
4989
|
* @param {MediaDirection} options.mediaSettings
|
|
4516
4990
|
* @returns {Promise}
|
|
4517
|
-
* @todo fix setRemoteStream for updateMedia
|
|
4518
4991
|
* @public
|
|
4519
4992
|
* @memberof Meeting
|
|
4520
4993
|
*/
|
|
4521
|
-
updateMedia(
|
|
4994
|
+
public updateMedia(
|
|
4995
|
+
options: {
|
|
4996
|
+
localStream?: MediaStream;
|
|
4997
|
+
localShare?: MediaStream;
|
|
4998
|
+
mediaSettings?: any;
|
|
4999
|
+
} = {} as any
|
|
5000
|
+
) {
|
|
4522
5001
|
const LOG_HEADER = 'Meeting:index#updateMedia -->';
|
|
4523
5002
|
|
|
4524
5003
|
if (!this.canUpdateMedia()) {
|
|
@@ -4530,20 +5009,27 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4530
5009
|
|
|
4531
5010
|
const previousSendShareStatus = this.mediaProperties.mediaDirection.sendShare;
|
|
4532
5011
|
|
|
5012
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
5013
|
+
return Promise.reject(new Error('media connection not established, call addMedia() first'));
|
|
5014
|
+
}
|
|
5015
|
+
|
|
4533
5016
|
return MeetingUtil.validateOptions(options)
|
|
4534
5017
|
.then(() => this.preMedia(localStream, localShare, mediaSettings))
|
|
4535
|
-
.then(() =>
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
5018
|
+
.then(() => this.mediaProperties.webrtcMediaConnection.updateSendReceiveOptions({
|
|
5019
|
+
send: {
|
|
5020
|
+
audio: this.mediaProperties.mediaDirection.sendAudio ? this.mediaProperties.audioTrack : null,
|
|
5021
|
+
video: this.mediaProperties.mediaDirection.sendVideo ? this.mediaProperties.videoTrack : null,
|
|
5022
|
+
screenShareVideo: this.mediaProperties.mediaDirection.sendShare ? this.mediaProperties.shareTrack : null
|
|
5023
|
+
},
|
|
5024
|
+
receive: {
|
|
5025
|
+
audio: this.mediaProperties.mediaDirection.receiveAudio,
|
|
5026
|
+
video: this.mediaProperties.mediaDirection.receiveVideo,
|
|
5027
|
+
screenShareVideo: this.mediaProperties.mediaDirection.receiveShare,
|
|
5028
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel
|
|
5029
|
+
}
|
|
4540
5030
|
})
|
|
4541
|
-
.then((
|
|
4542
|
-
LoggerProxy.logger.info(`${LOG_HEADER}
|
|
4543
|
-
this.setRemoteStream(peerConnection);
|
|
4544
|
-
if (mediaSettings.receiveShare || localShare) {
|
|
4545
|
-
PeerConnectionManager.setContentSlides(peerConnection);
|
|
4546
|
-
}
|
|
5031
|
+
.then(() => {
|
|
5032
|
+
LoggerProxy.logger.info(`${LOG_HEADER} webrtcMediaConnection.updateSendReceiveOptions done`);
|
|
4547
5033
|
})
|
|
4548
5034
|
.catch((error) => {
|
|
4549
5035
|
LoggerProxy.logger.error(`${LOG_HEADER} Error updatedMedia, `, error);
|
|
@@ -4560,25 +5046,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4560
5046
|
|
|
4561
5047
|
throw error;
|
|
4562
5048
|
})
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
roapSeq: this.roapSeq,
|
|
4568
|
-
meeting: this, // or can pass meeting ID
|
|
4569
|
-
}),
|
|
4570
|
-
{
|
|
4571
|
-
header: `${LOG_HEADER} sendRoapMediaRequest being sent`,
|
|
4572
|
-
success: `${LOG_HEADER} sendRoadMediaRequest successful`,
|
|
4573
|
-
failure: `${LOG_HEADER} Error updateMedia on send roap media request, `
|
|
4574
|
-
}))
|
|
5049
|
+
// todo: the following code used to be called always after sending the roap message with the new SDP
|
|
5050
|
+
// now it's called independently from the roap message (so might be before it), check if that's OK
|
|
5051
|
+
// if not, ensure it's called after (now it's called after roap message is sent out, but we're not
|
|
5052
|
+
// waiting for sendRoapMediaRequest() to be resolved)
|
|
4575
5053
|
.then(() => this.checkForStopShare(mediaSettings.sendShare, previousSendShareStatus))
|
|
4576
5054
|
.then((startShare) => {
|
|
4577
5055
|
// This is a special case if we do an /floor grant followed by /media
|
|
4578
5056
|
// we actually get a OFFER from the server and a GLAR condition happens
|
|
4579
5057
|
if (startShare) {
|
|
4580
5058
|
// We are assuming that the clients are connected when doing an update
|
|
4581
|
-
return this.
|
|
5059
|
+
return this.requestScreenShareFloor();
|
|
4582
5060
|
}
|
|
4583
5061
|
|
|
4584
5062
|
return Promise.resolve();
|
|
@@ -4587,6 +5065,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4587
5065
|
|
|
4588
5066
|
/**
|
|
4589
5067
|
* Update the main audio track with new parameters
|
|
5068
|
+
*
|
|
5069
|
+
* NOTE: this method can only be used with transcoded meetings, for multistream meetings use publishTrack()
|
|
5070
|
+
*
|
|
4590
5071
|
* @param {Object} options
|
|
4591
5072
|
* @param {boolean} options.sendAudio
|
|
4592
5073
|
* @param {boolean} options.receiveAudio
|
|
@@ -4595,21 +5076,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4595
5076
|
* @public
|
|
4596
5077
|
* @memberof Meeting
|
|
4597
5078
|
*/
|
|
4598
|
-
async updateAudio(options) {
|
|
5079
|
+
public async updateAudio(options: { sendAudio: boolean; receiveAudio: boolean; stream: MediaStream }) {
|
|
4599
5080
|
if (!this.canUpdateMedia()) {
|
|
4600
5081
|
return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.AUDIO, options);
|
|
4601
5082
|
}
|
|
4602
|
-
const {
|
|
4603
|
-
sendAudio, receiveAudio, stream
|
|
4604
|
-
} = options;
|
|
4605
|
-
|
|
4606
|
-
const {audioTransceiver} = this.mediaProperties.peerConnection;
|
|
5083
|
+
const {sendAudio, receiveAudio, stream} = options;
|
|
4607
5084
|
let track = MeetingUtil.getTrack(stream).audioTrack;
|
|
4608
5085
|
|
|
4609
5086
|
if (typeof sendAudio !== 'boolean' || typeof receiveAudio !== 'boolean') {
|
|
4610
5087
|
return Promise.reject(new ParameterError('Pass sendAudio and receiveAudio parameter'));
|
|
4611
5088
|
}
|
|
4612
5089
|
|
|
5090
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
5091
|
+
return Promise.reject(new Error('media connection not established, call addMedia() first'));
|
|
5092
|
+
}
|
|
5093
|
+
|
|
4613
5094
|
if (this.effects && this.effects.state) {
|
|
4614
5095
|
const bnrEnabled = this.effects.state.bnr.enabled;
|
|
4615
5096
|
|
|
@@ -4621,38 +5102,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4621
5102
|
}
|
|
4622
5103
|
|
|
4623
5104
|
return MeetingUtil.validateOptions({sendAudio, localStream: stream})
|
|
4624
|
-
.then(() => {
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
};
|
|
4632
|
-
}
|
|
4633
|
-
else {
|
|
4634
|
-
this.mediaProperties.mediaDirection = {};
|
|
5105
|
+
.then(() => this.mediaProperties.webrtcMediaConnection.updateSendReceiveOptions({
|
|
5106
|
+
send: {audio: track},
|
|
5107
|
+
receive: {
|
|
5108
|
+
audio: options.receiveAudio,
|
|
5109
|
+
video: this.mediaProperties.mediaDirection.receiveVideo,
|
|
5110
|
+
screenShareVideo: this.mediaProperties.mediaDirection.receiveShare,
|
|
5111
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel
|
|
4635
5112
|
}
|
|
4636
|
-
|
|
4637
|
-
return MeetingUtil.updateTransceiver(
|
|
4638
|
-
{
|
|
4639
|
-
type: 'audio',
|
|
4640
|
-
sendTrack: options.sendAudio,
|
|
4641
|
-
receiveTrack: options.receiveAudio,
|
|
4642
|
-
track,
|
|
4643
|
-
transceiver: audioTransceiver,
|
|
4644
|
-
peerConnection: this.mediaProperties.peerConnection,
|
|
4645
|
-
previousMediaDirection
|
|
4646
|
-
},
|
|
4647
|
-
{
|
|
4648
|
-
mediaProperties: this.mediaProperties,
|
|
4649
|
-
meeting: this,
|
|
4650
|
-
id: this.id
|
|
4651
|
-
}
|
|
4652
|
-
);
|
|
4653
|
-
})
|
|
5113
|
+
}))
|
|
4654
5114
|
.then(() => {
|
|
4655
5115
|
this.setLocalAudioTrack(track);
|
|
5116
|
+
// todo: maybe this.mediaProperties.mediaDirection could be removed? it's duplicating stuff from webrtcMediaConnection
|
|
4656
5117
|
this.mediaProperties.mediaDirection.sendAudio = sendAudio;
|
|
4657
5118
|
this.mediaProperties.mediaDirection.receiveAudio = receiveAudio;
|
|
4658
5119
|
|
|
@@ -4663,6 +5124,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4663
5124
|
|
|
4664
5125
|
/**
|
|
4665
5126
|
* Update the main video track with new parameters
|
|
5127
|
+
*
|
|
5128
|
+
* NOTE: this method can only be used with transcoded meetings, for multistream meetings use publishTrack()
|
|
5129
|
+
*
|
|
4666
5130
|
* @param {Object} options
|
|
4667
5131
|
* @param {boolean} options.sendVideo
|
|
4668
5132
|
* @param {boolean} options.receiveVideo
|
|
@@ -4671,35 +5135,30 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4671
5135
|
* @public
|
|
4672
5136
|
* @memberof Meeting
|
|
4673
5137
|
*/
|
|
4674
|
-
updateVideo(options) {
|
|
5138
|
+
public updateVideo(options: { sendVideo: boolean; receiveVideo: boolean; stream: MediaStream }) {
|
|
4675
5139
|
if (!this.canUpdateMedia()) {
|
|
4676
5140
|
return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.VIDEO, options);
|
|
4677
5141
|
}
|
|
4678
5142
|
const {sendVideo, receiveVideo, stream} = options;
|
|
4679
|
-
const {videoTransceiver} = this.mediaProperties.peerConnection;
|
|
4680
5143
|
const track = MeetingUtil.getTrack(stream).videoTrack;
|
|
4681
5144
|
|
|
4682
5145
|
if (typeof sendVideo !== 'boolean' || typeof receiveVideo !== 'boolean') {
|
|
4683
5146
|
return Promise.reject(new ParameterError('Pass sendVideo and receiveVideo parameter'));
|
|
4684
5147
|
}
|
|
4685
5148
|
|
|
5149
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
5150
|
+
return Promise.reject(new Error('media connection not established, call addMedia() first'));
|
|
5151
|
+
}
|
|
5152
|
+
|
|
4686
5153
|
return MeetingUtil.validateOptions({sendVideo, localStream: stream})
|
|
4687
|
-
.then(() =>
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
previousMediaDirection: {
|
|
4695
|
-
sendTrack: this.mediaProperties.mediaDirection.sendVideo,
|
|
4696
|
-
receiveTrack: this.mediaProperties.mediaDirection.receiveVideo
|
|
5154
|
+
.then(() => this.mediaProperties.webrtcMediaConnection.updateSendReceiveOptions({
|
|
5155
|
+
send: {video: track},
|
|
5156
|
+
receive: {
|
|
5157
|
+
audio: this.mediaProperties.mediaDirection.receiveAudio,
|
|
5158
|
+
video: options.receiveVideo,
|
|
5159
|
+
screenShareVideo: this.mediaProperties.mediaDirection.receiveShare,
|
|
5160
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel
|
|
4697
5161
|
}
|
|
4698
|
-
},
|
|
4699
|
-
{
|
|
4700
|
-
mediaProperties: this.mediaProperties,
|
|
4701
|
-
meeting: this,
|
|
4702
|
-
id: this.id
|
|
4703
5162
|
}))
|
|
4704
5163
|
.then(() => {
|
|
4705
5164
|
this.setLocalVideoTrack(track);
|
|
@@ -4719,7 +5178,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4719
5178
|
* @private
|
|
4720
5179
|
* @memberof Meeting
|
|
4721
5180
|
*/
|
|
4722
|
-
checkForStopShare(sendShare, previousShareStatus) {
|
|
5181
|
+
private checkForStopShare(sendShare: boolean, previousShareStatus: boolean) {
|
|
4723
5182
|
if (sendShare && !previousShareStatus) {
|
|
4724
5183
|
// When user starts sharing
|
|
4725
5184
|
return Promise.resolve(true);
|
|
@@ -4727,7 +5186,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4727
5186
|
|
|
4728
5187
|
if (!sendShare && previousShareStatus) {
|
|
4729
5188
|
// When user stops sharing
|
|
4730
|
-
return this.
|
|
5189
|
+
return this.releaseScreenShareFloor()
|
|
4731
5190
|
.then(() => Promise.resolve(false));
|
|
4732
5191
|
}
|
|
4733
5192
|
|
|
@@ -4736,6 +5195,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4736
5195
|
|
|
4737
5196
|
/**
|
|
4738
5197
|
* Update the share streams, can be used to start sharing
|
|
5198
|
+
*
|
|
5199
|
+
* NOTE: this method can only be used with transcoded meetings, for multistream meetings use publishTrack()
|
|
5200
|
+
*
|
|
4739
5201
|
* @param {Object} options
|
|
4740
5202
|
* @param {boolean} options.sendShare
|
|
4741
5203
|
* @param {boolean} options.receiveShare
|
|
@@ -4743,43 +5205,39 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4743
5205
|
* @public
|
|
4744
5206
|
* @memberof Meeting
|
|
4745
5207
|
*/
|
|
4746
|
-
updateShare(options) {
|
|
5208
|
+
public updateShare(options: { sendShare?: boolean; receiveShare?: boolean, stream?: any, skipSignalingCheck?: boolean }) {
|
|
4747
5209
|
if (!options.skipSignalingCheck && !this.canUpdateMedia()) {
|
|
4748
5210
|
return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.SHARE, options);
|
|
4749
5211
|
}
|
|
4750
5212
|
const {sendShare, receiveShare, stream} = options;
|
|
4751
|
-
const {shareTransceiver} = this.mediaProperties.peerConnection;
|
|
4752
5213
|
const track = MeetingUtil.getTrack(stream).videoTrack;
|
|
4753
5214
|
|
|
4754
5215
|
if (typeof sendShare !== 'boolean' || typeof receiveShare !== 'boolean') {
|
|
4755
5216
|
return Promise.reject(new ParameterError('Pass sendShare and receiveShare parameter'));
|
|
4756
5217
|
}
|
|
5218
|
+
|
|
5219
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
5220
|
+
return Promise.reject(new Error('media connection not established, call addMedia() first'));
|
|
5221
|
+
}
|
|
5222
|
+
|
|
4757
5223
|
const previousSendShareStatus = this.mediaProperties.mediaDirection.sendShare;
|
|
4758
5224
|
|
|
4759
5225
|
this.setLocalShareTrack(stream);
|
|
4760
5226
|
|
|
4761
5227
|
return MeetingUtil.validateOptions({sendShare, localShare: stream})
|
|
4762
5228
|
.then(() => this.checkForStopShare(sendShare, previousSendShareStatus))
|
|
4763
|
-
.then((startShare) =>
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
previousMediaDirection: {
|
|
4771
|
-
sendTrack: this.mediaProperties.mediaDirection.sendShare,
|
|
4772
|
-
receiveTrack: this.mediaProperties.mediaDirection.receiveShare
|
|
5229
|
+
.then((startShare) => this.mediaProperties.webrtcMediaConnection.updateSendReceiveOptions({
|
|
5230
|
+
send: {screenShareVideo: track},
|
|
5231
|
+
receive: {
|
|
5232
|
+
audio: this.mediaProperties.mediaDirection.receiveAudio,
|
|
5233
|
+
video: this.mediaProperties.mediaDirection.receiveVideo,
|
|
5234
|
+
screenShareVideo: options.receiveShare,
|
|
5235
|
+
remoteQualityLevel: this.mediaProperties.remoteQualityLevel
|
|
4773
5236
|
}
|
|
4774
|
-
},
|
|
4775
|
-
{
|
|
4776
|
-
mediaProperties: this.mediaProperties,
|
|
4777
|
-
meeting: this,
|
|
4778
|
-
id: this.id
|
|
4779
5237
|
})
|
|
4780
5238
|
.then(() => {
|
|
4781
5239
|
if (startShare) {
|
|
4782
|
-
return this.
|
|
5240
|
+
return this.requestScreenShareFloor();
|
|
4783
5241
|
}
|
|
4784
5242
|
|
|
4785
5243
|
return Promise.resolve();
|
|
@@ -4789,24 +5247,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4789
5247
|
this.mediaProperties.mediaDirection.receiveShare = receiveShare;
|
|
4790
5248
|
})
|
|
4791
5249
|
.catch((error) => {
|
|
4792
|
-
this.unsetLocalShareTrack(
|
|
5250
|
+
this.unsetLocalShareTrack();
|
|
4793
5251
|
throw error;
|
|
4794
|
-
})
|
|
4795
|
-
.finally(() => {
|
|
4796
|
-
const delay = 1e3;
|
|
4797
|
-
// Check to see if share was stopped natively before onended was assigned.
|
|
4798
|
-
const sharingModeIsActive = this.mediaProperties.peerConnection.shareTransceiver.direction === SENDRECV;
|
|
4799
|
-
const isSharingOutOfSync = sharingModeIsActive && !this.isLocalShareLive;
|
|
4800
|
-
|
|
4801
|
-
if (isSharingOutOfSync) {
|
|
4802
|
-
// Adding a delay to avoid a 409 from server
|
|
4803
|
-
// which results in user still appearing as if sharing.
|
|
4804
|
-
// Also delay give time for changes to peerConnection.
|
|
4805
|
-
setTimeout(
|
|
4806
|
-
() => this.handleShareTrackEnded(stream),
|
|
4807
|
-
delay
|
|
4808
|
-
);
|
|
4809
|
-
}
|
|
4810
5252
|
});
|
|
4811
5253
|
}
|
|
4812
5254
|
|
|
@@ -4819,9 +5261,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4819
5261
|
* @private
|
|
4820
5262
|
* @memberof Meeting
|
|
4821
5263
|
*/
|
|
4822
|
-
preMedia(localStream, localShare, mediaSettings) {
|
|
5264
|
+
private preMedia(localStream: MediaStream, localShare: MediaStream, mediaSettings: any) {
|
|
4823
5265
|
// eslint-disable-next-line no-warning-comments
|
|
4824
5266
|
// TODO wire into default config. There's currently an issue with the stateless plugin or how we register
|
|
5267
|
+
// @ts-ignore - config coming from registerPlugin
|
|
4825
5268
|
this.mediaProperties.setMediaDirection(Object.assign(this.config.mediaSettings, mediaSettings));
|
|
4826
5269
|
// add a setup a function move the create and setup media in future
|
|
4827
5270
|
// TODO: delete old audio and video if stale
|
|
@@ -4839,7 +5282,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4839
5282
|
* @public
|
|
4840
5283
|
* @memberof Meeting
|
|
4841
5284
|
*/
|
|
4842
|
-
acknowledge(type) {
|
|
5285
|
+
public acknowledge(type: string) {
|
|
4843
5286
|
if (!type) {
|
|
4844
5287
|
return Promise.reject(new ParameterError('Type must be set to acknowledge the meeting.'));
|
|
4845
5288
|
}
|
|
@@ -4874,7 +5317,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4874
5317
|
* @public
|
|
4875
5318
|
* @memberof Meeting
|
|
4876
5319
|
*/
|
|
4877
|
-
decline(reason) {
|
|
5320
|
+
public decline(reason: string) {
|
|
4878
5321
|
return MeetingUtil.declineMeeting(this, reason).then((decline) => {
|
|
4879
5322
|
this.meetingFiniteStateMachine.decline();
|
|
4880
5323
|
|
|
@@ -4894,7 +5337,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4894
5337
|
* @public
|
|
4895
5338
|
* @memberof Meeting
|
|
4896
5339
|
*/
|
|
4897
|
-
leave(options = {}) {
|
|
5340
|
+
public leave(options: { resourceId?: string, reason?: any } = {} as any) {
|
|
4898
5341
|
Metrics.postEvent({event: eventType.LEAVE, meeting: this, data: {trigger: trigger.USER_INTERACTION, canProceed: false}});
|
|
4899
5342
|
const leaveReason = options.reason || MEETING_REMOVED_REASON.CLIENT_LEAVE_REQUEST;
|
|
4900
5343
|
|
|
@@ -4971,7 +5414,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4971
5414
|
* @public
|
|
4972
5415
|
* @memberof Meeting
|
|
4973
5416
|
*/
|
|
4974
|
-
startWhiteboardShare(channelUrl, resourceToken) {
|
|
5417
|
+
public startWhiteboardShare(channelUrl: string, resourceToken: string) {
|
|
4975
5418
|
const whiteboard = this.locusInfo.mediaShares.find((element) => element.name === 'whiteboard');
|
|
4976
5419
|
|
|
4977
5420
|
if (!channelUrl) {
|
|
@@ -4981,7 +5424,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4981
5424
|
if (whiteboard) {
|
|
4982
5425
|
Metrics.postEvent({event: eventType.WHITEBOARD_SHARE_INITIATED, meeting: this});
|
|
4983
5426
|
|
|
4984
|
-
const body = {
|
|
5427
|
+
const body: any = {
|
|
4985
5428
|
disposition: FLOOR_ACTION.GRANTED,
|
|
4986
5429
|
personUrl: this.locusInfo.self.url,
|
|
4987
5430
|
deviceUrl: this.deviceUrl,
|
|
@@ -5027,7 +5470,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5027
5470
|
* @public
|
|
5028
5471
|
* @memberof Meeting
|
|
5029
5472
|
*/
|
|
5030
|
-
stopWhiteboardShare(channelUrl) {
|
|
5473
|
+
public stopWhiteboardShare(channelUrl: string) {
|
|
5031
5474
|
const whiteboard = this.locusInfo.mediaShares.find((element) => element.name === 'whiteboard');
|
|
5032
5475
|
|
|
5033
5476
|
if (whiteboard) {
|
|
@@ -5043,6 +5486,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5043
5486
|
LoggerProxy.logger.error('Meeting:index#stopWhiteboardShare --> Error ', error);
|
|
5044
5487
|
|
|
5045
5488
|
Metrics.sendBehavioralMetric(
|
|
5489
|
+
// @ts-ignore - check if STOP_WHITEBOARD_SHARE_FAILURE exists
|
|
5046
5490
|
BEHAVIORAL_METRICS.STOP_WHITEBOARD_SHARE_FAILURE,
|
|
5047
5491
|
{
|
|
5048
5492
|
correlation_id: this.correlationId,
|
|
@@ -5063,12 +5507,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5063
5507
|
}
|
|
5064
5508
|
|
|
5065
5509
|
/**
|
|
5066
|
-
*
|
|
5510
|
+
* Sends a request to Locus to obtain the screen share floor
|
|
5067
5511
|
* @returns {Promise} see #meetingRequest.changeMeetingFloor
|
|
5068
5512
|
* @private
|
|
5069
5513
|
* @memberof Meeting
|
|
5070
5514
|
*/
|
|
5071
|
-
|
|
5515
|
+
private requestScreenShareFloor() {
|
|
5072
5516
|
const content = this.locusInfo.mediaShares.find((element) => element.name === CONTENT);
|
|
5073
5517
|
|
|
5074
5518
|
if (content && (this.shareStatus !== SHARE_STATUS.LOCAL_SHARE_ACTIVE)) {
|
|
@@ -5114,7 +5558,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5114
5558
|
*/
|
|
5115
5559
|
// Internal only, temporarily allows optional params
|
|
5116
5560
|
// eslint-disable-next-line valid-jsdoc
|
|
5117
|
-
stopShare(options = {}) {
|
|
5561
|
+
public stopShare(options = {}) {
|
|
5118
5562
|
return this.updateShare({
|
|
5119
5563
|
sendShare: false,
|
|
5120
5564
|
receiveShare: this.mediaProperties.mediaDirection.receiveShare,
|
|
@@ -5123,12 +5567,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5123
5567
|
}
|
|
5124
5568
|
|
|
5125
5569
|
/**
|
|
5126
|
-
*
|
|
5570
|
+
* Sends a request to Locus to release the screen share floor.
|
|
5127
5571
|
* @returns {Promise} see #meetingRequest.changeMeetingFloor
|
|
5128
5572
|
* @private
|
|
5129
5573
|
* @memberof Meeting
|
|
5130
5574
|
*/
|
|
5131
|
-
|
|
5575
|
+
private releaseScreenShareFloor() {
|
|
5132
5576
|
const content = this.locusInfo.mediaShares.find((element) => element.name === CONTENT);
|
|
5133
5577
|
|
|
5134
5578
|
if (content && (this.mediaProperties.mediaDirection.sendShare)) {
|
|
@@ -5150,7 +5594,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5150
5594
|
resourceUrl: this.resourceUrl
|
|
5151
5595
|
})
|
|
5152
5596
|
.catch((error) => {
|
|
5153
|
-
LoggerProxy.logger.error('Meeting:index#
|
|
5597
|
+
LoggerProxy.logger.error('Meeting:index#releaseScreenShareFloor --> Error ', error);
|
|
5154
5598
|
|
|
5155
5599
|
Metrics.sendBehavioralMetric(
|
|
5156
5600
|
BEHAVIORAL_METRICS.STOP_FLOOR_REQUEST_FAILURE,
|
|
@@ -5178,7 +5622,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5178
5622
|
* @public
|
|
5179
5623
|
* @memberof Meeting
|
|
5180
5624
|
*/
|
|
5181
|
-
startRecording() {
|
|
5625
|
+
public startRecording() {
|
|
5182
5626
|
return MeetingUtil.startRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
|
|
5183
5627
|
}
|
|
5184
5628
|
|
|
@@ -5188,7 +5632,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5188
5632
|
* @public
|
|
5189
5633
|
* @memberof Meeting
|
|
5190
5634
|
*/
|
|
5191
|
-
stopRecording() {
|
|
5635
|
+
public stopRecording() {
|
|
5192
5636
|
return MeetingUtil.stopRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
|
|
5193
5637
|
}
|
|
5194
5638
|
|
|
@@ -5198,7 +5642,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5198
5642
|
* @public
|
|
5199
5643
|
* @memberof Meeting
|
|
5200
5644
|
*/
|
|
5201
|
-
pauseRecording() {
|
|
5645
|
+
public pauseRecording() {
|
|
5202
5646
|
return MeetingUtil.pauseRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
|
|
5203
5647
|
}
|
|
5204
5648
|
|
|
@@ -5208,7 +5652,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5208
5652
|
* @public
|
|
5209
5653
|
* @memberof Meeting
|
|
5210
5654
|
*/
|
|
5211
|
-
resumeRecording() {
|
|
5655
|
+
public resumeRecording() {
|
|
5212
5656
|
return MeetingUtil.resumeRecording(this.meetingRequest, this.locusUrl, this.locusInfo);
|
|
5213
5657
|
}
|
|
5214
5658
|
|
|
@@ -5218,7 +5662,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5218
5662
|
* @public
|
|
5219
5663
|
* @memberof Meeting
|
|
5220
5664
|
*/
|
|
5221
|
-
lockMeeting() {
|
|
5665
|
+
public lockMeeting() {
|
|
5222
5666
|
return MeetingUtil.lockMeeting(this.inMeetingActions, this.meetingRequest, this.locusUrl);
|
|
5223
5667
|
}
|
|
5224
5668
|
|
|
@@ -5228,7 +5672,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5228
5672
|
* @public
|
|
5229
5673
|
* @memberof Meeting
|
|
5230
5674
|
*/
|
|
5231
|
-
unlockMeeting() {
|
|
5675
|
+
public unlockMeeting() {
|
|
5232
5676
|
return MeetingUtil.unlockMeeting(this.inMeetingActions, this.meetingRequest, this.locusUrl);
|
|
5233
5677
|
}
|
|
5234
5678
|
|
|
@@ -5239,7 +5683,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5239
5683
|
* @private
|
|
5240
5684
|
* @memberof Meeting
|
|
5241
5685
|
*/
|
|
5242
|
-
rejectWithErrorLog(message) {
|
|
5686
|
+
private rejectWithErrorLog(message: string) {
|
|
5243
5687
|
LoggerProxy.logger.error(message);
|
|
5244
5688
|
|
|
5245
5689
|
return Promise.reject(new Error(message));
|
|
@@ -5252,7 +5696,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5252
5696
|
* @public
|
|
5253
5697
|
* @memberof Meeting
|
|
5254
5698
|
*/
|
|
5255
|
-
sendDTMF(tones) {
|
|
5699
|
+
public sendDTMF(tones: string) {
|
|
5256
5700
|
if (this.locusInfo && this.locusInfo.self) {
|
|
5257
5701
|
if (this.locusInfo.self.enableDTMF) {
|
|
5258
5702
|
return this.meetingRequest
|
|
@@ -5283,7 +5727,19 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5283
5727
|
* @public
|
|
5284
5728
|
* @memberof Meeting
|
|
5285
5729
|
*/
|
|
5286
|
-
changeVideoLayout(
|
|
5730
|
+
public changeVideoLayout(
|
|
5731
|
+
layoutType?: string,
|
|
5732
|
+
renderInfo: {
|
|
5733
|
+
main: {
|
|
5734
|
+
width: number;
|
|
5735
|
+
height: number;
|
|
5736
|
+
};
|
|
5737
|
+
content: {
|
|
5738
|
+
width: number;
|
|
5739
|
+
height: number;
|
|
5740
|
+
};
|
|
5741
|
+
} = {} as any
|
|
5742
|
+
) {
|
|
5287
5743
|
const {main, content} = renderInfo;
|
|
5288
5744
|
const {mediaDirection, remoteShare, remoteVideoTrack} = this.mediaProperties;
|
|
5289
5745
|
|
|
@@ -5379,7 +5835,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5379
5835
|
* @param {String} level {LOW|MEDIUM|HIGH}
|
|
5380
5836
|
* @returns {Promise<MediaStream>} localStream
|
|
5381
5837
|
*/
|
|
5382
|
-
setLocalVideoQuality(level) {
|
|
5838
|
+
setLocalVideoQuality(level: string) {
|
|
5383
5839
|
LoggerProxy.logger.log(`Meeting:index#setLocalVideoQuality --> Setting quality to ${level}`);
|
|
5384
5840
|
|
|
5385
5841
|
if (!VIDEO_RESOLUTIONS[level]) {
|
|
@@ -5429,7 +5885,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5429
5885
|
* @param {String} level {LOW|MEDIUM|HIGH}
|
|
5430
5886
|
* @returns {Promise}
|
|
5431
5887
|
*/
|
|
5432
|
-
setRemoteQualityLevel(level) {
|
|
5888
|
+
setRemoteQualityLevel(level: string) {
|
|
5433
5889
|
LoggerProxy.logger.log(`Meeting:index#setRemoteQualityLevel --> Setting quality to ${level}`);
|
|
5434
5890
|
|
|
5435
5891
|
if (!QUALITY_LEVELS[level]) {
|
|
@@ -5459,7 +5915,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5459
5915
|
* @returns {Promise}
|
|
5460
5916
|
* @deprecated After FHD support
|
|
5461
5917
|
*/
|
|
5462
|
-
setMeetingQuality(level) {
|
|
5918
|
+
setMeetingQuality(level: string) {
|
|
5463
5919
|
LoggerProxy.logger.log(`Meeting:index#setMeetingQuality --> Setting quality to ${level}`);
|
|
5464
5920
|
|
|
5465
5921
|
if (!QUALITY_LEVELS[level]) {
|
|
@@ -5514,6 +5970,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5514
5970
|
}
|
|
5515
5971
|
|
|
5516
5972
|
/**
|
|
5973
|
+
*
|
|
5974
|
+
* NOTE: this method can only be used with transcoded meetings, for multistream use publishTrack()
|
|
5975
|
+
*
|
|
5517
5976
|
* @param {Object} options parameter
|
|
5518
5977
|
* @param {Boolean} options.sendAudio send audio from the display share
|
|
5519
5978
|
* @param {Boolean} options.sendShare send video from the display share
|
|
@@ -5523,7 +5982,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5523
5982
|
* @param {Boolean} options.sharePreferences.highFrameRate if shareConstraints isn't provided, set default values based off of this boolean
|
|
5524
5983
|
* @returns {Promise}
|
|
5525
5984
|
*/
|
|
5526
|
-
shareScreen(
|
|
5985
|
+
shareScreen(
|
|
5986
|
+
options: {
|
|
5987
|
+
sendAudio: boolean;
|
|
5988
|
+
sendShare: boolean;
|
|
5989
|
+
sharePreferences: { shareConstraints: MediaTrackConstraints };
|
|
5990
|
+
} = {} as any
|
|
5991
|
+
) {
|
|
5527
5992
|
LoggerProxy.logger.log('Meeting:index#shareScreen --> Getting local share');
|
|
5528
5993
|
|
|
5529
5994
|
const shareConstraints = {
|
|
@@ -5532,6 +5997,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5532
5997
|
...options
|
|
5533
5998
|
};
|
|
5534
5999
|
|
|
6000
|
+
// @ts-ignore - config coming from registerPlugin
|
|
5535
6001
|
return Media.getDisplayMedia(shareConstraints, this.config)
|
|
5536
6002
|
.then((shareStream) => this.updateShare({
|
|
5537
6003
|
sendShare: true,
|
|
@@ -5569,7 +6035,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5569
6035
|
* @param {MediaStream} localShare
|
|
5570
6036
|
* @returns {undefined}
|
|
5571
6037
|
*/
|
|
5572
|
-
handleShareTrackEnded(localShare) {
|
|
6038
|
+
private handleShareTrackEnded(localShare: MediaStream) {
|
|
5573
6039
|
if (this.wirelessShare) {
|
|
5574
6040
|
this.leave({reason: MEETING_REMOVED_REASON.USER_ENDED_SHARE_STREAMS});
|
|
5575
6041
|
}
|
|
@@ -5609,7 +6075,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5609
6075
|
* @private
|
|
5610
6076
|
* @memberof Meeting
|
|
5611
6077
|
*/
|
|
5612
|
-
sendNetworkQualityEvent(res) {
|
|
6078
|
+
private sendNetworkQualityEvent(res: any) {
|
|
5613
6079
|
Trigger.trigger(
|
|
5614
6080
|
this,
|
|
5615
6081
|
{
|
|
@@ -5631,7 +6097,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5631
6097
|
* @private
|
|
5632
6098
|
* @returns {undefined}
|
|
5633
6099
|
*/
|
|
5634
|
-
handleMediaLogging({audioTrack, videoTrack}) {
|
|
6100
|
+
private handleMediaLogging({ audioTrack, videoTrack }: any) {
|
|
5635
6101
|
MeetingUtil.handleVideoLogging(videoTrack);
|
|
5636
6102
|
MeetingUtil.handleAudioLogging(audioTrack);
|
|
5637
6103
|
}
|
|
@@ -5640,7 +6106,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5640
6106
|
* @param {string} typeMedia 'audio' or 'video'
|
|
5641
6107
|
* @returns {undefined}
|
|
5642
6108
|
*/
|
|
5643
|
-
setStartSetupDelay(typeMedia) {
|
|
6109
|
+
setStartSetupDelay(typeMedia: string) {
|
|
5644
6110
|
this[`startSetupDelay${typeMedia}`] = performance.now();
|
|
5645
6111
|
this[`endSetupDelay${typeMedia}`] = undefined;
|
|
5646
6112
|
}
|
|
@@ -5649,7 +6115,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5649
6115
|
* @param {string} typeMedia 'audio' or 'video'
|
|
5650
6116
|
* @returns {undefined}
|
|
5651
6117
|
*/
|
|
5652
|
-
setEndSetupDelay(typeMedia) {
|
|
6118
|
+
setEndSetupDelay(typeMedia: string) {
|
|
5653
6119
|
this[`endSetupDelay${typeMedia}`] = performance.now();
|
|
5654
6120
|
}
|
|
5655
6121
|
|
|
@@ -5657,7 +6123,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5657
6123
|
* @param {string} typeMedia 'audio' or 'video'
|
|
5658
6124
|
* @returns {string} duration between start and end of setup
|
|
5659
6125
|
*/
|
|
5660
|
-
getSetupDelayDuration(typeMedia) {
|
|
6126
|
+
getSetupDelayDuration(typeMedia: string) {
|
|
5661
6127
|
const start = this[`startSetupDelay${typeMedia}`];
|
|
5662
6128
|
const end = this[`endSetupDelay${typeMedia}`];
|
|
5663
6129
|
|
|
@@ -5668,7 +6134,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5668
6134
|
* @param {string} typeMedia 'audio' or 'video'
|
|
5669
6135
|
* @returns {undefined}
|
|
5670
6136
|
*/
|
|
5671
|
-
setStartSendingMediaDelay(typeMedia) {
|
|
6137
|
+
setStartSendingMediaDelay(typeMedia: string) {
|
|
5672
6138
|
this[`startSendingMediaDelay${typeMedia}`] = performance.now();
|
|
5673
6139
|
this[`endSendingMediaDelay${typeMedia}`] = undefined;
|
|
5674
6140
|
}
|
|
@@ -5677,7 +6143,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5677
6143
|
* @param {string} typeMedia 'audio' or 'video'
|
|
5678
6144
|
* @returns {undefined}
|
|
5679
6145
|
*/
|
|
5680
|
-
setEndSendingMediaDelay(typeMedia) {
|
|
6146
|
+
setEndSendingMediaDelay(typeMedia: string) {
|
|
5681
6147
|
this[`endSendingMediaDelay${typeMedia}`] = performance.now();
|
|
5682
6148
|
}
|
|
5683
6149
|
|
|
@@ -5685,7 +6151,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5685
6151
|
* @param {string} typeMedia 'audio' or 'video'
|
|
5686
6152
|
* @returns {string} duration between join response and first media tx
|
|
5687
6153
|
*/
|
|
5688
|
-
getSendingMediaDelayDuration(typeMedia) {
|
|
6154
|
+
getSendingMediaDelayDuration(typeMedia: string) {
|
|
5689
6155
|
const start = this[`startSendingMediaDelay${typeMedia}`];
|
|
5690
6156
|
const end = this[`endSendingMediaDelay${typeMedia}`];
|
|
5691
6157
|
|
|
@@ -5696,7 +6162,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5696
6162
|
*
|
|
5697
6163
|
* @returns {undefined}
|
|
5698
6164
|
*/
|
|
5699
|
-
|
|
6165
|
+
setStartLocalSDPGenRemoteSDPRecvDelay() {
|
|
5700
6166
|
if (!this.startLocalSDPGenRemoteSDPRecvDelay) {
|
|
5701
6167
|
this.startLocalSDPGenRemoteSDPRecvDelay = performance.now();
|
|
5702
6168
|
this.endLocalSDPGenRemoteSDPRecvDelay = undefined;
|
|
@@ -5822,7 +6288,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5822
6288
|
* @public
|
|
5823
6289
|
* @memberof Meeting
|
|
5824
6290
|
*/
|
|
5825
|
-
endMeetingForAll() {
|
|
6291
|
+
public endMeetingForAll() {
|
|
5826
6292
|
Metrics.postEvent({event: eventType.LEAVE, meeting: this, data: {trigger: trigger.USER_INTERACTION, canProceed: false}});
|
|
5827
6293
|
|
|
5828
6294
|
LoggerProxy.logger.log('Meeting:index#endMeetingForAll --> End meeting for All');
|
|
@@ -5907,7 +6373,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5907
6373
|
* @public
|
|
5908
6374
|
* @memberof Meeting
|
|
5909
6375
|
*/
|
|
5910
|
-
isBnrEnabled() {
|
|
6376
|
+
public isBnrEnabled() {
|
|
5911
6377
|
return this.effects && this.effects.isBnrEnabled();
|
|
5912
6378
|
}
|
|
5913
6379
|
|
|
@@ -5918,7 +6384,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5918
6384
|
* @param {MedaiStreamTrack} audioTrack from updateAudio
|
|
5919
6385
|
* @memberof Meeting
|
|
5920
6386
|
*/
|
|
5921
|
-
async internal_enableBNR(audioTrack) {
|
|
6387
|
+
private async internal_enableBNR(audioTrack: any) {
|
|
5922
6388
|
try {
|
|
5923
6389
|
LoggerProxy.logger.info('Meeting:index#internal_enableBNR. Internal enable BNR called');
|
|
5924
6390
|
const bnrAudioTrack = await WebRTCMedia.Effects.BNR.enableBNR(audioTrack);
|
|
@@ -5939,7 +6405,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5939
6405
|
* @public
|
|
5940
6406
|
* @memberof Meeting
|
|
5941
6407
|
*/
|
|
5942
|
-
enableBNR() {
|
|
6408
|
+
public enableBNR() {
|
|
5943
6409
|
if (typeof this.mediaProperties === 'undefined' || typeof this.mediaProperties.audioTrack === 'undefined') {
|
|
5944
6410
|
return Promise.reject(new Error("Meeting doesn't have an audioTrack attached"));
|
|
5945
6411
|
}
|
|
@@ -5974,7 +6440,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5974
6440
|
* @public
|
|
5975
6441
|
* @memberof Meeting
|
|
5976
6442
|
*/
|
|
5977
|
-
disableBNR() {
|
|
6443
|
+
public disableBNR() {
|
|
5978
6444
|
if (typeof this.mediaProperties === 'undefined' || typeof this.mediaProperties.audioTrack === 'undefined') {
|
|
5979
6445
|
return Promise.reject(new Error("Meeting doesn't have an audioTrack attached"));
|
|
5980
6446
|
}
|