@webex/plugin-meetings 3.0.0-beta.17 → 3.0.0-beta.18
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/breakouts/breakout.js +116 -0
- package/dist/breakouts/breakout.js.map +1 -0
- package/dist/breakouts/collection.js +23 -0
- package/dist/breakouts/collection.js.map +1 -0
- package/dist/breakouts/index.js +226 -0
- package/dist/breakouts/index.js.map +1 -0
- package/dist/config.js +4 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +38 -5
- package/dist/constants.js.map +1 -1
- package/dist/locus-info/controlsUtils.js +2 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +48 -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/locus-info/selfUtils.js +19 -11
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +3 -3
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +4 -4
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.js +651 -460
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +25 -44
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/util.js +4 -57
- 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 +28 -18
- 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/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js +14 -1
- package/dist/member/util.js.map +1 -1
- package/dist/members/index.js +8 -6
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +3 -1
- package/dist/members/request.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +46 -6
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/multistreamMedia.js +4 -0
- package/dist/multistream/multistreamMedia.js.map +1 -1
- package/dist/multistream/receiveSlot.js +3 -3
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +8 -6
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +168 -63
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/reachability/index.js +63 -51
- package/dist/reachability/index.js.map +1 -1
- package/dist/reactions/constants.js +13 -0
- package/dist/reactions/constants.js.map +1 -0
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/reconnection-manager/index.js +25 -12
- package/dist/reconnection-manager/index.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/request.js +88 -68
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +72 -47
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/statsAnalyzer/index.js +3 -3
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +18 -6
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/package.json +24 -19
- package/src/breakouts/README.md +190 -0
- package/src/breakouts/breakout.ts +110 -0
- package/src/breakouts/collection.ts +19 -0
- package/src/breakouts/index.ts +225 -0
- package/src/config.ts +4 -1
- package/src/constants.ts +35 -1
- package/src/locus-info/controlsUtils.ts +2 -0
- package/src/locus-info/index.ts +59 -1
- package/src/locus-info/parser.ts +1 -0
- package/src/locus-info/selfUtils.ts +8 -0
- package/src/media/index.ts +1 -2
- package/src/media/properties.ts +6 -9
- package/src/meeting/index.ts +352 -111
- package/src/meeting/request.ts +9 -31
- package/src/meeting/request.type.ts +2 -0
- package/src/meeting/util.ts +3 -60
- package/src/meeting-info/meeting-info-v2.ts +2 -0
- package/src/meetings/index.ts +10 -5
- package/src/meetings/request.ts +1 -1
- package/src/member/index.ts +9 -0
- package/src/member/util.ts +14 -1
- package/src/members/index.ts +1 -0
- package/src/members/request.ts +1 -0
- package/src/multistream/mediaRequestManager.ts +79 -15
- package/src/multistream/multistreamMedia.ts +4 -0
- package/src/multistream/receiveSlot.ts +17 -12
- package/src/multistream/receiveSlotManager.ts +22 -21
- package/src/multistream/remoteMedia.ts +1 -1
- package/src/multistream/remoteMediaGroup.ts +2 -2
- package/src/multistream/remoteMediaManager.ts +150 -37
- package/src/reachability/index.ts +16 -13
- package/src/reactions/constants.ts +4 -0
- package/src/reactions/reactions.type.ts +25 -0
- package/src/reconnection-manager/index.ts +18 -9
- 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/request.ts +78 -73
- package/src/roap/turnDiscovery.ts +8 -6
- package/src/statsAnalyzer/index.ts +4 -4
- package/src/statsAnalyzer/mqaUtil.ts +6 -0
- package/test/unit/spec/breakouts/breakout.ts +119 -0
- package/test/unit/spec/breakouts/collection.ts +15 -0
- package/test/unit/spec/breakouts/index.ts +293 -0
- package/test/unit/spec/locus-info/controlsUtils.js +20 -0
- package/test/unit/spec/locus-info/index.js +103 -0
- package/test/unit/spec/locus-info/selfConstant.js +25 -0
- package/test/unit/spec/locus-info/selfUtils.js +84 -0
- package/test/unit/spec/media/index.ts +1 -1
- package/test/unit/spec/media/properties.ts +9 -9
- package/test/unit/spec/meeting/effectsState.js +5 -1
- package/test/unit/spec/meeting/index.js +235 -50
- package/test/unit/spec/meeting/request.js +17 -0
- package/test/unit/spec/meeting/utils.js +20 -129
- package/test/unit/spec/meetings/index.js +1 -0
- package/test/unit/spec/member/util.js +26 -1
- package/test/unit/spec/multistream/mediaRequestManager.ts +312 -50
- package/test/unit/spec/multistream/receiveSlot.ts +6 -6
- package/test/unit/spec/multistream/receiveSlotManager.ts +13 -13
- package/test/unit/spec/multistream/remoteMedia.ts +2 -2
- package/test/unit/spec/multistream/remoteMediaGroup.ts +5 -5
- package/test/unit/spec/multistream/remoteMediaManager.ts +354 -65
- package/test/unit/spec/reachability/index.ts +58 -24
- package/test/unit/spec/reconnection-manager/index.js +42 -13
- 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/request.ts +114 -0
- package/test/unit/spec/roap/turnDiscovery.ts +45 -29
- package/test/unit/spec/stats-analyzer/index.js +2 -2
- package/test/utils/webex-test-users.js +1 -0
- package/tsconfig.json +6 -0
- package/dist/media/internal-media-core-wrapper.js +0 -18
- package/dist/media/internal-media-core-wrapper.js.map +0 -1
- package/src/media/internal-media-core-wrapper.ts +0 -9
|
@@ -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
|
+
};
|
package/src/roap/request.ts
CHANGED
|
@@ -13,12 +13,14 @@ import {eventType} from '../metrics/config';
|
|
|
13
13
|
export default class RoapRequest extends StatelessWebexPlugin {
|
|
14
14
|
/**
|
|
15
15
|
* Joins a meeting via ROAP
|
|
16
|
-
* @param {Object}
|
|
16
|
+
* @param {Object} localSdp
|
|
17
17
|
* @returns {Promise} returns a promise that resolves/rejects whatever the request does
|
|
18
18
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const reachabilityData =
|
|
19
|
+
async attachRechabilityData(localSdp) {
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
const reachabilityData = await this.webex.boundedStorage
|
|
22
|
+
.get(REACHABILITY.namespace, REACHABILITY.localStorage)
|
|
23
|
+
.catch(() => {});
|
|
22
24
|
|
|
23
25
|
if (reachabilityData) {
|
|
24
26
|
try {
|
|
@@ -48,6 +50,7 @@ export default class RoapRequest extends StatelessWebexPlugin {
|
|
|
48
50
|
* @param {Boolean} options.audioMuted
|
|
49
51
|
* @param {Boolean} options.videoMuted
|
|
50
52
|
* @param {String} options.meetingId
|
|
53
|
+
* @param {Boolean} options.preferTranscoding
|
|
51
54
|
* @returns {Promise} returns the response/failure of the request
|
|
52
55
|
*/
|
|
53
56
|
sendRoap(options: {
|
|
@@ -76,77 +79,79 @@ export default class RoapRequest extends StatelessWebexPlugin {
|
|
|
76
79
|
|
|
77
80
|
Metrics.postEvent({event: eventType.MEDIA_REQUEST, meetingId});
|
|
78
81
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
{
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
82
|
+
return this.attachRechabilityData({
|
|
83
|
+
roapMessage,
|
|
84
|
+
// eslint-disable-next-line no-warning-comments
|
|
85
|
+
// TODO: check whats the need for video and audiomute
|
|
86
|
+
audioMuted: !!options.audioMuted,
|
|
87
|
+
videoMuted: !!options.videoMuted,
|
|
88
|
+
}).then((sdpWithReachability) => {
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
return this.webex
|
|
91
|
+
.request({
|
|
92
|
+
uri: mediaUrl,
|
|
93
|
+
method: HTTP_VERBS.PUT,
|
|
94
|
+
body: {
|
|
95
|
+
device: {
|
|
96
|
+
url: deviceUrl,
|
|
97
|
+
// @ts-ignore
|
|
98
|
+
deviceType: this.config.meetings.deviceType,
|
|
99
|
+
},
|
|
100
|
+
correlationId,
|
|
101
|
+
localMedias: [
|
|
102
|
+
{
|
|
103
|
+
localSdp: JSON.stringify(sdpWithReachability),
|
|
104
|
+
mediaId: options.mediaId,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
clientMediaPreferences: {
|
|
108
|
+
preferTranscoding: options.preferTranscoding ?? true,
|
|
103
109
|
},
|
|
104
|
-
],
|
|
105
|
-
clientMediaPreferences: {
|
|
106
|
-
preferTranscoding: options.preferTranscoding ?? true,
|
|
107
110
|
},
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
111
|
+
})
|
|
112
|
+
.then((res) => {
|
|
113
|
+
Metrics.postEvent({event: eventType.MEDIA_RESPONSE, meetingId});
|
|
114
|
+
|
|
115
|
+
// always it will be the first mediaConnection Object
|
|
116
|
+
const mediaConnections =
|
|
117
|
+
res.body.mediaConnections &&
|
|
118
|
+
res.body.mediaConnections.length > 0 &&
|
|
119
|
+
res.body.mediaConnections[0];
|
|
120
|
+
|
|
121
|
+
LoggerProxy.logger.info(
|
|
122
|
+
`Roap:request#sendRoap --> response:${JSON.stringify(
|
|
123
|
+
mediaConnections,
|
|
124
|
+
null,
|
|
125
|
+
2
|
|
126
|
+
)}'\n StatusCode:'${res.statusCode}`
|
|
127
|
+
);
|
|
128
|
+
const {locus} = res.body;
|
|
129
|
+
|
|
130
|
+
locus.roapSeq = options.roapMessage.seq;
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
locus,
|
|
134
|
+
...(mediaConnections && {mediaConnections: res.body.mediaConnections}),
|
|
135
|
+
};
|
|
136
|
+
})
|
|
137
|
+
.catch((err) => {
|
|
138
|
+
Metrics.postEvent({
|
|
139
|
+
event: eventType.MEDIA_RESPONSE,
|
|
140
|
+
meetingId,
|
|
141
|
+
data: {error: Metrics.parseLocusError(err, true)},
|
|
142
|
+
});
|
|
143
|
+
LoggerProxy.logger.error(
|
|
144
|
+
`Roap:request#sendRoap --> Error:${JSON.stringify(err, null, 2)}`
|
|
145
|
+
);
|
|
146
|
+
LoggerProxy.logger.error(
|
|
147
|
+
`Roap:request#sendRoapRequest --> errorBody:${JSON.stringify(
|
|
148
|
+
roapMessage,
|
|
149
|
+
null,
|
|
150
|
+
2
|
|
151
|
+
)} + '\\n mediaId:'${options.mediaId}`
|
|
152
|
+
);
|
|
153
|
+
throw err;
|
|
140
154
|
});
|
|
141
|
-
|
|
142
|
-
LoggerProxy.logger.error(
|
|
143
|
-
`Roap:request#sendRoapRequest --> errorBody:${JSON.stringify(
|
|
144
|
-
roapMessage,
|
|
145
|
-
null,
|
|
146
|
-
2
|
|
147
|
-
)} + '\\n mediaId:'${options.mediaId}`
|
|
148
|
-
);
|
|
149
|
-
throw err;
|
|
150
|
-
});
|
|
155
|
+
});
|
|
151
156
|
}
|
|
152
157
|
}
|
|
@@ -184,6 +184,7 @@ export default class TurnDiscovery {
|
|
|
184
184
|
audioMuted: meeting.isAudioMuted(),
|
|
185
185
|
videoMuted: meeting.isVideoMuted(),
|
|
186
186
|
meetingId: meeting.id,
|
|
187
|
+
preferTranscoding: !meeting.isMultistream,
|
|
187
188
|
})
|
|
188
189
|
.then(({mediaConnections}) => {
|
|
189
190
|
if (mediaConnections) {
|
|
@@ -216,6 +217,7 @@ export default class TurnDiscovery {
|
|
|
216
217
|
audioMuted: meeting.isAudioMuted(),
|
|
217
218
|
videoMuted: meeting.isVideoMuted(),
|
|
218
219
|
meetingId: meeting.id,
|
|
220
|
+
preferTranscoding: !meeting.isMultistream,
|
|
219
221
|
});
|
|
220
222
|
}
|
|
221
223
|
|
|
@@ -236,19 +238,19 @@ export default class TurnDiscovery {
|
|
|
236
238
|
* media connection just after a reconnection
|
|
237
239
|
* @returns {Promise}
|
|
238
240
|
*/
|
|
239
|
-
doTurnDiscovery(meeting: Meeting, isReconnecting
|
|
241
|
+
async doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean) {
|
|
240
242
|
// @ts-ignore - fix type
|
|
241
|
-
const isAnyClusterReachable = meeting.webex.meetings.reachability.isAnyClusterReachable();
|
|
243
|
+
const isAnyClusterReachable = await meeting.webex.meetings.reachability.isAnyClusterReachable();
|
|
242
244
|
|
|
243
245
|
if (isAnyClusterReachable) {
|
|
244
246
|
LoggerProxy.logger.info(
|
|
245
247
|
'Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery'
|
|
246
248
|
);
|
|
247
249
|
|
|
248
|
-
return
|
|
250
|
+
return {
|
|
249
251
|
turnServerInfo: undefined,
|
|
250
252
|
turnDiscoverySkippedReason: 'reachability',
|
|
251
|
-
}
|
|
253
|
+
};
|
|
252
254
|
}
|
|
253
255
|
|
|
254
256
|
// @ts-ignore - fix type
|
|
@@ -257,7 +259,7 @@ export default class TurnDiscovery {
|
|
|
257
259
|
'Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it'
|
|
258
260
|
);
|
|
259
261
|
|
|
260
|
-
return
|
|
262
|
+
return {turnServerInfo: undefined, turnDiscoverySkippedReason: 'config'};
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting)
|
|
@@ -283,7 +285,7 @@ export default class TurnDiscovery {
|
|
|
283
285
|
stack: e.stack,
|
|
284
286
|
});
|
|
285
287
|
|
|
286
|
-
return
|
|
288
|
+
return {turnServerInfo: undefined, turnDiscoverySkippedReason: undefined};
|
|
287
289
|
});
|
|
288
290
|
}
|
|
289
291
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable prefer-destructuring */
|
|
2
2
|
|
|
3
3
|
import {cloneDeep} from 'lodash';
|
|
4
|
-
import {
|
|
4
|
+
import {ConnectionState} from '@webex/internal-media-core';
|
|
5
5
|
|
|
6
6
|
import EventsScope from '../common/events/events-scope';
|
|
7
7
|
import {
|
|
@@ -335,7 +335,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
335
335
|
*
|
|
336
336
|
* @private
|
|
337
337
|
* @memberof StatsAnalyzer
|
|
338
|
-
* @param {
|
|
338
|
+
* @param {RoapMediaConnection} mediaConnection
|
|
339
339
|
* @returns {void}
|
|
340
340
|
*/
|
|
341
341
|
updateMediaConnection(mediaConnection: any) {
|
|
@@ -347,7 +347,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
347
347
|
*
|
|
348
348
|
* @public
|
|
349
349
|
* @memberof StatsAnalyzer
|
|
350
|
-
* @param {
|
|
350
|
+
* @param {RoapMediaConnection} mediaConnection
|
|
351
351
|
* @returns {Promise}
|
|
352
352
|
*/
|
|
353
353
|
public startAnalyzer(mediaConnection: any) {
|
|
@@ -820,7 +820,7 @@ export class StatsAnalyzer extends EventsScope {
|
|
|
820
820
|
|
|
821
821
|
if (
|
|
822
822
|
this.mediaConnection &&
|
|
823
|
-
this.mediaConnection.getConnectionState() ===
|
|
823
|
+
this.mediaConnection.getConnectionState() === ConnectionState.Failed
|
|
824
824
|
) {
|
|
825
825
|
LoggerProxy.logger.trace(
|
|
826
826
|
'StatsAnalyzer:index#getStatsAndParse --> media connection is in failed state'
|
|
@@ -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;
|