@webex/plugin-meetings 3.7.0-next.9 → 3.7.0-wxcc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/annotation/index.js +17 -0
- package/dist/annotation/index.js.map +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/common/errors/join-forbidden-error.js +52 -0
- package/dist/common/errors/join-forbidden-error.js.map +1 -0
- package/dist/common/errors/{webinar-registration-error.js → join-webinar-error.js} +12 -12
- package/dist/common/errors/join-webinar-error.js.map +1 -0
- package/dist/common/errors/multistream-not-supported-error.js +53 -0
- package/dist/common/errors/multistream-not-supported-error.js.map +1 -0
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +46 -5
- package/dist/constants.js.map +1 -1
- package/dist/index.js +16 -11
- package/dist/index.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +14 -3
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/selfUtils.js +30 -17
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +2 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +960 -832
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +9 -0
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/request.js +30 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/util.js +16 -16
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +96 -33
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +1 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.js +103 -54
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +2 -0
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/util.js +1 -1
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +39 -28
- package/dist/member/util.js.map +1 -1
- package/dist/metrics/constants.js +3 -2
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/remoteMedia.js +30 -15
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +24 -0
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/roap/index.js +10 -8
- package/dist/roap/index.js.map +1 -1
- package/dist/types/annotation/index.d.ts +5 -0
- package/dist/types/common/errors/join-forbidden-error.d.ts +15 -0
- package/dist/types/common/errors/{webinar-registration-error.d.ts → join-webinar-error.d.ts} +2 -2
- package/dist/types/common/errors/multistream-not-supported-error.d.ts +17 -0
- package/dist/types/constants.d.ts +38 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/locus-info/index.d.ts +2 -1
- package/dist/types/meeting/in-meeting-actions.d.ts +2 -0
- package/dist/types/meeting/index.d.ts +19 -12
- package/dist/types/meeting/locusMediaRequest.d.ts +4 -0
- package/dist/types/meeting/request.d.ts +12 -1
- package/dist/types/meeting/request.type.d.ts +6 -0
- package/dist/types/meeting/util.d.ts +1 -1
- package/dist/types/meeting-info/meeting-info-v2.d.ts +27 -4
- package/dist/types/meetings/index.d.ts +16 -1
- package/dist/types/meetings/meetings.types.d.ts +8 -0
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/types.d.ts +7 -0
- package/dist/types/metrics/constants.d.ts +2 -1
- package/dist/types/multistream/sendSlotManager.d.ts +8 -1
- package/dist/webinar/index.js +354 -3
- package/dist/webinar/index.js.map +1 -1
- package/package.json +23 -22
- package/src/annotation/index.ts +16 -0
- package/src/common/errors/join-forbidden-error.ts +26 -0
- package/src/common/errors/join-webinar-error.ts +24 -0
- package/src/common/errors/multistream-not-supported-error.ts +30 -0
- package/src/config.ts +1 -1
- package/src/constants.ts +43 -3
- package/src/index.ts +5 -3
- package/src/locus-info/index.ts +20 -3
- package/src/locus-info/selfUtils.ts +19 -6
- package/src/meeting/in-meeting-actions.ts +4 -0
- package/src/meeting/index.ts +259 -80
- package/src/meeting/locusMediaRequest.ts +7 -0
- package/src/meeting/request.ts +26 -1
- package/src/meeting/request.type.ts +7 -0
- package/src/meeting/util.ts +8 -10
- package/src/meeting-info/meeting-info-v2.ts +74 -11
- package/src/meeting-info/utilv2.ts +3 -1
- package/src/meetings/index.ts +73 -20
- package/src/meetings/meetings.types.ts +10 -0
- package/src/meetings/util.ts +2 -1
- package/src/member/index.ts +9 -0
- package/src/member/types.ts +8 -0
- package/src/member/util.ts +34 -24
- package/src/metrics/constants.ts +2 -1
- package/src/multistream/remoteMedia.ts +28 -15
- package/src/multistream/sendSlotManager.ts +31 -0
- package/src/roap/index.ts +10 -8
- package/src/webinar/index.ts +197 -3
- package/test/unit/spec/annotation/index.ts +46 -1
- package/test/unit/spec/locus-info/index.js +292 -60
- package/test/unit/spec/locus-info/selfConstant.js +7 -0
- package/test/unit/spec/locus-info/selfUtils.js +91 -1
- package/test/unit/spec/meeting/in-meeting-actions.ts +2 -0
- package/test/unit/spec/meeting/index.js +722 -105
- package/test/unit/spec/meeting/utils.js +22 -19
- package/test/unit/spec/meeting-info/meetinginfov2.js +46 -4
- package/test/unit/spec/meeting-info/utilv2.js +17 -0
- package/test/unit/spec/meetings/index.js +150 -13
- package/test/unit/spec/meetings/utils.js +10 -0
- package/test/unit/spec/member/util.js +52 -11
- package/test/unit/spec/multistream/remoteMedia.ts +11 -7
- package/test/unit/spec/roap/index.ts +47 -0
- package/test/unit/spec/webinar/index.ts +457 -0
- package/dist/common/errors/webinar-registration-error.js.map +0 -1
- package/src/common/errors/webinar-registration-error.ts +0 -27
|
@@ -19,6 +19,14 @@ export type RemoteVideoResolution =
|
|
|
19
19
|
| 'large' // 1080p or less
|
|
20
20
|
| 'best'; // highest possible resolution
|
|
21
21
|
|
|
22
|
+
const MAX_FS_VALUES = {
|
|
23
|
+
'90p': 60,
|
|
24
|
+
'180p': 240,
|
|
25
|
+
'360p': 920,
|
|
26
|
+
'720p': 3600,
|
|
27
|
+
'1080p': 8192,
|
|
28
|
+
};
|
|
29
|
+
|
|
22
30
|
/**
|
|
23
31
|
* Converts pane size into h264 maxFs
|
|
24
32
|
* @param {PaneSize} paneSize
|
|
@@ -29,28 +37,28 @@ export function getMaxFs(paneSize: RemoteVideoResolution): number {
|
|
|
29
37
|
|
|
30
38
|
switch (paneSize) {
|
|
31
39
|
case 'thumbnail':
|
|
32
|
-
maxFs =
|
|
40
|
+
maxFs = MAX_FS_VALUES['90p'];
|
|
33
41
|
break;
|
|
34
42
|
case 'very small':
|
|
35
|
-
maxFs =
|
|
43
|
+
maxFs = MAX_FS_VALUES['180p'];
|
|
36
44
|
break;
|
|
37
45
|
case 'small':
|
|
38
|
-
maxFs =
|
|
46
|
+
maxFs = MAX_FS_VALUES['360p'];
|
|
39
47
|
break;
|
|
40
48
|
case 'medium':
|
|
41
|
-
maxFs =
|
|
49
|
+
maxFs = MAX_FS_VALUES['720p'];
|
|
42
50
|
break;
|
|
43
51
|
case 'large':
|
|
44
|
-
maxFs =
|
|
52
|
+
maxFs = MAX_FS_VALUES['1080p'];
|
|
45
53
|
break;
|
|
46
54
|
case 'best':
|
|
47
|
-
maxFs =
|
|
55
|
+
maxFs = MAX_FS_VALUES['1080p']; // for now 'best' is 1080p, so same as 'large'
|
|
48
56
|
break;
|
|
49
57
|
default:
|
|
50
58
|
LoggerProxy.logger.warn(
|
|
51
59
|
`RemoteMedia#getMaxFs --> unsupported paneSize: ${paneSize}, using "medium" instead`
|
|
52
60
|
);
|
|
53
|
-
maxFs =
|
|
61
|
+
maxFs = MAX_FS_VALUES['720p'];
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
return maxFs;
|
|
@@ -117,16 +125,21 @@ export class RemoteMedia extends EventsScope {
|
|
|
117
125
|
return;
|
|
118
126
|
}
|
|
119
127
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
// we switch to the next resolution level when the height is 10% more than the current resolution height
|
|
129
|
+
// except for 1080p - we switch to it immediately when the height is more than 720p
|
|
130
|
+
const threshold = 1.1;
|
|
131
|
+
const getThresholdHeight = (h: number) => Math.round(h * threshold);
|
|
132
|
+
|
|
133
|
+
if (height < getThresholdHeight(90)) {
|
|
134
|
+
fs = MAX_FS_VALUES['90p'];
|
|
135
|
+
} else if (height < getThresholdHeight(180)) {
|
|
136
|
+
fs = MAX_FS_VALUES['180p'];
|
|
137
|
+
} else if (height < getThresholdHeight(360)) {
|
|
138
|
+
fs = MAX_FS_VALUES['360p'];
|
|
126
139
|
} else if (height <= 720) {
|
|
127
|
-
fs =
|
|
140
|
+
fs = MAX_FS_VALUES['720p'];
|
|
128
141
|
} else {
|
|
129
|
-
fs =
|
|
142
|
+
fs = MAX_FS_VALUES['1080p'];
|
|
130
143
|
}
|
|
131
144
|
|
|
132
145
|
this.receiveSlot?.setMaxFs(fs);
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
LocalStream,
|
|
5
5
|
MultistreamRoapMediaConnection,
|
|
6
6
|
NamedMediaGroup,
|
|
7
|
+
StreamState,
|
|
7
8
|
} from '@webex/internal-media-core';
|
|
8
9
|
|
|
9
10
|
export default class SendSlotManager {
|
|
@@ -83,6 +84,36 @@ export default class SendSlotManager {
|
|
|
83
84
|
);
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Sets the source state override for the given media type.
|
|
89
|
+
* @param {MediaType} mediaType - The type of media (must be MediaType.VideoMain to apply source state changes).
|
|
90
|
+
* @param {StreamState | null} state - The state to set or null to clear the override value.
|
|
91
|
+
* @returns {void}
|
|
92
|
+
*/
|
|
93
|
+
public setSourceStateOverride(mediaType: MediaType, state: StreamState | null) {
|
|
94
|
+
if (mediaType !== MediaType.VideoMain) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`sendSlotManager cannot set source state override which media type is ${mediaType}`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const slot = this.slots.get(mediaType);
|
|
101
|
+
|
|
102
|
+
if (!slot) {
|
|
103
|
+
throw new Error(`Slot for ${mediaType} does not exist`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (state) {
|
|
107
|
+
slot.setSourceStateOverride(state);
|
|
108
|
+
} else {
|
|
109
|
+
slot.clearSourceStateOverride();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.LoggerProxy.logger.info(
|
|
113
|
+
`SendSlotsManager->setSourceStateOverride#set source state override for ${mediaType} to ${state}`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
86
117
|
/**
|
|
87
118
|
* This method publishes the given stream to the sendSlot for the given mediaType
|
|
88
119
|
* @param {MediaType} mediaType MediaType of the sendSlot to which a stream needs to be published (AUDIO_MAIN/VIDEO_MAIN/AUDIO_SLIDES/VIDEO_SLIDES)
|
package/src/roap/index.ts
CHANGED
|
@@ -231,14 +231,16 @@ export default class Roap extends StatelessWebexPlugin {
|
|
|
231
231
|
headers,
|
|
232
232
|
} = remoteSdp.roapMessage;
|
|
233
233
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
234
|
+
if (messageType === ROAP.ROAP_TYPES.ANSWER) {
|
|
235
|
+
roapAnswer = {
|
|
236
|
+
seq: answerSeq,
|
|
237
|
+
messageType,
|
|
238
|
+
sdp: sdps[0],
|
|
239
|
+
errorType,
|
|
240
|
+
errorCause,
|
|
241
|
+
headers,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
242
244
|
}
|
|
243
245
|
}
|
|
244
246
|
|
package/src/webinar/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Copyright (c) 2015-2023 Cisco Systems, Inc. See LICENSE file.
|
|
3
3
|
*/
|
|
4
|
-
import {WebexPlugin} from '@webex/webex-core';
|
|
4
|
+
import {WebexPlugin, config} from '@webex/webex-core';
|
|
5
|
+
import uuid from 'uuid';
|
|
5
6
|
import {get} from 'lodash';
|
|
6
|
-
import {HTTP_VERBS, MEETINGS, SELF_ROLES} from '../constants';
|
|
7
|
+
import {_ID_, HEADERS, HTTP_VERBS, MEETINGS, SELF_ROLES, SHARE_STATUS} from '../constants';
|
|
7
8
|
|
|
8
9
|
import WebinarCollection from './collection';
|
|
9
10
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
@@ -24,6 +25,7 @@ const Webinar = WebexPlugin.extend({
|
|
|
24
25
|
selfIsPanelist: 'boolean', // self is panelist
|
|
25
26
|
selfIsAttendee: 'boolean', // self is attendee
|
|
26
27
|
practiceSessionEnabled: 'boolean', // practice session enabled
|
|
28
|
+
meetingId: 'string',
|
|
27
29
|
},
|
|
28
30
|
|
|
29
31
|
/**
|
|
@@ -67,14 +69,47 @@ const Webinar = WebexPlugin.extend({
|
|
|
67
69
|
const isPromoted =
|
|
68
70
|
oldRoles.includes(SELF_ROLES.ATTENDEE) && newRoles.includes(SELF_ROLES.PANELIST);
|
|
69
71
|
const isDemoted =
|
|
70
|
-
oldRoles.includes(SELF_ROLES.PANELIST) && newRoles.includes(SELF_ROLES.ATTENDEE)
|
|
72
|
+
(oldRoles.includes(SELF_ROLES.PANELIST) && newRoles.includes(SELF_ROLES.ATTENDEE)) ||
|
|
73
|
+
(!oldRoles.includes(SELF_ROLES.ATTENDEE) && newRoles.includes(SELF_ROLES.ATTENDEE)); // for attendee just join meeting case
|
|
71
74
|
this.set('selfIsPanelist', newRoles.includes(SELF_ROLES.PANELIST));
|
|
72
75
|
this.set('selfIsAttendee', newRoles.includes(SELF_ROLES.ATTENDEE));
|
|
73
76
|
this.updateCanManageWebcast(newRoles.includes(SELF_ROLES.MODERATOR));
|
|
77
|
+
this.updateStatusByRole({isPromoted, isDemoted});
|
|
74
78
|
|
|
75
79
|
return {isPromoted, isDemoted};
|
|
76
80
|
},
|
|
77
81
|
|
|
82
|
+
/**
|
|
83
|
+
* should join practice session data channel or not
|
|
84
|
+
* @param {Object} {isPromoted: boolean, isDemoted: boolean}} Role transition states
|
|
85
|
+
* @returns {void}
|
|
86
|
+
*/
|
|
87
|
+
updateStatusByRole({isPromoted, isDemoted}) {
|
|
88
|
+
const meeting = this.webex.meetings.getMeetingByType(_ID_, this.meetingId);
|
|
89
|
+
|
|
90
|
+
if (
|
|
91
|
+
(isDemoted && meeting?.shareStatus === SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE) ||
|
|
92
|
+
isPromoted
|
|
93
|
+
) {
|
|
94
|
+
// attendees in webinar should subscribe streaming for whiteboard sharing
|
|
95
|
+
// while panelist still need subscribe native mode so trigger force update here
|
|
96
|
+
meeting?.locusInfo?.updateMediaShares(meeting?.locusInfo?.mediaShares, true);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (this.practiceSessionEnabled) {
|
|
100
|
+
// may need change data channel in practice session
|
|
101
|
+
meeting?.updateLLMConnection();
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* should join practice session data channel or not
|
|
107
|
+
* @returns {boolean}
|
|
108
|
+
*/
|
|
109
|
+
isJoinPracticeSessionDataChannel() {
|
|
110
|
+
return this.selfIsPanelist && this.practiceSessionEnabled;
|
|
111
|
+
},
|
|
112
|
+
|
|
78
113
|
/**
|
|
79
114
|
* start or stop practice session for webinar
|
|
80
115
|
* @param {boolean} enabled
|
|
@@ -103,6 +138,165 @@ const Webinar = WebexPlugin.extend({
|
|
|
103
138
|
updatePracticeSessionStatus(payload) {
|
|
104
139
|
this.set('practiceSessionEnabled', payload.enabled);
|
|
105
140
|
},
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* start webcast mode for webinar
|
|
144
|
+
* @param {object} meeting
|
|
145
|
+
* @param {object} layout
|
|
146
|
+
* @returns {Promise}
|
|
147
|
+
*/
|
|
148
|
+
async startWebcast(meeting, layout) {
|
|
149
|
+
if (!meeting) {
|
|
150
|
+
LoggerProxy.logger.error(
|
|
151
|
+
`Meeting:webinar#startWebcast failed --> meeting parameter : ${meeting}`
|
|
152
|
+
);
|
|
153
|
+
throw new Error('Meeting parameter does not meet expectations');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return this.request({
|
|
157
|
+
method: HTTP_VERBS.PUT,
|
|
158
|
+
uri: `${this.webcastInstanceUrl}/streaming`,
|
|
159
|
+
headers: {
|
|
160
|
+
authorization: await this.webex.credentials.getUserToken(),
|
|
161
|
+
trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,
|
|
162
|
+
[HEADERS.CONTENT_TYPE]: HEADERS.CONTENT_TYPE_VALUE.APPLICATION_JSON,
|
|
163
|
+
},
|
|
164
|
+
body: {
|
|
165
|
+
action: 'start',
|
|
166
|
+
meetingInfo: {
|
|
167
|
+
locusId: meeting.locusId,
|
|
168
|
+
correlationId: meeting.correlationId,
|
|
169
|
+
},
|
|
170
|
+
layout,
|
|
171
|
+
},
|
|
172
|
+
}).catch((error) => {
|
|
173
|
+
LoggerProxy.logger.error('Meeting:webinar#startWebcast failed', error);
|
|
174
|
+
throw error;
|
|
175
|
+
});
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* stop webcast mode for webinar
|
|
180
|
+
* @returns {Promise}
|
|
181
|
+
*/
|
|
182
|
+
async stopWebcast() {
|
|
183
|
+
return this.request({
|
|
184
|
+
method: HTTP_VERBS.PUT,
|
|
185
|
+
uri: `${this.webcastInstanceUrl}/streaming`,
|
|
186
|
+
headers: {
|
|
187
|
+
authorization: await this.webex.credentials.getUserToken(),
|
|
188
|
+
trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,
|
|
189
|
+
[HEADERS.CONTENT_TYPE]: HEADERS.CONTENT_TYPE_VALUE.APPLICATION_JSON,
|
|
190
|
+
},
|
|
191
|
+
body: {
|
|
192
|
+
action: 'stop',
|
|
193
|
+
},
|
|
194
|
+
}).catch((error) => {
|
|
195
|
+
LoggerProxy.logger.error('Meeting:webinar#stopWebcast failed', error);
|
|
196
|
+
throw error;
|
|
197
|
+
});
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* query webcast layout for webinar
|
|
202
|
+
* @returns {Promise}
|
|
203
|
+
*/
|
|
204
|
+
async queryWebcastLayout() {
|
|
205
|
+
return this.request({
|
|
206
|
+
method: HTTP_VERBS.GET,
|
|
207
|
+
uri: `${this.webcastInstanceUrl}/layout`,
|
|
208
|
+
headers: {
|
|
209
|
+
authorization: await this.webex.credentials.getUserToken(),
|
|
210
|
+
trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,
|
|
211
|
+
},
|
|
212
|
+
}).catch((error) => {
|
|
213
|
+
LoggerProxy.logger.error('Meeting:webinar#queryWebcastLayout failed', error);
|
|
214
|
+
throw error;
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* update webcast layout for webinar
|
|
220
|
+
* @param {object} layout
|
|
221
|
+
* @returns {Promise}
|
|
222
|
+
*/
|
|
223
|
+
async updateWebcastLayout(layout) {
|
|
224
|
+
return this.request({
|
|
225
|
+
method: HTTP_VERBS.PUT,
|
|
226
|
+
uri: `${this.webcastInstanceUrl}/layout`,
|
|
227
|
+
headers: {
|
|
228
|
+
authorization: await this.webex.credentials.getUserToken(),
|
|
229
|
+
trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,
|
|
230
|
+
[HEADERS.CONTENT_TYPE]: HEADERS.CONTENT_TYPE_VALUE.APPLICATION_JSON,
|
|
231
|
+
},
|
|
232
|
+
body: {
|
|
233
|
+
videoLayout: layout.videoLayout,
|
|
234
|
+
contentLayout: layout.contentLayout,
|
|
235
|
+
syncStageLayout: layout.syncStageLayout,
|
|
236
|
+
syncStageInMeeting: layout.syncStageInMeeting,
|
|
237
|
+
},
|
|
238
|
+
}).catch((error) => {
|
|
239
|
+
LoggerProxy.logger.error('Meeting:webinar#updateWebcastLayout failed', error);
|
|
240
|
+
throw error;
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* view all webcast attendees
|
|
246
|
+
* @param {string} queryString
|
|
247
|
+
* @returns {Promise}
|
|
248
|
+
*/
|
|
249
|
+
async viewAllWebcastAttendees() {
|
|
250
|
+
return this.request({
|
|
251
|
+
method: HTTP_VERBS.GET,
|
|
252
|
+
uri: `${this.webcastInstanceUrl}/attendees`,
|
|
253
|
+
headers: {
|
|
254
|
+
authorization: await this.webex.credentials.getUserToken(),
|
|
255
|
+
trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,
|
|
256
|
+
},
|
|
257
|
+
}).catch((error) => {
|
|
258
|
+
LoggerProxy.logger.error('Meeting:webinar#viewAllWebcastAttendees failed', error);
|
|
259
|
+
throw error;
|
|
260
|
+
});
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* search webcast attendees by query string
|
|
265
|
+
* @param {string} queryString
|
|
266
|
+
* @returns {Promise}
|
|
267
|
+
*/
|
|
268
|
+
async searchWebcastAttendees(queryString = '') {
|
|
269
|
+
return this.request({
|
|
270
|
+
method: HTTP_VERBS.GET,
|
|
271
|
+
uri: `${this.webcastInstanceUrl}/attendees?keyword=${encodeURIComponent(queryString)}`,
|
|
272
|
+
headers: {
|
|
273
|
+
authorization: await this.webex.credentials.getUserToken(),
|
|
274
|
+
trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,
|
|
275
|
+
},
|
|
276
|
+
}).catch((error) => {
|
|
277
|
+
LoggerProxy.logger.error('Meeting:webinar#searchWebcastAttendees failed', error);
|
|
278
|
+
throw error;
|
|
279
|
+
});
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* expel webcast attendee by participantId
|
|
284
|
+
* @param {string} participantId
|
|
285
|
+
* @returns {Promise}
|
|
286
|
+
*/
|
|
287
|
+
async expelWebcastAttendee(participantId) {
|
|
288
|
+
return this.request({
|
|
289
|
+
method: HTTP_VERBS.DELETE,
|
|
290
|
+
uri: `${this.webcastInstanceUrl}/attendees/${participantId}`,
|
|
291
|
+
headers: {
|
|
292
|
+
authorization: await this.webex.credentials.getUserToken(),
|
|
293
|
+
trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,
|
|
294
|
+
},
|
|
295
|
+
}).catch((error) => {
|
|
296
|
+
LoggerProxy.logger.error('Meeting:webinar#expelWebcastAttendee failed', error);
|
|
297
|
+
throw error;
|
|
298
|
+
});
|
|
299
|
+
},
|
|
106
300
|
});
|
|
107
301
|
|
|
108
302
|
export default Webinar;
|
|
@@ -413,6 +413,51 @@ describe('live-annotation', () => {
|
|
|
413
413
|
});
|
|
414
414
|
});
|
|
415
415
|
});
|
|
416
|
-
});
|
|
417
416
|
|
|
417
|
+
describe('#deregisterEvents', () => {
|
|
418
|
+
let llmOn;
|
|
419
|
+
let llmOff;
|
|
420
|
+
let mercuryOn;
|
|
421
|
+
let mercuryOff;
|
|
422
|
+
|
|
423
|
+
beforeEach(() => {
|
|
424
|
+
llmOn = sinon.spy(webex.internal.llm, 'on');
|
|
425
|
+
llmOff = sinon.spy(webex.internal.llm, 'off');
|
|
426
|
+
mercuryOn = sinon.spy(webex.internal.mercury, 'on');
|
|
427
|
+
mercuryOff = sinon.spy(webex.internal.mercury, 'off');
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('cleans up events', () => {
|
|
431
|
+
annotationService.locusUrlUpdate(locusUrl);
|
|
432
|
+
assert.calledWith(
|
|
433
|
+
mercuryOn,
|
|
434
|
+
'event:locus.approval_request',
|
|
435
|
+
annotationService.eventCommandProcessor,
|
|
436
|
+
annotationService
|
|
437
|
+
);
|
|
438
|
+
assert.calledWith(
|
|
439
|
+
llmOn,
|
|
440
|
+
'event:relay.event',
|
|
441
|
+
annotationService.eventDataProcessor,
|
|
442
|
+
annotationService
|
|
443
|
+
);
|
|
444
|
+
assert.match(annotationService.hasSubscribedToEvents, true);
|
|
445
|
+
|
|
446
|
+
annotationService.deregisterEvents();
|
|
447
|
+
assert.calledWith(llmOff, 'event:relay.event', annotationService.eventDataProcessor);
|
|
448
|
+
assert.calledWith(
|
|
449
|
+
mercuryOff,
|
|
450
|
+
'event:locus.approval_request',
|
|
451
|
+
annotationService.eventCommandProcessor
|
|
452
|
+
);
|
|
453
|
+
assert.match(annotationService.hasSubscribedToEvents, false);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it('does not call llm off if events have not been registered', () => {
|
|
457
|
+
annotationService.deregisterEvents();
|
|
458
|
+
assert.notCalled(llmOff);
|
|
459
|
+
assert.notCalled(mercuryOff);
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
});
|
|
418
463
|
});
|