@webex/plugin-meetings 3.0.0-bnr.5 → 3.0.0-stream-classes.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/README.md +46 -8
- package/dist/annotation/annotation.types.js +7 -0
- package/dist/annotation/annotation.types.js.map +1 -0
- package/dist/annotation/constants.js +49 -0
- package/dist/annotation/constants.js.map +1 -0
- package/dist/annotation/index.js +342 -0
- package/dist/annotation/index.js.map +1 -0
- package/dist/breakouts/breakout.js +70 -32
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/events.js +45 -0
- package/dist/breakouts/events.js.map +1 -0
- package/dist/breakouts/index.js +422 -217
- package/dist/breakouts/index.js.map +1 -1
- package/dist/breakouts/utils.js +12 -1
- package/dist/breakouts/utils.js.map +1 -1
- package/dist/common/errors/webex-errors.js +3 -2
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/logs/logger-proxy.js +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.d.ts +1 -1
- package/dist/common/queue.js +24 -9
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +1 -7
- package/dist/config.js.map +1 -1
- package/dist/constants.js +118 -24
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +2 -0
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +19 -14
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/types.js.map +1 -1
- package/dist/controls-options-manager/util.js +80 -11
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/index.js +62 -20
- package/dist/index.js.map +1 -1
- package/dist/interpretation/collection.js +23 -0
- package/dist/interpretation/collection.js.map +1 -0
- package/dist/interpretation/index.js +366 -0
- package/dist/interpretation/index.js.map +1 -0
- package/dist/interpretation/siLanguage.js +25 -0
- package/dist/interpretation/siLanguage.js.map +1 -0
- package/dist/locus-info/controlsUtils.js +71 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +305 -57
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js +7 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js +43 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +219 -63
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js +44 -22
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +57 -104
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +60 -121
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +61 -3
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +2530 -2534
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +292 -0
- package/dist/meeting/locusMediaRequest.js.map +1 -0
- package/dist/meeting/muteState.js +125 -205
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +150 -150
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +568 -438
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/index.js +48 -7
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +94 -38
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +4 -2
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.d.ts +0 -2
- package/dist/meetings/index.js +260 -85
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +7 -0
- package/dist/meetings/meetings.types.js.map +1 -0
- package/dist/meetings/util.js +42 -7
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.d.ts +2 -0
- package/dist/member/index.js +26 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/member.types.d.ts +11 -0
- package/dist/member/member.types.js +18 -0
- package/dist/member/member.types.js.map +1 -0
- package/dist/member/types.js +11 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +60 -23
- package/dist/member/util.js.map +1 -1
- package/dist/members/index.js +4 -1
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +75 -45
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js +308 -317
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/config.js +1 -3
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/constants.js +1 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.d.ts +1 -1
- package/dist/metrics/index.js +1 -451
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +136 -40
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +4 -4
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +60 -3
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +36 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +233 -0
- package/dist/multistream/sendSlotManager.js.map +1 -0
- package/dist/reachability/index.js +18 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +5 -3
- package/dist/reachability/request.js.map +1 -1
- package/dist/reconnection-manager/index.js +181 -153
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/index.js +21 -2
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js +9 -8
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +25 -32
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +42 -51
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +97 -38
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/rtcMetrics/constants.js +12 -0
- package/dist/rtcMetrics/constants.js.map +1 -0
- package/dist/rtcMetrics/index.js +117 -0
- package/dist/rtcMetrics/index.js.map +1 -0
- package/dist/statsAnalyzer/index.js +0 -1
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/types/annotation/annotation.types.d.ts +43 -0
- package/dist/types/annotation/constants.d.ts +31 -0
- package/dist/types/annotation/index.d.ts +124 -0
- package/dist/types/breakouts/events.d.ts +2 -0
- package/dist/types/breakouts/utils.d.ts +7 -0
- package/dist/types/common/errors/webex-errors.d.ts +1 -1
- package/dist/types/config.d.ts +0 -6
- package/dist/types/constants.d.ts +51 -21
- package/dist/types/controls-options-manager/enums.d.ts +2 -0
- package/dist/types/controls-options-manager/index.d.ts +1 -1
- package/dist/types/controls-options-manager/types.d.ts +7 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/interpretation/collection.d.ts +5 -0
- package/dist/types/interpretation/index.d.ts +5 -0
- package/dist/types/interpretation/siLanguage.d.ts +5 -0
- package/dist/types/locus-info/index.d.ts +39 -1
- package/dist/types/media/index.d.ts +2 -0
- package/dist/types/media/properties.d.ts +16 -38
- package/dist/types/meeting/in-meeting-actions.d.ts +46 -2
- package/dist/types/meeting/index.d.ts +179 -379
- package/dist/types/meeting/locusMediaRequest.d.ts +70 -0
- package/dist/types/meeting/muteState.d.ts +39 -40
- package/dist/types/meeting/request.d.ts +25 -26
- package/dist/types/meeting/util.d.ts +74 -1
- package/dist/types/meeting-info/meeting-info-v2.d.ts +14 -3
- package/dist/types/meetings/index.d.ts +49 -1
- package/dist/types/meetings/meetings.types.d.ts +4 -0
- package/dist/types/member/index.d.ts +2 -0
- package/dist/types/members/request.d.ts +56 -11
- package/dist/types/members/util.d.ts +209 -1
- package/dist/types/metrics/config.d.ts +26 -2
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/types/metrics/index.d.ts +17 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +27 -10
- package/dist/types/multistream/receiveSlot.d.ts +3 -3
- package/dist/types/multistream/remoteMedia.d.ts +2 -2
- package/dist/types/multistream/remoteMediaManager.d.ts +14 -0
- package/dist/types/roap/request.d.ts +6 -8
- package/dist/types/roap/turnDiscovery.d.ts +18 -1
- package/package.json +21 -20
- package/src/annotation/annotation.types.ts +50 -0
- package/src/annotation/constants.ts +36 -0
- package/src/annotation/index.ts +328 -0
- package/src/breakouts/README.md +3 -2
- package/src/breakouts/breakout.ts +62 -27
- package/src/breakouts/events.ts +56 -0
- package/src/breakouts/index.ts +244 -64
- package/src/breakouts/utils.ts +13 -0
- package/src/common/errors/webex-errors.ts +6 -2
- package/src/common/logs/logger-proxy.ts +1 -1
- package/src/common/queue.ts +22 -8
- package/src/config.ts +0 -6
- package/src/constants.ts +111 -19
- package/src/controls-options-manager/enums.ts +2 -0
- package/src/controls-options-manager/index.ts +13 -10
- package/src/controls-options-manager/types.ts +10 -0
- package/src/controls-options-manager/util.ts +82 -11
- package/src/index.ts +18 -11
- package/src/interpretation/README.md +60 -0
- package/src/interpretation/collection.ts +19 -0
- package/src/interpretation/index.ts +332 -0
- package/src/interpretation/siLanguage.ts +18 -0
- package/src/locus-info/controlsUtils.ts +81 -0
- package/src/locus-info/index.ts +318 -57
- package/src/locus-info/infoUtils.ts +10 -2
- package/src/locus-info/mediaSharesUtils.ts +48 -0
- package/src/locus-info/parser.ts +224 -39
- package/src/locus-info/selfUtils.ts +32 -20
- package/src/media/index.ts +94 -108
- package/src/media/properties.ts +69 -109
- package/src/meeting/in-meeting-actions.ts +120 -4
- package/src/meeting/index.ts +1967 -2120
- package/src/meeting/locusMediaRequest.ts +314 -0
- package/src/meeting/muteState.ts +119 -194
- package/src/meeting/request.ts +122 -115
- package/src/meeting/util.ts +549 -413
- package/src/meeting-info/index.ts +54 -8
- package/src/meeting-info/meeting-info-v2.ts +89 -24
- package/src/meeting-info/utilv2.ts +6 -2
- package/src/meetings/index.ts +247 -87
- package/src/meetings/meetings.types.ts +12 -0
- package/src/meetings/util.ts +47 -12
- package/src/member/index.ts +28 -1
- package/src/member/types.ts +14 -0
- package/src/member/util.ts +75 -26
- package/src/members/index.ts +7 -1
- package/src/members/request.ts +61 -21
- package/src/members/util.ts +316 -326
- package/src/metrics/constants.ts +1 -0
- package/src/metrics/index.ts +1 -474
- package/src/multistream/mediaRequestManager.ts +183 -67
- package/src/multistream/receiveSlot.ts +4 -4
- package/src/multistream/receiveSlotManager.ts +4 -4
- package/src/multistream/remoteMedia.ts +2 -2
- package/src/multistream/remoteMediaGroup.ts +59 -0
- package/src/multistream/remoteMediaManager.ts +33 -0
- package/src/multistream/sendSlotManager.ts +170 -0
- package/src/reachability/index.ts +15 -4
- package/src/reachability/request.ts +7 -3
- package/src/reconnection-manager/index.ts +36 -29
- package/src/recording-controller/index.ts +20 -3
- package/src/recording-controller/util.ts +26 -9
- package/src/roap/index.ts +25 -30
- package/src/roap/request.ts +44 -51
- package/src/roap/turnDiscovery.ts +51 -25
- package/src/rtcMetrics/constants.ts +3 -0
- package/src/rtcMetrics/index.ts +100 -0
- package/src/statsAnalyzer/index.ts +0 -1
- package/test/integration/spec/converged-space-meetings.js +60 -3
- package/test/integration/spec/journey.js +336 -259
- package/test/integration/spec/space-meeting.js +76 -3
- package/test/unit/spec/annotation/index.ts +418 -0
- package/test/unit/spec/breakouts/breakout.ts +85 -26
- package/test/unit/spec/breakouts/events.ts +89 -0
- package/test/unit/spec/breakouts/index.ts +636 -98
- package/test/unit/spec/breakouts/utils.js +19 -1
- package/test/unit/spec/common/queue.js +31 -2
- package/test/unit/spec/controls-options-manager/index.js +8 -1
- package/test/unit/spec/controls-options-manager/util.js +576 -397
- package/test/unit/spec/fixture/locus.js +1 -0
- package/test/unit/spec/interpretation/collection.ts +15 -0
- package/test/unit/spec/interpretation/index.ts +589 -0
- package/test/unit/spec/interpretation/siLanguage.ts +28 -0
- package/test/unit/spec/locus-info/controlsUtils.js +195 -1
- package/test/unit/spec/locus-info/index.js +950 -45
- package/test/unit/spec/locus-info/infoUtils.js +37 -15
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
- package/test/unit/spec/locus-info/parser.js +62 -22
- package/test/unit/spec/locus-info/selfConstant.js +19 -0
- package/test/unit/spec/locus-info/selfUtils.js +131 -26
- package/test/unit/spec/media/index.ts +82 -79
- package/test/unit/spec/meeting/in-meeting-actions.ts +60 -2
- package/test/unit/spec/meeting/index.js +3208 -1734
- package/test/unit/spec/meeting/locusMediaRequest.ts +443 -0
- package/test/unit/spec/meeting/muteState.js +328 -417
- package/test/unit/spec/meeting/request.js +393 -48
- package/test/unit/spec/meeting/utils.js +552 -76
- package/test/unit/spec/meeting-info/index.js +181 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +258 -20
- package/test/unit/spec/meeting-info/utilv2.js +21 -0
- package/test/unit/spec/meetings/index.js +631 -145
- package/test/unit/spec/meetings/utils.js +164 -9
- package/test/unit/spec/member/index.js +44 -14
- package/test/unit/spec/member/util.js +296 -155
- package/test/unit/spec/members/index.js +23 -3
- package/test/unit/spec/members/request.js +167 -35
- package/test/unit/spec/metrics/index.js +1 -50
- package/test/unit/spec/multistream/mediaRequestManager.ts +366 -8
- package/test/unit/spec/multistream/receiveSlot.ts +1 -1
- package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +123 -0
- package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
- package/test/unit/spec/reachability/index.ts +66 -5
- package/test/unit/spec/reachability/request.js +3 -1
- package/test/unit/spec/reconnection-manager/index.js +55 -5
- package/test/unit/spec/recording-controller/index.js +294 -218
- package/test/unit/spec/recording-controller/util.js +223 -96
- package/test/unit/spec/roap/index.ts +21 -48
- package/test/unit/spec/roap/request.ts +74 -60
- package/test/unit/spec/roap/turnDiscovery.ts +30 -6
- package/test/unit/spec/rtcMetrics/index.ts +68 -0
- package/test/utils/integrationTestUtils.js +46 -0
- package/test/utils/testUtils.js +0 -60
- package/src/metrics/config.ts +0 -487
package/src/locus-info/parser.ts
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
import {difference} from 'lodash';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import SortedQueue from '../common/queue';
|
|
4
4
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
5
5
|
|
|
6
|
+
const MAX_OOO_DELTA_COUNT = 5; // when we receive an out-of-order delta and the queue builds up to MAX_OOO_DELTA_COUNT, we do a sync with Locus
|
|
7
|
+
const OOO_DELTA_WAIT_TIME = 10000; // [ms] minimum wait time before we do a sync if we get out-of-order deltas
|
|
8
|
+
const OOO_DELTA_WAIT_TIME_RANDOM_DELAY = 5000; // [ms] max random delay added to OOO_DELTA_WAIT_TIME
|
|
9
|
+
|
|
10
|
+
type LocusDeltaDto = {
|
|
11
|
+
baseSequence: {
|
|
12
|
+
rangeStart: number;
|
|
13
|
+
rangeEnd: number;
|
|
14
|
+
entries: number[];
|
|
15
|
+
};
|
|
16
|
+
sequence: {
|
|
17
|
+
rangeStart: number;
|
|
18
|
+
rangeEnd: number;
|
|
19
|
+
entries: number[];
|
|
20
|
+
};
|
|
21
|
+
syncUrl: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
6
24
|
/**
|
|
7
25
|
* Locus Delta Parser
|
|
8
26
|
* @private
|
|
@@ -10,11 +28,11 @@ import LoggerProxy from '../common/logs/logger-proxy';
|
|
|
10
28
|
*/
|
|
11
29
|
export default class Parser {
|
|
12
30
|
// processing status
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
31
|
+
status:
|
|
32
|
+
| 'IDLE' // not doing anything
|
|
33
|
+
| 'PAUSED' // paused, because we are doing a sync
|
|
34
|
+
| 'WORKING' // processing a delta event
|
|
35
|
+
| 'BLOCKED'; // received an out-of-order delta, so waiting for the missing one
|
|
18
36
|
|
|
19
37
|
// loci comparison states
|
|
20
38
|
static loci = {
|
|
@@ -24,21 +42,59 @@ export default class Parser {
|
|
|
24
42
|
DESYNC: 'DESYNC',
|
|
25
43
|
USE_INCOMING: 'USE_INCOMING',
|
|
26
44
|
USE_CURRENT: 'USE_CURRENT',
|
|
45
|
+
WAIT: 'WAIT',
|
|
27
46
|
ERROR: 'ERROR',
|
|
28
47
|
};
|
|
29
48
|
|
|
30
|
-
queue:
|
|
49
|
+
queue: SortedQueue<LocusDeltaDto>;
|
|
31
50
|
workingCopy: any;
|
|
51
|
+
syncTimer: null | number | NodeJS.Timeout;
|
|
32
52
|
|
|
33
53
|
/**
|
|
34
54
|
* @constructs Parser
|
|
35
55
|
*/
|
|
36
56
|
constructor() {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
const deltaCompareFunc = (left: LocusDeltaDto, right: LocusDeltaDto) => {
|
|
58
|
+
const {LT, GT} = Parser.loci;
|
|
59
|
+
const {extractComparisonState: extract} = Parser;
|
|
60
|
+
|
|
61
|
+
if (Parser.isSequenceEmpty(left)) {
|
|
62
|
+
return -1;
|
|
63
|
+
}
|
|
64
|
+
if (Parser.isSequenceEmpty(right)) {
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
const result = extract(Parser.compareSequence(left.baseSequence, right.baseSequence));
|
|
68
|
+
|
|
69
|
+
if (result === LT) {
|
|
70
|
+
return -1;
|
|
71
|
+
}
|
|
72
|
+
if (result === GT) {
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return 0;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
this.queue = new SortedQueue<LocusDeltaDto>(deltaCompareFunc);
|
|
80
|
+
this.status = 'IDLE';
|
|
40
81
|
this.onDeltaAction = null;
|
|
41
82
|
this.workingCopy = null;
|
|
83
|
+
this.syncTimer = null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Returns a debug string representing a locus delta - useful for logging
|
|
88
|
+
*
|
|
89
|
+
* @param {LocusDeltaDto} locus Locus delta
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
92
|
+
static locus2string(locus: LocusDeltaDto) {
|
|
93
|
+
if (!locus.sequence?.entries) {
|
|
94
|
+
return 'invalid';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return locus.sequence.entries.length ? `seq=${locus.sequence.entries.at(-1)}` : 'empty';
|
|
42
98
|
}
|
|
43
99
|
|
|
44
100
|
/**
|
|
@@ -208,7 +264,7 @@ export default class Parser {
|
|
|
208
264
|
* @returns {string} loci comparison state
|
|
209
265
|
*/
|
|
210
266
|
private static compareDelta(current, incoming) {
|
|
211
|
-
const {LT, GT, EQ, DESYNC, USE_INCOMING} = Parser.loci;
|
|
267
|
+
const {LT, GT, EQ, DESYNC, USE_INCOMING, WAIT} = Parser.loci;
|
|
212
268
|
|
|
213
269
|
const {extractComparisonState: extract} = Parser;
|
|
214
270
|
const {packComparisonResult: pack} = Parser;
|
|
@@ -228,6 +284,17 @@ export default class Parser {
|
|
|
228
284
|
comparison = USE_INCOMING;
|
|
229
285
|
break;
|
|
230
286
|
|
|
287
|
+
case LT:
|
|
288
|
+
if (extract(Parser.compareSequence(incoming.baseSequence, incoming.sequence)) === EQ) {
|
|
289
|
+
// special case where Locus sends a delta with baseSequence === sequence to trigger a sync,
|
|
290
|
+
// because the delta event is too large to be sent over mercury connection
|
|
291
|
+
comparison = DESYNC;
|
|
292
|
+
} else {
|
|
293
|
+
// the incoming locus has baseSequence from the future, so it is out-of-order,
|
|
294
|
+
// we are missing 1 or more locus that should be in front of it, we need to wait for it
|
|
295
|
+
comparison = WAIT;
|
|
296
|
+
}
|
|
297
|
+
break;
|
|
231
298
|
default:
|
|
232
299
|
comparison = DESYNC;
|
|
233
300
|
}
|
|
@@ -235,6 +302,49 @@ export default class Parser {
|
|
|
235
302
|
return pack(comparison, result);
|
|
236
303
|
}
|
|
237
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Compares Locus sequences - it should be called only for full Locus DTOs, not deltas
|
|
307
|
+
*
|
|
308
|
+
* @param {Types~Locus} current Current working copy
|
|
309
|
+
* @param {Types~Locus} incomingFullDto New Full Locus DTO
|
|
310
|
+
* @returns {string} either Parser.loci.USE_INCOMING or Parser.loci.USE_CURRENT
|
|
311
|
+
*/
|
|
312
|
+
static compareFullDtoSequence(current, incomingFullDto) {
|
|
313
|
+
if (Parser.isSequenceEmpty(current) || Parser.isSequenceEmpty(incomingFullDto)) {
|
|
314
|
+
return Parser.loci.USE_INCOMING;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// the sequence.entries list will always contain at least 1 entry
|
|
318
|
+
// https://sqbu-github.cisco.com/WebExSquared/cloud-apps/wiki/Locus-Sequence-Comparison-Algorithm
|
|
319
|
+
|
|
320
|
+
return incomingFullDto.sequence.entries.slice(-1)[0] > current.sequence.entries.slice(-1)[0]
|
|
321
|
+
? Parser.loci.USE_INCOMING
|
|
322
|
+
: Parser.loci.USE_CURRENT;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Returns true if the incoming full locus DTO is newer than the current working copy
|
|
327
|
+
*
|
|
328
|
+
* @param {Types~Locus} incomingFullDto New Full Locus DTO
|
|
329
|
+
* @returns {string} either Parser.loci.USE_INCOMING or Parser.loci.USE_CURRENT
|
|
330
|
+
*/
|
|
331
|
+
isNewFullLocus(incomingFullDto) {
|
|
332
|
+
if (!Parser.isLoci(incomingFullDto)) {
|
|
333
|
+
LoggerProxy.logger.info('Locus-info:parser#isNewFullLocus --> Ignoring non-locus object.');
|
|
334
|
+
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (!this.workingCopy) {
|
|
339
|
+
// we don't have a working copy yet, so any full locus is better than nothing
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const comparisonResult = Parser.compareFullDtoSequence(this.workingCopy, incomingFullDto);
|
|
344
|
+
|
|
345
|
+
return comparisonResult === Parser.loci.USE_INCOMING;
|
|
346
|
+
}
|
|
347
|
+
|
|
238
348
|
/**
|
|
239
349
|
* Compares Locus sequences
|
|
240
350
|
* @param {Types~Locus} current Current working copy
|
|
@@ -393,17 +503,10 @@ export default class Parser {
|
|
|
393
503
|
*/
|
|
394
504
|
isValidLocus(newLoci) {
|
|
395
505
|
let isValid = false;
|
|
396
|
-
const {IDLE} = Parser.status;
|
|
397
506
|
const {isLoci} = Parser;
|
|
398
|
-
// @ts-ignore
|
|
399
|
-
const setStatus = (status) => {
|
|
400
|
-
// @ts-ignore
|
|
401
|
-
this.status = status;
|
|
402
|
-
};
|
|
403
507
|
|
|
404
508
|
// one or both objects are not locus delta events
|
|
405
509
|
if (!isLoci(this.workingCopy) || !isLoci(newLoci)) {
|
|
406
|
-
setStatus(IDLE);
|
|
407
510
|
LoggerProxy.logger.info(
|
|
408
511
|
'Locus-info:parser#processDeltaEvent --> Ignoring non-locus object. workingCopy:',
|
|
409
512
|
this.workingCopy,
|
|
@@ -455,19 +558,25 @@ export default class Parser {
|
|
|
455
558
|
* @returns {undefined}
|
|
456
559
|
*/
|
|
457
560
|
nextEvent() {
|
|
458
|
-
|
|
459
|
-
if (this.status === Parser.status.PAUSED) {
|
|
561
|
+
if (this.status === 'PAUSED') {
|
|
460
562
|
LoggerProxy.logger.info('Locus-info:parser#nextEvent --> Locus parser paused.');
|
|
461
563
|
|
|
462
564
|
return;
|
|
463
565
|
}
|
|
464
566
|
|
|
567
|
+
if (this.status === 'BLOCKED') {
|
|
568
|
+
LoggerProxy.logger.info(
|
|
569
|
+
'Locus-info:parser#nextEvent --> Locus parser blocked by out-of-order delta.'
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
|
|
465
575
|
// continue processing until queue is empty
|
|
466
576
|
if (this.queue.size() > 0) {
|
|
467
577
|
this.processDeltaEvent();
|
|
468
578
|
} else {
|
|
469
|
-
|
|
470
|
-
this.status = Parser.status.IDLE;
|
|
579
|
+
this.status = 'IDLE';
|
|
471
580
|
}
|
|
472
581
|
}
|
|
473
582
|
|
|
@@ -478,7 +587,7 @@ export default class Parser {
|
|
|
478
587
|
* @param {Types~Locus} locus Locus delta
|
|
479
588
|
* @returns {undefined}
|
|
480
589
|
*/
|
|
481
|
-
// eslint-disable-next-line no-unused-vars
|
|
590
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
482
591
|
onDeltaAction(action: string, locus) {}
|
|
483
592
|
|
|
484
593
|
/**
|
|
@@ -489,15 +598,20 @@ export default class Parser {
|
|
|
489
598
|
onDeltaEvent(loci) {
|
|
490
599
|
// enqueue the new loci
|
|
491
600
|
this.queue.enqueue(loci);
|
|
492
|
-
// start processing events in the queue if idle
|
|
493
|
-
// and a function handler is defined
|
|
494
|
-
// @ts-ignore
|
|
495
|
-
if (this.status === Parser.status.IDLE && this.onDeltaAction) {
|
|
496
|
-
// Update status, ensure we only process one event at a time.
|
|
497
|
-
// @ts-ignore
|
|
498
|
-
this.status = Parser.status.WORKING;
|
|
499
601
|
|
|
500
|
-
|
|
602
|
+
if (this.onDeltaAction) {
|
|
603
|
+
if (this.status === 'BLOCKED') {
|
|
604
|
+
if (this.queue.size() > MAX_OOO_DELTA_COUNT) {
|
|
605
|
+
this.triggerSync('queue too big, blocked on out-of-order delta');
|
|
606
|
+
} else {
|
|
607
|
+
this.processDeltaEvent();
|
|
608
|
+
}
|
|
609
|
+
} else if (this.status === 'IDLE') {
|
|
610
|
+
// Update status, ensure we only process one event at a time.
|
|
611
|
+
this.status = 'WORKING';
|
|
612
|
+
|
|
613
|
+
this.processDeltaEvent();
|
|
614
|
+
}
|
|
501
615
|
}
|
|
502
616
|
}
|
|
503
617
|
|
|
@@ -516,11 +630,55 @@ export default class Parser {
|
|
|
516
630
|
* @returns {undefined}
|
|
517
631
|
*/
|
|
518
632
|
pause() {
|
|
519
|
-
|
|
520
|
-
this.status = Parser.status.PAUSED;
|
|
633
|
+
this.status = 'PAUSED';
|
|
521
634
|
LoggerProxy.logger.info('Locus-info:parser#pause --> Locus parser paused.');
|
|
522
635
|
}
|
|
523
636
|
|
|
637
|
+
/**
|
|
638
|
+
* Triggers a sync with Locus
|
|
639
|
+
*
|
|
640
|
+
* @param {string} reason used just for logging
|
|
641
|
+
* @returns {undefined}
|
|
642
|
+
*/
|
|
643
|
+
private triggerSync(reason: string) {
|
|
644
|
+
LoggerProxy.logger.info(`Locus-info:parser#triggerSync --> doing sync, reason: ${reason}`);
|
|
645
|
+
this.stopSyncTimer();
|
|
646
|
+
this.pause();
|
|
647
|
+
this.onDeltaAction(Parser.loci.DESYNC, this.workingCopy);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Starts a timer with a random delay. When that timer expires we will do a sync.
|
|
652
|
+
*
|
|
653
|
+
* The main purpose of this timer is to handle a case when we get some out-of-order deltas,
|
|
654
|
+
* so we start waiting to receive the missing delta. If that delta never arrives, this timer
|
|
655
|
+
* will trigger a sync with Locus.
|
|
656
|
+
*
|
|
657
|
+
* @returns {undefined}
|
|
658
|
+
*/
|
|
659
|
+
private startSyncTimer() {
|
|
660
|
+
if (this.syncTimer === null) {
|
|
661
|
+
const timeout = OOO_DELTA_WAIT_TIME + Math.random() * OOO_DELTA_WAIT_TIME_RANDOM_DELAY;
|
|
662
|
+
|
|
663
|
+
this.syncTimer = setTimeout(() => {
|
|
664
|
+
this.syncTimer = null;
|
|
665
|
+
this.triggerSync('timer expired, blocked on out-of-order delta');
|
|
666
|
+
}, timeout);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Stops the timer for triggering a sync
|
|
672
|
+
*
|
|
673
|
+
* @returns {undefined}
|
|
674
|
+
*/
|
|
675
|
+
private stopSyncTimer() {
|
|
676
|
+
if (this.syncTimer !== null) {
|
|
677
|
+
clearTimeout(this.syncTimer);
|
|
678
|
+
this.syncTimer = null;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
524
682
|
/**
|
|
525
683
|
* Processes next locus delta in the queue,
|
|
526
684
|
* continues until the queue is empty
|
|
@@ -528,11 +686,13 @@ export default class Parser {
|
|
|
528
686
|
* @returns {undefined}
|
|
529
687
|
*/
|
|
530
688
|
processDeltaEvent() {
|
|
531
|
-
const {DESYNC, USE_INCOMING} = Parser.loci;
|
|
689
|
+
const {DESYNC, USE_INCOMING, WAIT} = Parser.loci;
|
|
532
690
|
const {extractComparisonState: extract} = Parser;
|
|
533
691
|
const newLoci = this.queue.dequeue();
|
|
534
692
|
|
|
535
693
|
if (!this.isValidLocus(newLoci)) {
|
|
694
|
+
this.nextEvent();
|
|
695
|
+
|
|
536
696
|
return;
|
|
537
697
|
}
|
|
538
698
|
|
|
@@ -543,6 +703,8 @@ export default class Parser {
|
|
|
543
703
|
// for full debugging.
|
|
544
704
|
LoggerProxy.logger.debug(`Locus-info:parser#processDeltaEvent --> Locus Debug: ${result}`);
|
|
545
705
|
|
|
706
|
+
let needToWait = false;
|
|
707
|
+
|
|
546
708
|
if (lociComparison === DESYNC) {
|
|
547
709
|
// wait for desync response
|
|
548
710
|
this.pause();
|
|
@@ -551,15 +713,39 @@ export default class Parser {
|
|
|
551
713
|
// Note: The working copy of parser gets updated in .onFullLocus()
|
|
552
714
|
// and here when USE_INCOMING locus.
|
|
553
715
|
this.workingCopy = newLoci;
|
|
716
|
+
} else if (lociComparison === WAIT) {
|
|
717
|
+
// we've taken newLoci from the front of the queue, so put it back there as we have to wait
|
|
718
|
+
// for the one that should be in front of it, before we can process it
|
|
719
|
+
this.queue.enqueue(newLoci);
|
|
720
|
+
needToWait = true;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (needToWait) {
|
|
724
|
+
this.status = 'BLOCKED';
|
|
725
|
+
this.startSyncTimer();
|
|
726
|
+
} else {
|
|
727
|
+
this.stopSyncTimer();
|
|
728
|
+
|
|
729
|
+
if (this.status === 'BLOCKED') {
|
|
730
|
+
// we are not blocked anymore
|
|
731
|
+
this.status = 'WORKING';
|
|
732
|
+
|
|
733
|
+
LoggerProxy.logger.info(
|
|
734
|
+
`Locus-info:parser#processDeltaEvent --> received delta that we were waiting for ${Parser.locus2string(
|
|
735
|
+
newLoci
|
|
736
|
+
)}, not blocked anymore`
|
|
737
|
+
);
|
|
738
|
+
}
|
|
554
739
|
}
|
|
555
740
|
|
|
556
741
|
if (this.onDeltaAction) {
|
|
557
742
|
LoggerProxy.logger.info(
|
|
558
|
-
`Locus-info:parser#processDeltaEvent --> Locus Delta
|
|
743
|
+
`Locus-info:parser#processDeltaEvent --> Locus Delta ${Parser.locus2string(
|
|
744
|
+
newLoci
|
|
745
|
+
)}, Action: ${lociComparison}`
|
|
559
746
|
);
|
|
560
747
|
|
|
561
|
-
|
|
562
|
-
this.onDeltaAction.call(this, lociComparison, newLoci);
|
|
748
|
+
this.onDeltaAction(lociComparison, newLoci);
|
|
563
749
|
}
|
|
564
750
|
|
|
565
751
|
this.nextEvent();
|
|
@@ -571,8 +757,7 @@ export default class Parser {
|
|
|
571
757
|
*/
|
|
572
758
|
resume() {
|
|
573
759
|
LoggerProxy.logger.info('Locus-info:parser#resume --> Locus parser resumed.');
|
|
574
|
-
|
|
575
|
-
this.status = Parser.status.WORKING;
|
|
760
|
+
this.status = 'WORKING';
|
|
576
761
|
this.nextEvent();
|
|
577
762
|
}
|
|
578
763
|
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
AUDIO,
|
|
15
15
|
VIDEO,
|
|
16
16
|
MediaContent,
|
|
17
|
-
SELF_ROLES,
|
|
18
17
|
} from '../constants';
|
|
19
18
|
import ParameterError from '../common/errors/parameter';
|
|
20
19
|
|
|
@@ -37,6 +36,7 @@ SelfUtils.parse = (self: any, deviceId: string) => {
|
|
|
37
36
|
remoteMuted: SelfUtils.getRemoteMuted(self),
|
|
38
37
|
unmuteAllowed: SelfUtils.getUnmuteAllowed(self),
|
|
39
38
|
localAudioUnmuteRequested: SelfUtils.getLocalAudioUnmuteRequested(self),
|
|
39
|
+
localAudioUnmuteRequestedTimeStamp: SelfUtils.getLocalAudioUnmuteRequestedTimeStamp(self),
|
|
40
40
|
localAudioUnmuteRequired: SelfUtils.getLocalAudioUnmuteRequired(self),
|
|
41
41
|
lastModified: SelfUtils.getLastModified(self),
|
|
42
42
|
modifiedBy: SelfUtils.getModifiedBy(self),
|
|
@@ -65,6 +65,7 @@ SelfUtils.parse = (self: any, deviceId: string) => {
|
|
|
65
65
|
isSharingBlocked: SelfUtils.isSharingBlocked(self),
|
|
66
66
|
breakoutSessions: SelfUtils.getBreakoutSessions(self),
|
|
67
67
|
breakout: SelfUtils.getBreakout(self),
|
|
68
|
+
interpretation: SelfUtils.getInterpretation(self),
|
|
68
69
|
};
|
|
69
70
|
}
|
|
70
71
|
|
|
@@ -73,6 +74,7 @@ SelfUtils.parse = (self: any, deviceId: string) => {
|
|
|
73
74
|
|
|
74
75
|
SelfUtils.getBreakoutSessions = (self) => self?.controls?.breakout?.sessions;
|
|
75
76
|
SelfUtils.getBreakout = (self) => self?.controls?.breakout;
|
|
77
|
+
SelfUtils.getInterpretation = (self) => self?.controls?.interpretation;
|
|
76
78
|
|
|
77
79
|
SelfUtils.getLayout = (self) =>
|
|
78
80
|
Array.isArray(self?.controls?.layouts) ? self.controls.layouts[0].type : undefined;
|
|
@@ -108,7 +110,7 @@ SelfUtils.getSelves = (oldSelf, newSelf, deviceId) => {
|
|
|
108
110
|
current
|
|
109
111
|
);
|
|
110
112
|
updates.moderatorChanged = SelfUtils.moderatorChanged(previous, current);
|
|
111
|
-
updates.
|
|
113
|
+
updates.isRolesChanged = SelfUtils.isRolesChanged(previous, current);
|
|
112
114
|
updates.isMediaInactiveOrReleased = SelfUtils.wasMediaInactiveOrReleased(previous, current);
|
|
113
115
|
updates.isUserObserving = SelfUtils.isDeviceObserving(previous, current);
|
|
114
116
|
updates.layoutChanged = SelfUtils.layoutChanged(previous, current);
|
|
@@ -125,6 +127,7 @@ SelfUtils.getSelves = (oldSelf, newSelf, deviceId) => {
|
|
|
125
127
|
previous?.canNotViewTheParticipantList !== current.canNotViewTheParticipantList;
|
|
126
128
|
updates.isSharingBlockedChanged = previous?.isSharingBlocked !== current.isSharingBlocked;
|
|
127
129
|
updates.breakoutsChanged = SelfUtils.breakoutsChanged(previous, current);
|
|
130
|
+
updates.interpretationChanged = SelfUtils.interpretationChanged(previous, current);
|
|
128
131
|
|
|
129
132
|
return {
|
|
130
133
|
previous,
|
|
@@ -153,6 +156,9 @@ SelfUtils.layoutChanged = (previous: any, current: any) =>
|
|
|
153
156
|
SelfUtils.breakoutsChanged = (previous, current) =>
|
|
154
157
|
!isEqual(previous?.breakoutSessions, current?.breakoutSessions) && !!current?.breakout;
|
|
155
158
|
|
|
159
|
+
SelfUtils.interpretationChanged = (previous, current) =>
|
|
160
|
+
!isEqual(previous?.interpretation, current?.interpretation) && !!current?.interpretation;
|
|
161
|
+
|
|
156
162
|
SelfUtils.isMediaInactive = (previous, current) => {
|
|
157
163
|
if (
|
|
158
164
|
previous &&
|
|
@@ -270,6 +276,10 @@ SelfUtils.getRemoteMuted = (self: any) => {
|
|
|
270
276
|
|
|
271
277
|
SelfUtils.getLocalAudioUnmuteRequested = (self) => !!self?.controls?.audio?.requestedToUnmute;
|
|
272
278
|
|
|
279
|
+
// requestedToUnmute timestamp
|
|
280
|
+
SelfUtils.getLocalAudioUnmuteRequestedTimeStamp = (self) =>
|
|
281
|
+
Date.parse(self?.controls?.audio?.lastModifiedRequestedToUnmute) || 0;
|
|
282
|
+
|
|
273
283
|
SelfUtils.getUnmuteAllowed = (self) => {
|
|
274
284
|
if (!self || !self.controls || !self.controls.audio) {
|
|
275
285
|
return null;
|
|
@@ -340,30 +350,19 @@ SelfUtils.moderatorChanged = (oldSelf, changedSelf) => {
|
|
|
340
350
|
};
|
|
341
351
|
|
|
342
352
|
/**
|
|
353
|
+
* determine whether the roles of self is changed or not
|
|
343
354
|
* @param {Object} oldSelf
|
|
344
355
|
* @param {Object} changedSelf
|
|
345
356
|
* @returns {Boolean}
|
|
346
|
-
* @throws {Error} if changed self was undefined
|
|
347
357
|
*/
|
|
348
|
-
SelfUtils.
|
|
349
|
-
if (!oldSelf) {
|
|
350
|
-
return false;
|
|
351
|
-
}
|
|
358
|
+
SelfUtils.isRolesChanged = (oldSelf, changedSelf) => {
|
|
352
359
|
if (!changedSelf) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
);
|
|
360
|
+
// no new self means no change
|
|
361
|
+
return false;
|
|
356
362
|
}
|
|
357
|
-
const isAttendeeOnly =
|
|
358
|
-
oldSelf.roles.includes(SELF_ROLES.ATTENDEE) &&
|
|
359
|
-
!oldSelf.roles.includes(SELF_ROLES.COHOST) &&
|
|
360
|
-
!oldSelf.roles.includes(SELF_ROLES.MODERATOR);
|
|
361
|
-
const isCohost = changedSelf.roles.includes(SELF_ROLES.COHOST);
|
|
362
|
-
const isModerator = changedSelf.roles.includes(SELF_ROLES.MODERATOR);
|
|
363
|
-
|
|
364
|
-
return isAttendeeOnly && (isCohost || isModerator);
|
|
365
|
-
};
|
|
366
363
|
|
|
364
|
+
return !isEqual(oldSelf?.roles, changedSelf?.roles);
|
|
365
|
+
};
|
|
367
366
|
/**
|
|
368
367
|
* @param {Object} oldSelf
|
|
369
368
|
* @param {Object} changedSelf
|
|
@@ -443,7 +442,10 @@ SelfUtils.localAudioUnmuteRequestedByServer = (oldSelf: any = {}, changedSelf: a
|
|
|
443
442
|
);
|
|
444
443
|
}
|
|
445
444
|
|
|
446
|
-
return
|
|
445
|
+
return (
|
|
446
|
+
changedSelf.localAudioUnmuteRequested &&
|
|
447
|
+
changedSelf.localAudioUnmuteRequestedTimeStamp > oldSelf.localAudioUnmuteRequestedTimeStamp
|
|
448
|
+
);
|
|
447
449
|
};
|
|
448
450
|
|
|
449
451
|
SelfUtils.localAudioUnmuteRequiredByServer = (oldSelf: any = {}, changedSelf: any) => {
|
|
@@ -496,4 +498,14 @@ SelfUtils.getMediaStatus = (mediaSessions = []) => {
|
|
|
496
498
|
return mediaStatus;
|
|
497
499
|
};
|
|
498
500
|
|
|
501
|
+
SelfUtils.getReplacedBreakoutMoveId = (self: any, deviceId: string) => {
|
|
502
|
+
if (self && Array.isArray(self.devices)) {
|
|
503
|
+
const joinedDevice = self.devices.find((device) => deviceId === device.url);
|
|
504
|
+
if (Array.isArray(joinedDevice?.replaces)) {
|
|
505
|
+
return joinedDevice.replaces[0]?.breakoutMoveId;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return null;
|
|
510
|
+
};
|
|
499
511
|
export default SelfUtils;
|