@webex/plugin-meetings 3.12.0-next.2 → 3.12.0-next.21
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/aiEnableRequest/index.js +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/controls-options-manager/constants.js +11 -1
- package/dist/controls-options-manager/constants.js.map +1 -1
- package/dist/controls-options-manager/index.js +23 -21
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/util.js +91 -0
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/hashTree/constants.js +10 -1
- package/dist/hashTree/constants.js.map +1 -1
- package/dist/hashTree/hashTreeParser.js +56 -31
- package/dist/hashTree/hashTreeParser.js.map +1 -1
- package/dist/hashTree/utils.js +22 -0
- package/dist/hashTree/utils.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +51 -23
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/index.js +372 -292
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +1 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +8 -9
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/util.js +21 -2
- package/dist/meetings/util.js.map +1 -1
- package/dist/metrics/constants.js +5 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +116 -2
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/types/controls-options-manager/constants.d.ts +6 -1
- package/dist/types/hashTree/constants.d.ts +1 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +12 -2
- package/dist/types/hashTree/utils.d.ts +11 -0
- package/dist/types/locus-info/index.d.ts +9 -5
- package/dist/types/meeting/index.d.ts +11 -0
- package/dist/types/metrics/constants.d.ts +4 -0
- package/dist/types/multistream/sendSlotManager.d.ts +23 -1
- package/dist/webinar/index.js +301 -226
- package/dist/webinar/index.js.map +1 -1
- package/package.json +16 -16
- package/src/controls-options-manager/constants.ts +14 -1
- package/src/controls-options-manager/index.ts +26 -19
- package/src/controls-options-manager/util.ts +81 -1
- package/src/hashTree/constants.ts +9 -0
- package/src/hashTree/hashTreeParser.ts +60 -36
- package/src/hashTree/utils.ts +17 -0
- package/src/locus-info/index.ts +56 -30
- package/src/meeting/index.ts +98 -11
- package/src/meeting/util.ts +1 -0
- package/src/meetings/index.ts +15 -16
- package/src/meetings/util.ts +26 -1
- package/src/metrics/constants.ts +5 -0
- package/src/multistream/sendSlotManager.ts +97 -3
- package/src/webinar/index.ts +75 -1
- package/test/unit/spec/controls-options-manager/index.js +114 -6
- package/test/unit/spec/controls-options-manager/util.js +165 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +441 -30
- package/test/unit/spec/hashTree/utils.ts +88 -1
- package/test/unit/spec/locus-info/index.js +75 -27
- package/test/unit/spec/meeting/index.js +54 -36
- package/test/unit/spec/meeting/utils.js +4 -0
- package/test/unit/spec/meetings/index.js +36 -3
- package/test/unit/spec/meetings/utils.js +108 -0
- package/test/unit/spec/multistream/sendSlotManager.ts +135 -36
- package/test/unit/spec/webinar/index.ts +60 -0
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import {HashTreeObject, ObjectType} from '../../../../src/hashTree/types';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
deleteNestedObjectsWithHtMeta,
|
|
4
|
+
isSelf,
|
|
5
|
+
sortByInitPriority,
|
|
6
|
+
} from '../../../../src/hashTree/utils';
|
|
7
|
+
import {DataSetNames, DATA_SET_INIT_PRIORITY} from '../../../../src/hashTree/constants';
|
|
3
8
|
|
|
4
9
|
import {assert} from '@webex/test-helper-chai';
|
|
5
10
|
|
|
@@ -137,4 +142,86 @@ describe('Hash Tree Utils', () => {
|
|
|
137
142
|
assert.isFalse(isSelf(participantObject));
|
|
138
143
|
});
|
|
139
144
|
});
|
|
145
|
+
|
|
146
|
+
describe('#sortByInitPriority', () => {
|
|
147
|
+
[
|
|
148
|
+
{
|
|
149
|
+
description: 'places "main" and "self" first when both appear',
|
|
150
|
+
input: ['atd-active', 'main', 'atd-unmuted', 'self'],
|
|
151
|
+
expected: ['main', 'self', 'atd-active', 'atd-unmuted'],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
description: 'preserves original order of non-priority items',
|
|
155
|
+
input: ['atd-unmuted', 'atd-active', 'self'],
|
|
156
|
+
expected: ['self', 'atd-unmuted', 'atd-active'],
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
description: 'returns items unchanged when no priority items present',
|
|
160
|
+
input: ['atd-active', 'atd-unmuted'],
|
|
161
|
+
expected: ['atd-active', 'atd-unmuted'],
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
description: 'reorders when only priority items present',
|
|
165
|
+
input: ['self', 'main'],
|
|
166
|
+
expected: ['main', 'self'],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
description: 'handles empty list',
|
|
170
|
+
input: [],
|
|
171
|
+
expected: [],
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
description: 'handles only some priority items present',
|
|
175
|
+
input: ['atd-active', 'main'],
|
|
176
|
+
expected: ['main', 'atd-active'],
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
description: 'handles single non-priority item',
|
|
180
|
+
input: ['atd-active'],
|
|
181
|
+
expected: ['atd-active'],
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
description: 'handles single priority item',
|
|
185
|
+
input: ['self'],
|
|
186
|
+
expected: ['self'],
|
|
187
|
+
},
|
|
188
|
+
].forEach(({description, input, expected}) => {
|
|
189
|
+
it(description, () => {
|
|
190
|
+
const items = input.map((name) => ({name}));
|
|
191
|
+
|
|
192
|
+
const result = sortByInitPriority(items, DATA_SET_INIT_PRIORITY);
|
|
193
|
+
|
|
194
|
+
assert.deepEqual(
|
|
195
|
+
result.map((i) => i.name),
|
|
196
|
+
expected
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should not mutate the original array', () => {
|
|
202
|
+
const items = [{name: DataSetNames.ATD_ACTIVE}, {name: DataSetNames.SELF}];
|
|
203
|
+
const originalOrder = items.map((i) => i.name);
|
|
204
|
+
|
|
205
|
+
sortByInitPriority(items, DATA_SET_INIT_PRIORITY);
|
|
206
|
+
|
|
207
|
+
assert.deepEqual(
|
|
208
|
+
items.map((i) => i.name),
|
|
209
|
+
originalOrder
|
|
210
|
+
);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should preserve extra properties on items', () => {
|
|
214
|
+
const items = [
|
|
215
|
+
{name: DataSetNames.ATD_ACTIVE, url: 'url1'},
|
|
216
|
+
{name: DataSetNames.SELF, url: 'url2'},
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
const result = sortByInitPriority(items, DATA_SET_INIT_PRIORITY);
|
|
220
|
+
|
|
221
|
+
assert.deepEqual(result, [
|
|
222
|
+
{name: DataSetNames.SELF, url: 'url2'},
|
|
223
|
+
{name: DataSetNames.ATD_ACTIVE, url: 'url1'},
|
|
224
|
+
]);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
140
227
|
});
|
|
@@ -413,7 +413,7 @@ describe('plugin-meetings', () => {
|
|
|
413
413
|
};
|
|
414
414
|
|
|
415
415
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
416
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
416
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
417
417
|
updatedObjects: [{htMeta: {elementId: {type: 'self'}}, data: newSelf}],
|
|
418
418
|
});
|
|
419
419
|
|
|
@@ -440,7 +440,7 @@ describe('plugin-meetings', () => {
|
|
|
440
440
|
locusInfo.info.isWebinar = true;
|
|
441
441
|
|
|
442
442
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
443
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
443
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
444
444
|
updatedObjects: [{htMeta: {elementId: {type: 'self'}}, data: newSelf}],
|
|
445
445
|
});
|
|
446
446
|
|
|
@@ -473,7 +473,7 @@ describe('plugin-meetings', () => {
|
|
|
473
473
|
locusInfo.info.isWebinar = true;
|
|
474
474
|
|
|
475
475
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
476
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
476
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
477
477
|
updatedObjects: [{htMeta: {elementId: {type: 'self'}}, data: newSelf}],
|
|
478
478
|
});
|
|
479
479
|
|
|
@@ -501,7 +501,7 @@ describe('plugin-meetings', () => {
|
|
|
501
501
|
};
|
|
502
502
|
|
|
503
503
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
504
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
504
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
505
505
|
updatedObjects: [{htMeta: {elementId: {type: 'fullState'}}, data: newFullState}],
|
|
506
506
|
});
|
|
507
507
|
|
|
@@ -519,7 +519,7 @@ describe('plugin-meetings', () => {
|
|
|
519
519
|
};
|
|
520
520
|
|
|
521
521
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
522
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
522
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
523
523
|
updatedObjects: [{htMeta: {elementId: {type: 'info'}}, data: newInfo}],
|
|
524
524
|
});
|
|
525
525
|
|
|
@@ -537,7 +537,7 @@ describe('plugin-meetings', () => {
|
|
|
537
537
|
};
|
|
538
538
|
|
|
539
539
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
540
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
540
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
541
541
|
updatedObjects: [{htMeta: {elementId: {type: 'links'}}, data: newLinks}],
|
|
542
542
|
});
|
|
543
543
|
|
|
@@ -557,7 +557,7 @@ describe('plugin-meetings', () => {
|
|
|
557
557
|
};
|
|
558
558
|
|
|
559
559
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
560
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
560
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
561
561
|
updatedObjects: [{htMeta: newLocusHtMeta, data: newLocus}],
|
|
562
562
|
});
|
|
563
563
|
|
|
@@ -590,7 +590,7 @@ describe('plugin-meetings', () => {
|
|
|
590
590
|
};
|
|
591
591
|
|
|
592
592
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
593
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
593
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
594
594
|
updatedObjects: [
|
|
595
595
|
{
|
|
596
596
|
htMeta: newLocusHtMeta,
|
|
@@ -637,7 +637,7 @@ describe('plugin-meetings', () => {
|
|
|
637
637
|
};
|
|
638
638
|
|
|
639
639
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
640
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
640
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
641
641
|
updatedObjects: [
|
|
642
642
|
// first, a removal of LOCUS object
|
|
643
643
|
{htMeta: {elementId: {type: 'locus'}}, data: null},
|
|
@@ -671,7 +671,7 @@ describe('plugin-meetings', () => {
|
|
|
671
671
|
const newLocusHtMeta = {elementId: {type: 'locus', version: 99}};
|
|
672
672
|
|
|
673
673
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
674
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
674
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
675
675
|
updatedObjects: [
|
|
676
676
|
// first, an update
|
|
677
677
|
{htMeta: newLocusHtMeta, data: newLocus},
|
|
@@ -700,7 +700,7 @@ describe('plugin-meetings', () => {
|
|
|
700
700
|
};
|
|
701
701
|
|
|
702
702
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
703
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
703
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
704
704
|
updatedObjects: [
|
|
705
705
|
// first, an update
|
|
706
706
|
{htMeta: {elementId: {type: 'locus'}}, data: newLocus1},
|
|
@@ -730,7 +730,7 @@ describe('plugin-meetings', () => {
|
|
|
730
730
|
};
|
|
731
731
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
732
732
|
// with 1 participant added, 1 updated, and 1 removed
|
|
733
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
733
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
734
734
|
updatedObjects: [
|
|
735
735
|
{htMeta: {elementId: {type: 'participant', id: 'fake-ht-participant-1'}}, data: null},
|
|
736
736
|
{
|
|
@@ -774,7 +774,7 @@ describe('plugin-meetings', () => {
|
|
|
774
774
|
};
|
|
775
775
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
776
776
|
// with 1 participant added, 1 updated, and 1 removed
|
|
777
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
777
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
778
778
|
updatedObjects: [
|
|
779
779
|
{htMeta: {elementId: {type: 'mediashare', id: 'fake-ht-mediaShare-1'}}, data: null},
|
|
780
780
|
{
|
|
@@ -807,7 +807,7 @@ describe('plugin-meetings', () => {
|
|
|
807
807
|
};
|
|
808
808
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
809
809
|
// with 1 embedded app added, 1 updated, and 1 removed
|
|
810
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
810
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
811
811
|
updatedObjects: [
|
|
812
812
|
{htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-1'}}, data: null},
|
|
813
813
|
{
|
|
@@ -844,7 +844,7 @@ describe('plugin-meetings', () => {
|
|
|
844
844
|
};
|
|
845
845
|
|
|
846
846
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
847
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
847
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
848
848
|
updatedObjects: [
|
|
849
849
|
{
|
|
850
850
|
htMeta: {elementId: {type: 'mediashare', id: 'fake-ht-mediaShare-2'}},
|
|
@@ -883,7 +883,7 @@ describe('plugin-meetings', () => {
|
|
|
883
883
|
};
|
|
884
884
|
|
|
885
885
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
886
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
886
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
887
887
|
updatedObjects: [
|
|
888
888
|
{
|
|
889
889
|
htMeta: {elementId: {type: 'controlentry', id: 'control-1'}},
|
|
@@ -911,7 +911,7 @@ describe('plugin-meetings', () => {
|
|
|
911
911
|
|
|
912
912
|
it('should process locus update correctly when CONTROL object is received with no data', () => {
|
|
913
913
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
914
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
914
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
915
915
|
updatedObjects: [
|
|
916
916
|
{
|
|
917
917
|
htMeta: {elementId: {type: 'controlentry', id: 'some-control-id'}},
|
|
@@ -935,7 +935,7 @@ describe('plugin-meetings', () => {
|
|
|
935
935
|
const destroyStub = sinon.stub(locusInfo.webex.meetings, 'destroy');
|
|
936
936
|
|
|
937
937
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
938
|
-
locusInfoUpdateCallback(MEETING_ENDED);
|
|
938
|
+
locusInfoUpdateCallback({updateType: MEETING_ENDED});
|
|
939
939
|
|
|
940
940
|
assert.calledOnceWithExactly(collectionGetStub, locusInfo.meetingId);
|
|
941
941
|
assert.calledOnceWithExactly(
|
|
@@ -953,7 +953,7 @@ describe('plugin-meetings', () => {
|
|
|
953
953
|
const destroyStub = sinon.stub(locusInfo.webex.meetings, 'destroy');
|
|
954
954
|
|
|
955
955
|
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
956
|
-
locusInfoUpdateCallback(MEETING_ENDED);
|
|
956
|
+
locusInfoUpdateCallback({updateType: MEETING_ENDED});
|
|
957
957
|
|
|
958
958
|
assert.calledOnceWithExactly(collectionGetStub, locusInfo.meetingId);
|
|
959
959
|
assert.notCalled(destroyStub);
|
|
@@ -963,7 +963,7 @@ describe('plugin-meetings', () => {
|
|
|
963
963
|
const createdHashTreeParser = locusInfo.hashTreeParsers.get('fake-locus-url');
|
|
964
964
|
createdHashTreeParser.initializedFromHashTree = false;
|
|
965
965
|
|
|
966
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
966
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
967
967
|
updatedObjects: [
|
|
968
968
|
{
|
|
969
969
|
htMeta: {elementId: {type: 'self'}},
|
|
@@ -978,7 +978,7 @@ describe('plugin-meetings', () => {
|
|
|
978
978
|
});
|
|
979
979
|
|
|
980
980
|
it('should set forceReplaceMembers to false on subsequent updates (initializedFromHashTree is true)', () => {
|
|
981
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
981
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
982
982
|
updatedObjects: [
|
|
983
983
|
{
|
|
984
984
|
htMeta: {elementId: {type: 'self'}},
|
|
@@ -994,7 +994,7 @@ describe('plugin-meetings', () => {
|
|
|
994
994
|
it('should copy participant data to self when participant matches self identity and state is LEFT with reason MOVED', () => {
|
|
995
995
|
locusInfo.self = {id: 'fake-self', identity: 'user-123'};
|
|
996
996
|
|
|
997
|
-
locusInfoUpdateCallback(OBJECTS_UPDATED,
|
|
997
|
+
locusInfoUpdateCallback({updateType: OBJECTS_UPDATED,
|
|
998
998
|
updatedObjects: [
|
|
999
999
|
{
|
|
1000
1000
|
htMeta: {elementId: {type: 'participant', id: 99}},
|
|
@@ -2024,7 +2024,7 @@ describe('plugin-meetings', () => {
|
|
|
2024
2024
|
function: 'updateSelf',
|
|
2025
2025
|
},
|
|
2026
2026
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2027
|
-
{muted: true, unmuteAllowed: true}
|
|
2027
|
+
{muted: true, unmuteAllowed: true, modifiedBy: null}
|
|
2028
2028
|
);
|
|
2029
2029
|
|
|
2030
2030
|
// but sometimes "previous self" is defined, but without controls.audio.muted, so we test this here:
|
|
@@ -2039,7 +2039,7 @@ describe('plugin-meetings', () => {
|
|
|
2039
2039
|
function: 'updateSelf',
|
|
2040
2040
|
},
|
|
2041
2041
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2042
|
-
{muted: true, unmuteAllowed: true}
|
|
2042
|
+
{muted: true, unmuteAllowed: true, modifiedBy: null}
|
|
2043
2043
|
);
|
|
2044
2044
|
});
|
|
2045
2045
|
|
|
@@ -2098,7 +2098,7 @@ describe('plugin-meetings', () => {
|
|
|
2098
2098
|
function: 'updateSelf',
|
|
2099
2099
|
},
|
|
2100
2100
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2101
|
-
{muted: true, unmuteAllowed: true}
|
|
2101
|
+
{muted: true, unmuteAllowed: true, modifiedBy: null}
|
|
2102
2102
|
);
|
|
2103
2103
|
});
|
|
2104
2104
|
|
|
@@ -2237,7 +2237,7 @@ describe('plugin-meetings', () => {
|
|
|
2237
2237
|
function: 'updateSelf',
|
|
2238
2238
|
},
|
|
2239
2239
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2240
|
-
{muted: true, unmuteAllowed: false}
|
|
2240
|
+
{muted: true, unmuteAllowed: false, modifiedBy: null}
|
|
2241
2241
|
);
|
|
2242
2242
|
|
|
2243
2243
|
// now change only disallowUnmute
|
|
@@ -2255,7 +2255,28 @@ describe('plugin-meetings', () => {
|
|
|
2255
2255
|
function: 'updateSelf',
|
|
2256
2256
|
},
|
|
2257
2257
|
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2258
|
-
{muted: true, unmuteAllowed: true}
|
|
2258
|
+
{muted: true, unmuteAllowed: true, modifiedBy: null}
|
|
2259
|
+
);
|
|
2260
|
+
});
|
|
2261
|
+
|
|
2262
|
+
it('should include modifiedBy in payload when muted by host', () => {
|
|
2263
|
+
locusInfo.webex.internal.device.url = self.deviceUrl;
|
|
2264
|
+
locusInfo.updateSelf(self);
|
|
2265
|
+
const newSelf = cloneDeep(self);
|
|
2266
|
+
newSelf.controls.audio.muted = true;
|
|
2267
|
+
newSelf.controls.audio.meta = {modifiedBy: 'host-uuid-123'};
|
|
2268
|
+
|
|
2269
|
+
locusInfo.emitScoped = sinon.stub();
|
|
2270
|
+
locusInfo.updateSelf(newSelf);
|
|
2271
|
+
|
|
2272
|
+
assert.calledWith(
|
|
2273
|
+
locusInfo.emitScoped,
|
|
2274
|
+
{
|
|
2275
|
+
file: 'locus-info',
|
|
2276
|
+
function: 'updateSelf',
|
|
2277
|
+
},
|
|
2278
|
+
LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED,
|
|
2279
|
+
{muted: true, unmuteAllowed: true, modifiedBy: 'host-uuid-123'}
|
|
2259
2280
|
);
|
|
2260
2281
|
});
|
|
2261
2282
|
|
|
@@ -3161,6 +3182,7 @@ describe('plugin-meetings', () => {
|
|
|
3161
3182
|
const createSelfElementWithReplaces = (replacedLocusUrl, replacedAt) => ({
|
|
3162
3183
|
htMeta: {elementId: {type: 'Self'}},
|
|
3163
3184
|
data: {
|
|
3185
|
+
deviceUrl,
|
|
3164
3186
|
devices: [{url: deviceUrl, replaces: [{locusUrl: replacedLocusUrl, replacedAt}]}],
|
|
3165
3187
|
},
|
|
3166
3188
|
});
|
|
@@ -4413,6 +4435,31 @@ describe('plugin-meetings', () => {
|
|
|
4413
4435
|
});
|
|
4414
4436
|
});
|
|
4415
4437
|
|
|
4438
|
+
describe('#cleanUp', () => {
|
|
4439
|
+
it('calls cleanUp on all hash tree parsers and clears maps', () => {
|
|
4440
|
+
const parser1 = {cleanUp: sinon.stub()};
|
|
4441
|
+
const parser2 = {cleanUp: sinon.stub()};
|
|
4442
|
+
|
|
4443
|
+
locusInfo.hashTreeParsers.set('url1', {parser: parser1, initializedFromHashTree: true});
|
|
4444
|
+
locusInfo.hashTreeParsers.set('url2', {parser: parser2, initializedFromHashTree: true});
|
|
4445
|
+
locusInfo.hashTreeObjectId2ParticipantId.set(1, 'participant1');
|
|
4446
|
+
|
|
4447
|
+
locusInfo.cleanUp();
|
|
4448
|
+
|
|
4449
|
+
assert.calledOnce(parser1.cleanUp);
|
|
4450
|
+
assert.calledOnce(parser2.cleanUp);
|
|
4451
|
+
assert.equal(locusInfo.hashTreeParsers.size, 0);
|
|
4452
|
+
assert.equal(locusInfo.hashTreeObjectId2ParticipantId.size, 0);
|
|
4453
|
+
});
|
|
4454
|
+
|
|
4455
|
+
it('works when there are no hash tree parsers', () => {
|
|
4456
|
+
locusInfo.cleanUp();
|
|
4457
|
+
|
|
4458
|
+
assert.equal(locusInfo.hashTreeParsers.size, 0);
|
|
4459
|
+
assert.equal(locusInfo.hashTreeObjectId2ParticipantId.size, 0);
|
|
4460
|
+
});
|
|
4461
|
+
});
|
|
4462
|
+
|
|
4416
4463
|
describe('#handleOneonOneEvent', () => {
|
|
4417
4464
|
beforeEach(() => {
|
|
4418
4465
|
locusInfo.emitScoped = sinon.stub();
|
|
@@ -5146,6 +5193,7 @@ describe('plugin-meetings', () => {
|
|
|
5146
5193
|
return {
|
|
5147
5194
|
htMeta: {elementId: {type: 'Self'}},
|
|
5148
5195
|
data: {
|
|
5196
|
+
deviceUrl,
|
|
5149
5197
|
devices,
|
|
5150
5198
|
},
|
|
5151
5199
|
};
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
import {
|
|
39
39
|
ConnectionState,
|
|
40
40
|
MediaConnectionEventNames,
|
|
41
|
+
MediaCodecMimeType,
|
|
41
42
|
StatsAnalyzerEventNames,
|
|
42
43
|
StatsMonitorEventNames,
|
|
43
44
|
Errors,
|
|
@@ -1981,11 +1982,12 @@ describe('plugin-meetings', () => {
|
|
|
1981
1982
|
describe('#handleLLMOnline', () => {
|
|
1982
1983
|
beforeEach(() => {
|
|
1983
1984
|
webex.internal.llm.off = sinon.stub();
|
|
1985
|
+
webex.internal.voicea.getIsCaptionBoxOn = sinon.stub().returns(false);
|
|
1986
|
+
webex.internal.voicea.updateSubchannelSubscriptions = sinon.stub();
|
|
1984
1987
|
});
|
|
1985
1988
|
|
|
1986
|
-
it('
|
|
1989
|
+
it('emits transcription connected events', () => {
|
|
1987
1990
|
meeting.handleLLMOnline();
|
|
1988
|
-
assert.calledOnceWithExactly(webex.internal.llm.off, 'online', meeting.handleLLMOnline);
|
|
1989
1991
|
assert.calledWith(
|
|
1990
1992
|
TriggerProxy.trigger,
|
|
1991
1993
|
sinon.match.instanceOf(Meeting),
|
|
@@ -1996,6 +1998,24 @@ describe('plugin-meetings', () => {
|
|
|
1996
1998
|
EVENT_TRIGGERS.MEETING_TRANSCRIPTION_CONNECTED
|
|
1997
1999
|
);
|
|
1998
2000
|
});
|
|
2001
|
+
|
|
2002
|
+
it('restores transcription subscription when caption intent is enabled', () => {
|
|
2003
|
+
webex.internal.voicea.getIsCaptionBoxOn.returns(true);
|
|
2004
|
+
|
|
2005
|
+
meeting.handleLLMOnline();
|
|
2006
|
+
|
|
2007
|
+
assert.calledOnceWithExactly(webex.internal.voicea.updateSubchannelSubscriptions, {
|
|
2008
|
+
subscribe: ['transcription'],
|
|
2009
|
+
});
|
|
2010
|
+
});
|
|
2011
|
+
|
|
2012
|
+
it('does not restore transcription subscription when caption intent is disabled', () => {
|
|
2013
|
+
webex.internal.voicea.getIsCaptionBoxOn.returns(false);
|
|
2014
|
+
|
|
2015
|
+
meeting.handleLLMOnline();
|
|
2016
|
+
|
|
2017
|
+
assert.notCalled(webex.internal.voicea.updateSubchannelSubscriptions);
|
|
2018
|
+
});
|
|
1999
2019
|
});
|
|
2000
2020
|
|
|
2001
2021
|
describe('#join', () => {
|
|
@@ -2015,6 +2035,7 @@ describe('plugin-meetings', () => {
|
|
|
2015
2035
|
it('should have #join', () => {
|
|
2016
2036
|
assert.exists(meeting.join);
|
|
2017
2037
|
});
|
|
2038
|
+
|
|
2018
2039
|
beforeEach(() => {
|
|
2019
2040
|
setCorrelationIdSpy = sinon.spy(meeting, 'setCorrelationId');
|
|
2020
2041
|
meeting.setLocus = sinon.stub().returns(true);
|
|
@@ -2168,7 +2189,6 @@ describe('plugin-meetings', () => {
|
|
|
2168
2189
|
await meeting.join().catch(() => {
|
|
2169
2190
|
assert.calledOnce(MeetingUtil.joinMeeting);
|
|
2170
2191
|
|
|
2171
|
-
// Assert that client.locus.join.response error event is not sent from this function, it is now emitted from MeetingUtil.joinMeeting
|
|
2172
2192
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
|
2173
2193
|
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
2174
2194
|
name: 'client.call.initiated',
|
|
@@ -2200,6 +2220,7 @@ describe('plugin-meetings', () => {
|
|
|
2200
2220
|
});
|
|
2201
2221
|
});
|
|
2202
2222
|
});
|
|
2223
|
+
|
|
2203
2224
|
describe('lmm, transcription & permissionTokenRefresh decoupling', () => {
|
|
2204
2225
|
beforeEach(() => {
|
|
2205
2226
|
sandbox.stub(MeetingUtil, 'joinMeeting').returns(Promise.resolve(joinMeetingResult));
|
|
@@ -2270,7 +2291,6 @@ describe('plugin-meetings', () => {
|
|
|
2270
2291
|
const locusInfoParseStub = sinon.stub(meeting.locusInfo, 'parse');
|
|
2271
2292
|
sinon.stub(meeting, 'isJoined').returns(true);
|
|
2272
2293
|
|
|
2273
|
-
// Set up llm.on stub to capture the registered listener when updateLLMConnection is called
|
|
2274
2294
|
let locusLLMEventListener;
|
|
2275
2295
|
meeting.webex.internal.llm.on = sinon.stub().callsFake((eventName, callback) => {
|
|
2276
2296
|
if (eventName === 'event:locus.state_message') {
|
|
@@ -2279,16 +2299,12 @@ describe('plugin-meetings', () => {
|
|
|
2279
2299
|
});
|
|
2280
2300
|
meeting.webex.internal.llm.off = sinon.stub();
|
|
2281
2301
|
|
|
2282
|
-
// we need the real meeting.updateLLMConnection not the mock
|
|
2283
2302
|
meeting.updateLLMConnection.restore();
|
|
2284
2303
|
|
|
2285
|
-
// Call updateLLMConnection to register the listener
|
|
2286
2304
|
await meeting.updateLLMConnection();
|
|
2287
2305
|
|
|
2288
|
-
// Verify the listener was registered and we captured it
|
|
2289
2306
|
assert.isDefined(locusLLMEventListener, 'LLM event listener should be registered');
|
|
2290
2307
|
|
|
2291
|
-
// Now trigger the event
|
|
2292
2308
|
const eventData = {
|
|
2293
2309
|
eventType: 'locus.state_message',
|
|
2294
2310
|
stateElementsMessage: {
|
|
@@ -2308,13 +2324,10 @@ describe('plugin-meetings', () => {
|
|
|
2308
2324
|
sinon.stub(meeting.webex.internal.llm, 'hasEverConnected').value(true);
|
|
2309
2325
|
sinon.stub(meeting.webex.internal.llm, 'registerAndConnect').resolves({});
|
|
2310
2326
|
|
|
2311
|
-
// Restore the real updateLLMConnection
|
|
2312
2327
|
meeting.updateLLMConnection.restore();
|
|
2313
2328
|
|
|
2314
|
-
// Call updateLLMConnection to start the timer
|
|
2315
2329
|
await meeting.updateLLMConnection();
|
|
2316
2330
|
|
|
2317
|
-
// Fast forward time by 3 minutes
|
|
2318
2331
|
fakeClock.tick(3 * 60 * 1000);
|
|
2319
2332
|
|
|
2320
2333
|
assert.calledWith(
|
|
@@ -2339,18 +2352,14 @@ describe('plugin-meetings', () => {
|
|
|
2339
2352
|
.stub(meeting.webex.internal.llm, 'getDatachannelUrl')
|
|
2340
2353
|
.returns('https://datachannel1.example.com');
|
|
2341
2354
|
|
|
2342
|
-
// Restore the real updateLLMConnection
|
|
2343
2355
|
meeting.updateLLMConnection.restore();
|
|
2344
2356
|
|
|
2345
|
-
// First, connect LLM and start the timer
|
|
2346
2357
|
isJoinedStub.returns(true);
|
|
2347
2358
|
meeting.webex.internal.llm.isConnected.returns(false);
|
|
2348
2359
|
await meeting.updateLLMConnection();
|
|
2349
2360
|
|
|
2350
|
-
// Verify timer was started
|
|
2351
2361
|
assert.exists(meeting.llmHealthCheckTimer);
|
|
2352
2362
|
|
|
2353
|
-
// Now simulate that we're no longer joined
|
|
2354
2363
|
isJoinedStub.returns(false);
|
|
2355
2364
|
meeting.webex.internal.llm.isConnected.returns(true);
|
|
2356
2365
|
|
|
@@ -2358,10 +2367,8 @@ describe('plugin-meetings', () => {
|
|
|
2358
2367
|
|
|
2359
2368
|
assert.calledOnce(meeting.webex.internal.llm.disconnectLLM);
|
|
2360
2369
|
|
|
2361
|
-
// Verify the timer was cleared (should be undefined)
|
|
2362
2370
|
assert.isUndefined(meeting.llmHealthCheckTimer);
|
|
2363
2371
|
|
|
2364
|
-
// Fast forward time to ensure no metric is sent
|
|
2365
2372
|
Metrics.sendBehavioralMetric.resetHistory();
|
|
2366
2373
|
fakeClock.tick(3 * 60 * 1000);
|
|
2367
2374
|
|
|
@@ -2396,7 +2403,6 @@ describe('plugin-meetings', () => {
|
|
|
2396
2403
|
.stub()
|
|
2397
2404
|
.rejects(new CaptchaError('bad captcha'));
|
|
2398
2405
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
2399
|
-
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil, 'joinMeetingOptions');
|
|
2400
2406
|
|
|
2401
2407
|
try {
|
|
2402
2408
|
await meeting.join();
|
|
@@ -2410,8 +2416,7 @@ describe('plugin-meetings', () => {
|
|
|
2410
2416
|
);
|
|
2411
2417
|
assert.instanceOf(error, CaptchaError);
|
|
2412
2418
|
assert.equal(error.message, 'bad captcha');
|
|
2413
|
-
|
|
2414
|
-
assert.notCalled(joinMeetingOptionsSpy);
|
|
2419
|
+
assert.notCalled(MeetingUtil.joinMeeting);
|
|
2415
2420
|
}
|
|
2416
2421
|
});
|
|
2417
2422
|
|
|
@@ -2420,7 +2425,6 @@ describe('plugin-meetings', () => {
|
|
|
2420
2425
|
.stub()
|
|
2421
2426
|
.rejects(new PasswordError('bad password'));
|
|
2422
2427
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
2423
|
-
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
|
|
2424
2428
|
|
|
2425
2429
|
try {
|
|
2426
2430
|
await meeting.join();
|
|
@@ -2434,8 +2438,7 @@ describe('plugin-meetings', () => {
|
|
|
2434
2438
|
);
|
|
2435
2439
|
assert.instanceOf(error, PasswordError);
|
|
2436
2440
|
assert.equal(error.message, 'bad password');
|
|
2437
|
-
|
|
2438
|
-
assert.notCalled(joinMeetingOptionsSpy);
|
|
2441
|
+
assert.notCalled(MeetingUtil.joinMeeting);
|
|
2439
2442
|
}
|
|
2440
2443
|
});
|
|
2441
2444
|
|
|
@@ -2444,7 +2447,6 @@ describe('plugin-meetings', () => {
|
|
|
2444
2447
|
.stub()
|
|
2445
2448
|
.rejects(new PermissionError('bad permission'));
|
|
2446
2449
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
2447
|
-
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
|
|
2448
2450
|
|
|
2449
2451
|
try {
|
|
2450
2452
|
await meeting.join();
|
|
@@ -2458,14 +2460,14 @@ describe('plugin-meetings', () => {
|
|
|
2458
2460
|
);
|
|
2459
2461
|
assert.instanceOf(error, PermissionError);
|
|
2460
2462
|
assert.equal(error.message, 'bad permission');
|
|
2461
|
-
|
|
2462
|
-
assert.notCalled(joinMeetingOptionsSpy);
|
|
2463
|
+
assert.notCalled(MeetingUtil.joinMeeting);
|
|
2463
2464
|
}
|
|
2464
2465
|
});
|
|
2465
2466
|
});
|
|
2466
2467
|
});
|
|
2467
2468
|
});
|
|
2468
2469
|
|
|
2470
|
+
|
|
2469
2471
|
describe('#addMedia', () => {
|
|
2470
2472
|
const muteStateStub = {
|
|
2471
2473
|
handleClientRequest: sinon.stub().returns(Promise.resolve(true)),
|
|
@@ -9214,8 +9216,8 @@ describe('plugin-meetings', () => {
|
|
|
9214
9216
|
const fakeMultistreamRoapMediaConnection = {
|
|
9215
9217
|
createSendSlot: () => {
|
|
9216
9218
|
return {
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
+
setCustomCodecParameters: sinon.stub().resolves(),
|
|
9220
|
+
markCustomCodecParametersForDeletion: sinon.stub().resolves(),
|
|
9219
9221
|
};
|
|
9220
9222
|
},
|
|
9221
9223
|
};
|
|
@@ -9238,27 +9240,29 @@ describe('plugin-meetings', () => {
|
|
|
9238
9240
|
}
|
|
9239
9241
|
);
|
|
9240
9242
|
|
|
9241
|
-
it('should set
|
|
9243
|
+
it('should set custom codec parameters when shouldEnableMusicMode is true', async () => {
|
|
9242
9244
|
await meeting.enableMusicMode(true);
|
|
9243
9245
|
assert.calledOnceWithExactly(
|
|
9244
|
-
meeting.sendSlotManager.getSlot(MediaType.AudioMain).
|
|
9246
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCustomCodecParameters,
|
|
9247
|
+
MediaCodecMimeType.OPUS,
|
|
9245
9248
|
{
|
|
9246
9249
|
maxaveragebitrate: '64000',
|
|
9247
9250
|
maxplaybackrate: '48000',
|
|
9248
9251
|
}
|
|
9249
9252
|
);
|
|
9250
9253
|
assert.notCalled(
|
|
9251
|
-
meeting.sendSlotManager.getSlot(MediaType.AudioMain).
|
|
9254
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).markCustomCodecParametersForDeletion
|
|
9252
9255
|
);
|
|
9253
9256
|
});
|
|
9254
9257
|
|
|
9255
|
-
it('should
|
|
9258
|
+
it('should mark custom codec parameters for deletion when shouldEnableMusicMode is false', async () => {
|
|
9256
9259
|
await meeting.enableMusicMode(false);
|
|
9257
9260
|
assert.calledOnceWithExactly(
|
|
9258
|
-
meeting.sendSlotManager.getSlot(MediaType.AudioMain).
|
|
9261
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).markCustomCodecParametersForDeletion,
|
|
9262
|
+
MediaCodecMimeType.OPUS,
|
|
9259
9263
|
['maxaveragebitrate', 'maxplaybackrate']
|
|
9260
9264
|
);
|
|
9261
|
-
assert.notCalled(meeting.sendSlotManager.getSlot(MediaType.AudioMain).
|
|
9265
|
+
assert.notCalled(meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCustomCodecParameters);
|
|
9262
9266
|
});
|
|
9263
9267
|
});
|
|
9264
9268
|
|
|
@@ -10413,14 +10417,24 @@ describe('plugin-meetings', () => {
|
|
|
10413
10417
|
);
|
|
10414
10418
|
done();
|
|
10415
10419
|
});
|
|
10416
|
-
it('listens to the self admitted guest event', (
|
|
10420
|
+
it('listens to the self admitted guest event without blocking on token prefetch', async () => {
|
|
10417
10421
|
meeting.stopKeepAlive = sinon.stub();
|
|
10418
10422
|
meeting.updateLLMConnection = sinon.stub();
|
|
10423
|
+
let resolvePrefetch;
|
|
10424
|
+
|
|
10425
|
+
meeting.ensureDefaultDatachannelTokenAfterAdmit = sinon
|
|
10426
|
+
.stub()
|
|
10427
|
+
.returns(new Promise((resolve) => {
|
|
10428
|
+
resolvePrefetch = resolve;
|
|
10429
|
+
}));
|
|
10419
10430
|
meeting.rtcMetrics = {
|
|
10420
10431
|
sendNextMetrics: sinon.stub(),
|
|
10421
10432
|
};
|
|
10433
|
+
|
|
10422
10434
|
meeting.locusInfo.emit({function: 'test', file: 'test'}, 'SELF_ADMITTED_GUEST', test1);
|
|
10435
|
+
|
|
10423
10436
|
assert.calledOnceWithExactly(meeting.stopKeepAlive);
|
|
10437
|
+
assert.calledOnceWithExactly(meeting.ensureDefaultDatachannelTokenAfterAdmit);
|
|
10424
10438
|
assert.calledThrice(TriggerProxy.trigger);
|
|
10425
10439
|
assert.calledWith(
|
|
10426
10440
|
TriggerProxy.trigger,
|
|
@@ -10439,7 +10453,11 @@ describe('plugin-meetings', () => {
|
|
|
10439
10453
|
correlation_id: meeting.correlationId,
|
|
10440
10454
|
}
|
|
10441
10455
|
);
|
|
10442
|
-
|
|
10456
|
+
|
|
10457
|
+
resolvePrefetch(false);
|
|
10458
|
+
await Promise.resolve();
|
|
10459
|
+
|
|
10460
|
+
assert.calledOnce(meeting.updateLLMConnection);
|
|
10443
10461
|
});
|
|
10444
10462
|
|
|
10445
10463
|
it('listens to the breakouts changed event', () => {
|