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