@webex/plugin-meetings 2.37.2 → 2.38.0
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/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/locus-info/index.js +24 -0
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +1 -0
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.js +405 -352
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +0 -27
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +0 -56
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +2 -0
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +27 -17
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/request.js +14 -12
- package/dist/meetings/request.js.map +1 -1
- package/dist/member/util.js +3 -1
- package/dist/member/util.js.map +1 -1
- package/dist/members/request.js +3 -1
- package/dist/members/request.js.map +1 -1
- package/dist/reachability/index.js +4 -4
- package/dist/reachability/index.js.map +1 -1
- package/dist/reactions/reactions.type.js +1 -0
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/recording-controller/enums.js +17 -0
- package/dist/recording-controller/enums.js.map +1 -0
- package/dist/recording-controller/index.js +343 -0
- package/dist/recording-controller/index.js.map +1 -0
- package/dist/recording-controller/util.js +63 -0
- package/dist/recording-controller/util.js.map +1 -0
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +18 -6
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/package.json +23 -18
- package/src/config.ts +1 -1
- package/src/constants.ts +1 -0
- package/src/locus-info/index.ts +24 -0
- package/src/locus-info/parser.ts +1 -0
- package/src/media/properties.ts +1 -1
- package/src/meeting/index.ts +121 -70
- package/src/meeting/request.ts +0 -31
- package/src/meeting/util.ts +0 -60
- package/src/meeting-info/meeting-info-v2.ts +2 -0
- package/src/meetings/index.ts +8 -3
- package/src/meetings/request.ts +1 -1
- package/src/member/util.ts +2 -1
- package/src/members/request.ts +1 -0
- package/src/reachability/index.ts +2 -1
- package/src/reactions/reactions.type.ts +2 -1
- package/src/recording-controller/enums.ts +8 -0
- package/src/recording-controller/index.ts +315 -0
- package/src/recording-controller/util.ts +58 -0
- package/src/roap/turnDiscovery.ts +1 -1
- package/src/statsAnalyzer/mqaUtil.ts +6 -0
- package/test/integration/spec/journey.js +1 -1
- package/test/integration/spec/space-meeting.js +1 -1
- package/test/integration/spec/transcription.js +1 -1
- package/test/unit/spec/meeting/index.js +33 -6
- package/test/unit/spec/meeting/utils.js +0 -127
- package/test/unit/spec/recording-controller/index.js +231 -0
- package/test/unit/spec/recording-controller/util.js +102 -0
- package/test/unit/spec/roap/index.ts +2 -1
- package/test/unit/spec/roap/turnDiscovery.ts +5 -4
- package/tsconfig.json +6 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import PermissionError from '../common/errors/permission';
|
|
2
|
+
import {CONTROLS, HTTP_VERBS} from '../constants';
|
|
3
|
+
import MeetingRequest from '../meeting/request';
|
|
4
|
+
import RecordingAction from './enums';
|
|
5
|
+
import Util from './util';
|
|
6
|
+
import LoggerProxy from '../common/logs/logger-proxy';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @description Recording manages the recording functionality of the meeting object, there should only be one instantation of recording per meeting
|
|
10
|
+
* @export
|
|
11
|
+
* @private
|
|
12
|
+
* @class Recording
|
|
13
|
+
*/
|
|
14
|
+
export default class RecordingController {
|
|
15
|
+
/**
|
|
16
|
+
* @instance
|
|
17
|
+
* @type {MeetingRequest}
|
|
18
|
+
* @private
|
|
19
|
+
* @memberof RecordingController
|
|
20
|
+
*/
|
|
21
|
+
private request: MeetingRequest;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @instance
|
|
25
|
+
* @type {Array}
|
|
26
|
+
* @private
|
|
27
|
+
* @memberof RecordingInfo
|
|
28
|
+
*/
|
|
29
|
+
private displayHints: Array<string> = [];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @instance
|
|
33
|
+
* @type {string}
|
|
34
|
+
* @private
|
|
35
|
+
* @memberof RecordingInfo
|
|
36
|
+
*/
|
|
37
|
+
private serviceUrl: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @instance
|
|
41
|
+
* @type {string}
|
|
42
|
+
* @private
|
|
43
|
+
* @memberof RecordingInfo
|
|
44
|
+
*/
|
|
45
|
+
private sessionId: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @instance
|
|
49
|
+
* @type {string}
|
|
50
|
+
* @private
|
|
51
|
+
* @memberof RecordingInfo
|
|
52
|
+
*/
|
|
53
|
+
private locusUrl: string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @instance
|
|
57
|
+
* @type {string}
|
|
58
|
+
* @private
|
|
59
|
+
* @memberof RecordingInfo
|
|
60
|
+
*/
|
|
61
|
+
private locusId: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {MeetingRequest} request
|
|
65
|
+
* @param {Object} options
|
|
66
|
+
* @constructor
|
|
67
|
+
* @memberof RecordingController
|
|
68
|
+
*/
|
|
69
|
+
constructor(
|
|
70
|
+
request: MeetingRequest,
|
|
71
|
+
options?: {
|
|
72
|
+
serviceUrl?: string;
|
|
73
|
+
sessionId: string;
|
|
74
|
+
locusUrl: string;
|
|
75
|
+
displayHints?: Array<string>;
|
|
76
|
+
}
|
|
77
|
+
) {
|
|
78
|
+
this.initialize(request);
|
|
79
|
+
this.set(options);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @param {MeetingRequest} request
|
|
84
|
+
* @param {LocusInfo} info
|
|
85
|
+
* @returns {void}
|
|
86
|
+
* @private
|
|
87
|
+
* @memberof RecordingController
|
|
88
|
+
*/
|
|
89
|
+
private initialize(request: MeetingRequest) {
|
|
90
|
+
this.request = request;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {Object} options
|
|
95
|
+
* @returns {void}
|
|
96
|
+
* @public
|
|
97
|
+
* @memberof RecordingController
|
|
98
|
+
*/
|
|
99
|
+
public set(options?: {
|
|
100
|
+
serviceUrl?: string;
|
|
101
|
+
sessionId: string;
|
|
102
|
+
locusUrl: string;
|
|
103
|
+
displayHints?: Array<string>;
|
|
104
|
+
}) {
|
|
105
|
+
this.extract(options);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {string} url
|
|
110
|
+
* @returns {void}
|
|
111
|
+
* @public
|
|
112
|
+
* @memberof RecordingController
|
|
113
|
+
*/
|
|
114
|
+
public setLocusUrl(url: string) {
|
|
115
|
+
this.locusUrl = url;
|
|
116
|
+
this.locusId = Util.extractLocusId(this.locusUrl);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @param {Array} hints
|
|
121
|
+
* @returns {void}
|
|
122
|
+
* @public
|
|
123
|
+
* @memberof RecordingController
|
|
124
|
+
*/
|
|
125
|
+
public setDisplayHints(hints: Array<string>) {
|
|
126
|
+
this.displayHints = hints;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @param {string} id
|
|
131
|
+
* @returns {void}
|
|
132
|
+
* @public
|
|
133
|
+
* @memberof RecordingController
|
|
134
|
+
*/
|
|
135
|
+
public setSessionId(id: string) {
|
|
136
|
+
this.sessionId = id;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @param {string} url
|
|
141
|
+
* @returns {void}
|
|
142
|
+
* @public
|
|
143
|
+
* @memberof RecordingController
|
|
144
|
+
*/
|
|
145
|
+
public setServiceUrl(url: string) {
|
|
146
|
+
this.serviceUrl = url;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @returns {string}
|
|
151
|
+
* @public
|
|
152
|
+
* @memberof RecordingController
|
|
153
|
+
*/
|
|
154
|
+
public getLocusUrl() {
|
|
155
|
+
return this.locusUrl;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @returns {string}
|
|
160
|
+
* @public
|
|
161
|
+
* @memberof RecordingController
|
|
162
|
+
*/
|
|
163
|
+
public getLocusId() {
|
|
164
|
+
return this.locusId;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @returns {string}
|
|
169
|
+
* @public
|
|
170
|
+
* @memberof RecordingController
|
|
171
|
+
*/
|
|
172
|
+
public getSessionId() {
|
|
173
|
+
return this.sessionId;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @returns {string}
|
|
178
|
+
* @public
|
|
179
|
+
* @memberof RecordingController
|
|
180
|
+
*/
|
|
181
|
+
public getServiceUrl() {
|
|
182
|
+
return this.serviceUrl;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @returns {Array}
|
|
187
|
+
* @public
|
|
188
|
+
* @memberof RecordingController
|
|
189
|
+
*/
|
|
190
|
+
public getDisplayHints() {
|
|
191
|
+
return this.displayHints;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @param {Object} options
|
|
196
|
+
* @returns {void}
|
|
197
|
+
* @private
|
|
198
|
+
* @memberof RecordingController
|
|
199
|
+
*/
|
|
200
|
+
private extract(options?: {
|
|
201
|
+
serviceUrl?: string;
|
|
202
|
+
sessionId: string;
|
|
203
|
+
locusUrl: string;
|
|
204
|
+
displayHints?: Array<string>;
|
|
205
|
+
}) {
|
|
206
|
+
this.setServiceUrl(options?.serviceUrl);
|
|
207
|
+
this.setSessionId(options?.sessionId);
|
|
208
|
+
this.setDisplayHints(options?.displayHints);
|
|
209
|
+
this.setLocusUrl(options?.locusUrl);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @param {RecordingAction} action
|
|
214
|
+
* @private
|
|
215
|
+
* @memberof RecordingController
|
|
216
|
+
* @returns {Promise}
|
|
217
|
+
*/
|
|
218
|
+
private recordingService(action: RecordingAction): Promise<any> {
|
|
219
|
+
// @ts-ignore
|
|
220
|
+
return this.request.request({
|
|
221
|
+
body: {
|
|
222
|
+
meetingInfo: {
|
|
223
|
+
locusSessionId: this.sessionId,
|
|
224
|
+
},
|
|
225
|
+
recording: {
|
|
226
|
+
action: action.toLowerCase(),
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
uri: `${this.serviceUrl}/loci/${this.locusId}/recording`,
|
|
230
|
+
method: HTTP_VERBS.PUT,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @param {RecordingAction} action
|
|
236
|
+
* @private
|
|
237
|
+
* @memberof RecordingController
|
|
238
|
+
* @returns {Promise}
|
|
239
|
+
*/
|
|
240
|
+
private recordingControls(action: RecordingAction): Promise<any> {
|
|
241
|
+
const record = Util.deriveRecordingStates(action);
|
|
242
|
+
|
|
243
|
+
LoggerProxy.logger.log(`RecordingController:index#recordingControls --> ${record}`);
|
|
244
|
+
|
|
245
|
+
// @ts-ignore
|
|
246
|
+
return this.request.request({
|
|
247
|
+
uri: `${this.locusUrl}/${CONTROLS}`,
|
|
248
|
+
body: {
|
|
249
|
+
record,
|
|
250
|
+
},
|
|
251
|
+
method: HTTP_VERBS.PATCH,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @param {RecordingAction} action
|
|
257
|
+
* @private
|
|
258
|
+
* @memberof RecordingController
|
|
259
|
+
* @returns {Promise}
|
|
260
|
+
*/
|
|
261
|
+
private recordingFacade(action: RecordingAction): Promise<any> {
|
|
262
|
+
LoggerProxy.logger.log(
|
|
263
|
+
`RecordingController:index#recordingFacade --> recording action [${action}]`
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
// assumes action is proper cased (i.e., Example)
|
|
267
|
+
if (Util?.[`canUser${action}`](this.displayHints)) {
|
|
268
|
+
if (this.serviceUrl) {
|
|
269
|
+
return this.recordingService(action);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return this.recordingControls(action);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return Promise.reject(
|
|
276
|
+
new PermissionError(`${action} recording not allowed, due to moderator property.`)
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @private
|
|
282
|
+
* @memberof RecordingController
|
|
283
|
+
* @returns {Promise}
|
|
284
|
+
*/
|
|
285
|
+
public startRecording(): Promise<any> {
|
|
286
|
+
return this.recordingFacade(RecordingAction.Start);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* @private
|
|
291
|
+
* @memberof RecordingController
|
|
292
|
+
* @returns {Promise}
|
|
293
|
+
*/
|
|
294
|
+
public stopRecording(): Promise<any> {
|
|
295
|
+
return this.recordingFacade(RecordingAction.Stop);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* @private
|
|
300
|
+
* @memberof RecordingController
|
|
301
|
+
* @returns {Promise}
|
|
302
|
+
*/
|
|
303
|
+
public pauseRecording(): Promise<any> {
|
|
304
|
+
return this.recordingFacade(RecordingAction.Pause);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* @private
|
|
309
|
+
* @memberof RecordingController
|
|
310
|
+
* @returns {Promise}
|
|
311
|
+
*/
|
|
312
|
+
public resumeRecording(): Promise<any> {
|
|
313
|
+
return this.recordingFacade(RecordingAction.Resume);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {DISPLAY_HINTS} from '../constants';
|
|
2
|
+
import RecordingAction from './enums';
|
|
3
|
+
|
|
4
|
+
const canUserStart = (displayHints: Array<string>): boolean =>
|
|
5
|
+
displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_START);
|
|
6
|
+
|
|
7
|
+
const canUserPause = (displayHints: Array<string>): boolean =>
|
|
8
|
+
displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_PAUSE);
|
|
9
|
+
|
|
10
|
+
const canUserResume = (displayHints: Array<string>): boolean =>
|
|
11
|
+
displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_RESUME);
|
|
12
|
+
|
|
13
|
+
const canUserStop = (displayHints: Array<string>): boolean =>
|
|
14
|
+
displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_STOP);
|
|
15
|
+
|
|
16
|
+
const extractLocusId = (url: string) => {
|
|
17
|
+
return url?.split('/').pop();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const deriveRecordingStates = (action: RecordingAction): {recording: boolean; paused: boolean} => {
|
|
21
|
+
let recording;
|
|
22
|
+
let paused;
|
|
23
|
+
|
|
24
|
+
switch (action) {
|
|
25
|
+
case RecordingAction.Start:
|
|
26
|
+
recording = true;
|
|
27
|
+
paused = false;
|
|
28
|
+
break;
|
|
29
|
+
case RecordingAction.Stop:
|
|
30
|
+
recording = false;
|
|
31
|
+
paused = false;
|
|
32
|
+
break;
|
|
33
|
+
case RecordingAction.Resume:
|
|
34
|
+
recording = true;
|
|
35
|
+
paused = false;
|
|
36
|
+
break;
|
|
37
|
+
case RecordingAction.Pause:
|
|
38
|
+
recording = true;
|
|
39
|
+
paused = true;
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
throw new Error(`Recording state cannot be derived from invalid action: ${action}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
recording,
|
|
47
|
+
paused,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default {
|
|
52
|
+
canUserStart,
|
|
53
|
+
canUserPause,
|
|
54
|
+
canUserResume,
|
|
55
|
+
canUserStop,
|
|
56
|
+
deriveRecordingStates,
|
|
57
|
+
extractLocusId,
|
|
58
|
+
};
|
|
@@ -230,7 +230,7 @@ export default class TurnDiscovery {
|
|
|
230
230
|
* media connection just after a reconnection
|
|
231
231
|
* @returns {Promise}
|
|
232
232
|
*/
|
|
233
|
-
doTurnDiscovery(meeting: Meeting, isReconnecting
|
|
233
|
+
doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean) {
|
|
234
234
|
// @ts-ignore - fix type
|
|
235
235
|
const isAnyClusterReachable = meeting.webex.meetings.reachability.isAnyClusterReachable();
|
|
236
236
|
|
|
@@ -26,6 +26,7 @@ export const getAudioReceiverMqa = ({audioReceiver, statsResults, lastMqaDataSen
|
|
|
26
26
|
|
|
27
27
|
// @ts-ignore
|
|
28
28
|
audioReceiver.streams[0].common.maxRtpJitter =
|
|
29
|
+
// @ts-ignore
|
|
29
30
|
max(statsResults[mediaType][sendrecvType].meanRtpJitter) * 1000 || 0;
|
|
30
31
|
audioReceiver.streams[0].common.meanRtpJitter =
|
|
31
32
|
mean(statsResults[mediaType][sendrecvType].meanRtpJitter) * 1000 || 0;
|
|
@@ -72,6 +73,7 @@ export const getAudioSenderMqa = ({audioSender, statsResults, lastMqaDataSent})
|
|
|
72
73
|
|
|
73
74
|
// @ts-ignore
|
|
74
75
|
audioSender.common.maxRemoteJitter =
|
|
76
|
+
// @ts-ignore
|
|
75
77
|
max(statsResults[mediaType][sendrecvType].meanRemoteJitter) * 1000 || 0;
|
|
76
78
|
audioSender.common.meanRemoteJitter =
|
|
77
79
|
mean(statsResults[mediaType][sendrecvType].meanRemoteJitter) * 1000 || 0;
|
|
@@ -96,6 +98,7 @@ export const getAudioSenderMqa = ({audioSender, statsResults, lastMqaDataSent})
|
|
|
96
98
|
|
|
97
99
|
// @ts-ignore
|
|
98
100
|
audioSender.common.maxRoundTripTime =
|
|
101
|
+
// @ts-ignore
|
|
99
102
|
max(statsResults[mediaType][sendrecvType].meanRoundTripTime) * 1000 || 0;
|
|
100
103
|
audioSender.common.meanRoundTripTime =
|
|
101
104
|
mean(statsResults[mediaType][sendrecvType].meanRoundTripTime) * 1000 || 0;
|
|
@@ -152,6 +155,7 @@ export const getVideoReceiverMqa = ({
|
|
|
152
155
|
|
|
153
156
|
// @ts-ignore
|
|
154
157
|
videoReceiver.common.maxRemoteJitter =
|
|
158
|
+
// @ts-ignore
|
|
155
159
|
max(statsResults[mediaType][sendrecvType].meanRemoteJitter) * 1000 || 0;
|
|
156
160
|
videoReceiver.common.meanRemoteJitter =
|
|
157
161
|
mean(statsResults[mediaType][sendrecvType].meanRemoteJitter) * 1000 || 0;
|
|
@@ -217,6 +221,7 @@ export const getVideoSenderMqa = ({
|
|
|
217
221
|
|
|
218
222
|
// @ts-ignore
|
|
219
223
|
videoSender.common.maxRemoteJitter =
|
|
224
|
+
// @ts-ignore
|
|
220
225
|
max(statsResults[mediaType][sendrecvType].meanRemoteJitter) * 1000 || 0;
|
|
221
226
|
videoSender.common.meanRemoteJitter =
|
|
222
227
|
mean(statsResults[mediaType][sendrecvType].meanRemoteJitter) * 1000 || 0;
|
|
@@ -239,6 +244,7 @@ export const getVideoSenderMqa = ({
|
|
|
239
244
|
|
|
240
245
|
// @ts-ignore
|
|
241
246
|
videoSender.common.maxRoundTripTime =
|
|
247
|
+
// @ts-ignore
|
|
242
248
|
max(statsResults[mediaType][sendrecvType].meanRoundTripTime) * 1000 || 0;
|
|
243
249
|
videoSender.common.meanRoundTripTime =
|
|
244
250
|
mean(statsResults[mediaType][sendrecvType].meanRoundTripTime) * 1000 || 0;
|
|
@@ -5,7 +5,7 @@ import {assert} from '@webex/test-helper-chai';
|
|
|
5
5
|
import {skipInNode} from '@webex/test-helper-mocha';
|
|
6
6
|
import sinon from 'sinon';
|
|
7
7
|
|
|
8
|
-
import BrowserDetection from '@webex/plugin-meetings/
|
|
8
|
+
import BrowserDetection from '@webex/plugin-meetings/dist/common/browser-detection';
|
|
9
9
|
|
|
10
10
|
import DEFAULT_RESOLUTIONS from '../../../src/config';
|
|
11
11
|
import testUtils from '../../utils/testUtils';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {assert} from '@webex/test-helper-chai';
|
|
3
3
|
import {skipInNode, jenkinsOnly} from '@webex/test-helper-mocha';
|
|
4
4
|
import {patterns} from '@webex/common';
|
|
5
|
-
import MeetingInfoUtil from '@webex/plugin-meetings/
|
|
5
|
+
import MeetingInfoUtil from '@webex/plugin-meetings/dist/meeting-info/utilv2';
|
|
6
6
|
|
|
7
7
|
import CMR from '../../utils/cmr';
|
|
8
8
|
import testUtils from '../../utils/testUtils';
|
|
@@ -35,6 +35,7 @@ import Media from '@webex/plugin-meetings/src/media/index';
|
|
|
35
35
|
import PeerConnectionManager from '@webex/plugin-meetings/src/peer-connection-manager';
|
|
36
36
|
import ReconnectionManager from '@webex/plugin-meetings/src/reconnection-manager';
|
|
37
37
|
import MediaUtil from '@webex/plugin-meetings/src/media/util';
|
|
38
|
+
import RecordingUtil from '@webex/plugin-meetings/src/recording-controller/util';
|
|
38
39
|
import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
|
|
39
40
|
import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
|
|
40
41
|
import TriggerProxy from '@webex/plugin-meetings/src/common/events/trigger-proxy';
|
|
@@ -3583,6 +3584,7 @@ describe('plugin-meetings', () => {
|
|
|
3583
3584
|
const newLocusUrl = 'newLocusUrl/12345';
|
|
3584
3585
|
|
|
3585
3586
|
meeting.members = {locusUrlUpdate: sinon.stub().returns(Promise.resolve(test1))};
|
|
3587
|
+
meeting.recordingController = {setLocusUrl: sinon.stub().returns(undefined)};
|
|
3586
3588
|
|
|
3587
3589
|
meeting.locusInfo.emit(
|
|
3588
3590
|
{function: 'test', file: 'test'},
|
|
@@ -3590,11 +3592,36 @@ describe('plugin-meetings', () => {
|
|
|
3590
3592
|
newLocusUrl
|
|
3591
3593
|
);
|
|
3592
3594
|
assert.calledWith(meeting.members.locusUrlUpdate, newLocusUrl);
|
|
3595
|
+
assert.calledWith(meeting.recordingController.setLocusUrl, newLocusUrl);
|
|
3593
3596
|
assert.equal(meeting.locusUrl, newLocusUrl);
|
|
3594
3597
|
assert(meeting.locusId, '12345');
|
|
3595
3598
|
done();
|
|
3596
3599
|
});
|
|
3597
3600
|
});
|
|
3601
|
+
|
|
3602
|
+
describe('#setUpLocusServicesListener', () => {
|
|
3603
|
+
it('listens to the locus services update event', (done) => {
|
|
3604
|
+
const newLocusServices = {
|
|
3605
|
+
services: {
|
|
3606
|
+
record: {
|
|
3607
|
+
url: 'url',
|
|
3608
|
+
}
|
|
3609
|
+
},
|
|
3610
|
+
};
|
|
3611
|
+
|
|
3612
|
+
meeting.recordingController = {setServiceUrl: sinon.stub().returns(undefined), setSessionId: sinon.stub().returns(undefined)};
|
|
3613
|
+
|
|
3614
|
+
meeting.locusInfo.emit(
|
|
3615
|
+
{function: 'test', file: 'test'},
|
|
3616
|
+
'LINKS_SERVICES',
|
|
3617
|
+
newLocusServices
|
|
3618
|
+
);
|
|
3619
|
+
|
|
3620
|
+
assert.calledWith(meeting.recordingController.setServiceUrl, newLocusServices.services.record.url);
|
|
3621
|
+
assert.calledOnce(meeting.recordingController.setSessionId);
|
|
3622
|
+
done();
|
|
3623
|
+
});
|
|
3624
|
+
});
|
|
3598
3625
|
describe('#setUpLocusInfoMediaInactiveListener', () => {
|
|
3599
3626
|
it('listens to disconnect due to un activity ', (done) => {
|
|
3600
3627
|
TriggerProxy.trigger.reset();
|
|
@@ -4009,7 +4036,7 @@ describe('plugin-meetings', () => {
|
|
|
4009
4036
|
let inMeetingActionsSetSpy;
|
|
4010
4037
|
let canUserLockSpy;
|
|
4011
4038
|
let canUserUnlockSpy;
|
|
4012
|
-
let
|
|
4039
|
+
let canUserStartSpy;
|
|
4013
4040
|
let canUserStopSpy;
|
|
4014
4041
|
let canUserPauseSpy;
|
|
4015
4042
|
let canUserResumeSpy;
|
|
@@ -4023,10 +4050,10 @@ describe('plugin-meetings', () => {
|
|
|
4023
4050
|
locusInfoOnSpy = sinon.spy(meeting.locusInfo, 'on');
|
|
4024
4051
|
canUserLockSpy = sinon.spy(MeetingUtil, 'canUserLock');
|
|
4025
4052
|
canUserUnlockSpy = sinon.spy(MeetingUtil, 'canUserUnlock');
|
|
4026
|
-
|
|
4027
|
-
canUserStopSpy = sinon.spy(
|
|
4028
|
-
canUserPauseSpy = sinon.spy(
|
|
4029
|
-
canUserResumeSpy = sinon.spy(
|
|
4053
|
+
canUserStartSpy = sinon.spy(RecordingUtil, 'canUserStart');
|
|
4054
|
+
canUserStopSpy = sinon.spy(RecordingUtil, 'canUserStop');
|
|
4055
|
+
canUserPauseSpy = sinon.spy(RecordingUtil, 'canUserPause');
|
|
4056
|
+
canUserResumeSpy = sinon.spy(RecordingUtil, 'canUserResume');
|
|
4030
4057
|
inMeetingActionsSetSpy = sinon.spy(meeting.inMeetingActions, 'set');
|
|
4031
4058
|
canUserRaiseHandSpy = sinon.spy(MeetingUtil, 'canUserRaiseHand');
|
|
4032
4059
|
canUserLowerAllHandsSpy = sinon.spy(MeetingUtil, 'canUserLowerAllHands');
|
|
@@ -4064,7 +4091,7 @@ describe('plugin-meetings', () => {
|
|
|
4064
4091
|
|
|
4065
4092
|
assert.calledWith(canUserLockSpy, payload.info.userDisplayHints);
|
|
4066
4093
|
assert.calledWith(canUserUnlockSpy, payload.info.userDisplayHints);
|
|
4067
|
-
assert.calledWith(
|
|
4094
|
+
assert.calledWith(canUserStartSpy, payload.info.userDisplayHints);
|
|
4068
4095
|
assert.calledWith(canUserStopSpy, payload.info.userDisplayHints);
|
|
4069
4096
|
assert.calledWith(canUserPauseSpy, payload.info.userDisplayHints);
|
|
4070
4097
|
assert.calledWith(canUserResumeSpy, payload.info.userDisplayHints);
|
|
@@ -297,34 +297,6 @@ describe('plugin-meetings', () => {
|
|
|
297
297
|
});
|
|
298
298
|
});
|
|
299
299
|
|
|
300
|
-
describe('canUserRecord', () => {
|
|
301
|
-
it('works as expected', () => {
|
|
302
|
-
assert.deepEqual(MeetingUtil.canUserRecord(['RECORDING_CONTROL_START']), true);
|
|
303
|
-
assert.deepEqual(MeetingUtil.canUserRecord([]), false);
|
|
304
|
-
});
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
describe('canUserPause', () => {
|
|
308
|
-
it('works as expected', () => {
|
|
309
|
-
assert.deepEqual(MeetingUtil.canUserPause(['RECORDING_CONTROL_PAUSE']), true);
|
|
310
|
-
assert.deepEqual(MeetingUtil.canUserPause([]), false);
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
describe('canUserResume', () => {
|
|
315
|
-
it('works as expected', () => {
|
|
316
|
-
assert.deepEqual(MeetingUtil.canUserResume(['RECORDING_CONTROL_RESUME']), true);
|
|
317
|
-
assert.deepEqual(MeetingUtil.canUserResume([]), false);
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
describe('canUserStop', () => {
|
|
322
|
-
it('works as expected', () => {
|
|
323
|
-
assert.deepEqual(MeetingUtil.canUserStop(['RECORDING_CONTROL_STOP']), true);
|
|
324
|
-
assert.deepEqual(MeetingUtil.canUserStop([]), false);
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
|
|
328
300
|
[
|
|
329
301
|
{functionName: 'canEnableClosedCaption', displayHint: 'CAPTION_START'},
|
|
330
302
|
{functionName: 'canStartTranscribing', displayHint: 'TRANSCRIPTION_CONTROL_START'},
|
|
@@ -343,104 +315,5 @@ describe('plugin-meetings', () => {
|
|
|
343
315
|
});
|
|
344
316
|
});
|
|
345
317
|
});
|
|
346
|
-
|
|
347
|
-
describe('recording tests', () => {
|
|
348
|
-
let request;
|
|
349
|
-
let locusInfo;
|
|
350
|
-
const locusUrl = 'locusUrl';
|
|
351
|
-
|
|
352
|
-
beforeEach(() => {
|
|
353
|
-
locusInfo = {
|
|
354
|
-
parsedLocus: {
|
|
355
|
-
info: {
|
|
356
|
-
userDisplayHints: ['RECORDING_CONTROL_START'],
|
|
357
|
-
},
|
|
358
|
-
},
|
|
359
|
-
};
|
|
360
|
-
request = {
|
|
361
|
-
recordMeeting: sinon.stub().returns(Promise.resolve()),
|
|
362
|
-
};
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
describe('startRecording', () => {
|
|
366
|
-
it('can start recording when the correct display hint is present', () => {
|
|
367
|
-
locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_START');
|
|
368
|
-
|
|
369
|
-
const result = MeetingUtil.startRecording(request, locusUrl, locusInfo);
|
|
370
|
-
|
|
371
|
-
assert.calledWith(request.recordMeeting, {locusUrl, recording: true, paused: false});
|
|
372
|
-
|
|
373
|
-
assert.deepEqual(result, request.recordMeeting.firstCall.returnValue);
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
it('rejects when correct display hint is not present', () => {
|
|
377
|
-
const result = MeetingUtil.startRecording(request, locusUrl, {});
|
|
378
|
-
|
|
379
|
-
assert.notCalled(request.recordMeeting);
|
|
380
|
-
|
|
381
|
-
assert.isRejected(result);
|
|
382
|
-
});
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
describe('pauseRecording', () => {
|
|
386
|
-
it('can pause recording when the correct display hint is present', () => {
|
|
387
|
-
locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_PAUSE');
|
|
388
|
-
|
|
389
|
-
const result = MeetingUtil.pauseRecording(request, locusUrl, locusInfo);
|
|
390
|
-
|
|
391
|
-
assert.calledWith(request.recordMeeting, {locusUrl, recording: true, paused: true});
|
|
392
|
-
|
|
393
|
-
assert.deepEqual(result, request.recordMeeting.firstCall.returnValue);
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
it('rejects when correct display hint is not present', () => {
|
|
397
|
-
const result = MeetingUtil.pauseRecording(request, locusUrl, {});
|
|
398
|
-
|
|
399
|
-
assert.notCalled(request.recordMeeting);
|
|
400
|
-
|
|
401
|
-
assert.isRejected(result);
|
|
402
|
-
});
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
describe('resumeRecording', () => {
|
|
406
|
-
it('can resume recording when the correct display hint is present', () => {
|
|
407
|
-
locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_RESUME');
|
|
408
|
-
|
|
409
|
-
const result = MeetingUtil.resumeRecording(request, locusUrl, locusInfo);
|
|
410
|
-
|
|
411
|
-
assert.calledWith(request.recordMeeting, {locusUrl, recording: true, paused: false});
|
|
412
|
-
|
|
413
|
-
assert.deepEqual(result, request.recordMeeting.firstCall.returnValue);
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it('rejects when correct display hint is not present', () => {
|
|
417
|
-
const result = MeetingUtil.resumeRecording(request, locusUrl, {});
|
|
418
|
-
|
|
419
|
-
assert.notCalled(request.recordMeeting);
|
|
420
|
-
|
|
421
|
-
assert.isRejected(result);
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
describe('stopRecording', () => {
|
|
426
|
-
it('can stop recording when the correct display hint is present', () => {
|
|
427
|
-
locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_STOP');
|
|
428
|
-
|
|
429
|
-
const result = MeetingUtil.stopRecording(request, locusUrl, locusInfo);
|
|
430
|
-
|
|
431
|
-
assert.calledWith(request.recordMeeting, {locusUrl, recording: false, paused: false});
|
|
432
|
-
|
|
433
|
-
assert.deepEqual(result, request.recordMeeting.firstCall.returnValue);
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
it('rejects when correct display hint is not present', () => {
|
|
437
|
-
const result = MeetingUtil.stopRecording(request, locusUrl, {});
|
|
438
|
-
|
|
439
|
-
assert.notCalled(request.recordMeeting);
|
|
440
|
-
|
|
441
|
-
assert.isRejected(result);
|
|
442
|
-
});
|
|
443
|
-
});
|
|
444
|
-
});
|
|
445
318
|
});
|
|
446
319
|
});
|