@webex/plugin-meetings 3.11.0-next.21 → 3.11.0-next.23
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 +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/hashTree/types.js +3 -2
- package/dist/hashTree/types.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +22 -1
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/types.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +11 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/types/hashTree/types.d.ts +2 -0
- package/dist/types/locus-info/types.d.ts +1 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +1 -1
- package/src/hashTree/types.ts +3 -0
- package/src/locus-info/index.ts +26 -0
- package/src/locus-info/types.ts +1 -0
- package/src/multistream/remoteMediaManager.ts +13 -0
- package/test/unit/spec/locus-info/index.js +85 -28
- package/test/unit/spec/multistream/remoteMediaManager.ts +30 -0
|
@@ -329,6 +329,16 @@ describe('plugin-meetings', () => {
|
|
|
329
329
|
htMeta: {elementId: {type: 'mediashare', id: 'fake-ht-mediaShare-2', version: 1}},
|
|
330
330
|
},
|
|
331
331
|
];
|
|
332
|
+
locusInfo.embeddedApps = [
|
|
333
|
+
{
|
|
334
|
+
id: 'fake-embedded-app-1',
|
|
335
|
+
htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-1', version: 1}},
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
id: 'fake-embedded-app-2',
|
|
339
|
+
htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-2', version: 1}},
|
|
340
|
+
},
|
|
341
|
+
];
|
|
332
342
|
locusInfo.meetings = {id: 'fake-meetings'};
|
|
333
343
|
locusInfo.participants = [
|
|
334
344
|
{id: 'fake-participant-1', name: 'Participant One'},
|
|
@@ -364,6 +374,16 @@ describe('plugin-meetings', () => {
|
|
|
364
374
|
htMeta: {elementId: {type: 'mediashare', id: 'fake-ht-mediaShare-2', version: 1}},
|
|
365
375
|
},
|
|
366
376
|
],
|
|
377
|
+
embeddedApps: [
|
|
378
|
+
{
|
|
379
|
+
id: 'fake-embedded-app-1',
|
|
380
|
+
htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-1', version: 1}},
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
id: 'fake-embedded-app-2',
|
|
384
|
+
htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-2', version: 1}},
|
|
385
|
+
},
|
|
386
|
+
],
|
|
367
387
|
meetings: {id: 'fake-meetings'},
|
|
368
388
|
jsSdkMeta: {removedParticipantIds: []},
|
|
369
389
|
participants: [], // empty means there were no participant updates
|
|
@@ -540,6 +560,7 @@ describe('plugin-meetings', () => {
|
|
|
540
560
|
self: {id: 'fake-self'},
|
|
541
561
|
links: {id: 'fake-links'},
|
|
542
562
|
mediaShares: expectedLocusInfo.mediaShares,
|
|
563
|
+
embeddedApps: expectedLocusInfo.embeddedApps,
|
|
543
564
|
// and now the new fields
|
|
544
565
|
...newLocus,
|
|
545
566
|
htMeta: newLocusHtMeta,
|
|
@@ -572,6 +593,7 @@ describe('plugin-meetings', () => {
|
|
|
572
593
|
self: 'new-self',
|
|
573
594
|
participants: 'new-participants',
|
|
574
595
|
mediaShares: 'new-mediaShares',
|
|
596
|
+
embeddedApps: 'new-embeddedApps',
|
|
575
597
|
},
|
|
576
598
|
},
|
|
577
599
|
],
|
|
@@ -587,6 +609,7 @@ describe('plugin-meetings', () => {
|
|
|
587
609
|
self: {id: 'fake-self'},
|
|
588
610
|
links: {id: 'fake-links'},
|
|
589
611
|
mediaShares: expectedLocusInfo.mediaShares,
|
|
612
|
+
embeddedApps: expectedLocusInfo.embeddedApps,
|
|
590
613
|
participants: [], // empty means there were no participant updates
|
|
591
614
|
jsSdkMeta: {removedParticipantIds: []}, // no participants were removed
|
|
592
615
|
...newLocus,
|
|
@@ -622,6 +645,7 @@ describe('plugin-meetings', () => {
|
|
|
622
645
|
self: {id: 'fake-self'},
|
|
623
646
|
links: {id: 'fake-links'},
|
|
624
647
|
mediaShares: expectedLocusInfo.mediaShares,
|
|
648
|
+
embeddedApps: expectedLocusInfo.embeddedApps,
|
|
625
649
|
// and now the new fields
|
|
626
650
|
...newLocus,
|
|
627
651
|
htMeta: newLocusHtMeta,
|
|
@@ -761,6 +785,39 @@ describe('plugin-meetings', () => {
|
|
|
761
785
|
});
|
|
762
786
|
});
|
|
763
787
|
|
|
788
|
+
it('should process locus update correctly when called with updated EMBEDDEDAPP objects', () => {
|
|
789
|
+
const newEmbeddedApp = {
|
|
790
|
+
id: 'new-embedded-app-3',
|
|
791
|
+
htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-3', version: 100}},
|
|
792
|
+
};
|
|
793
|
+
const updatedEmbeddedApp2 = {
|
|
794
|
+
id: 'fake-embedded-app-2',
|
|
795
|
+
someNewProp: 'newValue',
|
|
796
|
+
htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-2', version: 100}},
|
|
797
|
+
};
|
|
798
|
+
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
799
|
+
// with 1 embedded app added, 1 updated, and 1 removed
|
|
800
|
+
locusInfoUpdateCallback(OBJECTS_UPDATED, {
|
|
801
|
+
updatedObjects: [
|
|
802
|
+
{htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-1'}}, data: null},
|
|
803
|
+
{
|
|
804
|
+
htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-2'}},
|
|
805
|
+
data: updatedEmbeddedApp2,
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
htMeta: {elementId: {type: 'embeddedapp', id: 'fake-ht-embeddedApp-3'}},
|
|
809
|
+
data: newEmbeddedApp,
|
|
810
|
+
},
|
|
811
|
+
],
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
// check onDeltaLocus() was called with correctly updated locus info
|
|
815
|
+
assert.calledOnceWithExactly(onDeltaLocusStub, {
|
|
816
|
+
...expectedLocusInfo,
|
|
817
|
+
embeddedApps: [updatedEmbeddedApp2, newEmbeddedApp],
|
|
818
|
+
});
|
|
819
|
+
});
|
|
820
|
+
|
|
764
821
|
it('should process locus update correctly when called with a combination of various updated objects', () => {
|
|
765
822
|
const newSelf = {
|
|
766
823
|
id: 'new-self',
|
|
@@ -2958,28 +3015,28 @@ describe('plugin-meetings', () => {
|
|
|
2958
3015
|
assert.isFunction(locusParser.onDeltaAction);
|
|
2959
3016
|
});
|
|
2960
3017
|
|
|
2961
|
-
it(
|
|
3018
|
+
it('#updateLocusInfo invokes updateLocusUrl before updateMeetingInfo', () => {
|
|
2962
3019
|
const callOrder = [];
|
|
2963
|
-
sinon.stub(locusInfo,
|
|
2964
|
-
sinon.stub(locusInfo,
|
|
2965
|
-
sinon.stub(locusInfo,
|
|
2966
|
-
sinon.stub(locusInfo,
|
|
2967
|
-
sinon.stub(locusInfo,
|
|
2968
|
-
sinon.stub(locusInfo,
|
|
2969
|
-
callOrder.push(
|
|
3020
|
+
sinon.stub(locusInfo, 'updateControls');
|
|
3021
|
+
sinon.stub(locusInfo, 'updateConversationUrl');
|
|
3022
|
+
sinon.stub(locusInfo, 'updateCreated');
|
|
3023
|
+
sinon.stub(locusInfo, 'updateFullState');
|
|
3024
|
+
sinon.stub(locusInfo, 'updateHostInfo');
|
|
3025
|
+
sinon.stub(locusInfo, 'updateMeetingInfo').callsFake(() => {
|
|
3026
|
+
callOrder.push('updateMeetingInfo');
|
|
2970
3027
|
});
|
|
2971
|
-
sinon.stub(locusInfo,
|
|
2972
|
-
sinon.stub(locusInfo,
|
|
2973
|
-
sinon.stub(locusInfo,
|
|
2974
|
-
sinon.stub(locusInfo,
|
|
2975
|
-
callOrder.push(
|
|
3028
|
+
sinon.stub(locusInfo, 'updateMediaShares');
|
|
3029
|
+
sinon.stub(locusInfo, 'updateReplaces');
|
|
3030
|
+
sinon.stub(locusInfo, 'updateSelf');
|
|
3031
|
+
sinon.stub(locusInfo, 'updateLocusUrl').callsFake(() => {
|
|
3032
|
+
callOrder.push('updateLocusUrl');
|
|
2976
3033
|
});
|
|
2977
|
-
sinon.stub(locusInfo,
|
|
2978
|
-
sinon.stub(locusInfo,
|
|
2979
|
-
sinon.stub(locusInfo,
|
|
2980
|
-
sinon.stub(locusInfo,
|
|
2981
|
-
sinon.stub(locusInfo,
|
|
2982
|
-
sinon.stub(locusInfo,
|
|
3034
|
+
sinon.stub(locusInfo, 'updateAclUrl');
|
|
3035
|
+
sinon.stub(locusInfo, 'updateBasequence');
|
|
3036
|
+
sinon.stub(locusInfo, 'updateSequence');
|
|
3037
|
+
sinon.stub(locusInfo, 'updateEmbeddedApps');
|
|
3038
|
+
sinon.stub(locusInfo, 'updateLinks');
|
|
3039
|
+
sinon.stub(locusInfo, 'compareAndUpdate');
|
|
2983
3040
|
|
|
2984
3041
|
locusInfo.updateLocusInfo(locus);
|
|
2985
3042
|
|
|
@@ -3035,7 +3092,7 @@ describe('plugin-meetings', () => {
|
|
|
3035
3092
|
it('#updateLocusInfo puts the Locus DTO top level properties at the right place in LocusInfo class', () => {
|
|
3036
3093
|
// this test verifies that the top-level properties of Locus DTO are copied
|
|
3037
3094
|
// into LocusInfo class and set as top level properties too
|
|
3038
|
-
// this is important, because the code handling Locus
|
|
3095
|
+
// this is important, because the code handling Locus hash trees relies on it, see updateFromHashTree()
|
|
3039
3096
|
const info = {id: 'info id'};
|
|
3040
3097
|
const fullState = {id: 'fullState id'};
|
|
3041
3098
|
const links = {services: {id: 'service links'}, resources: {id: 'resource links'}};
|
|
@@ -3903,7 +3960,7 @@ describe('plugin-meetings', () => {
|
|
|
3903
3960
|
|
|
3904
3961
|
describe('#updateLocusUrl', () => {
|
|
3905
3962
|
it('trigger LOCUS_INFO_UPDATE_URL event with isMainLocus is true as default', () => {
|
|
3906
|
-
const fakeUrl =
|
|
3963
|
+
const fakeUrl = 'https://fake.com/locus';
|
|
3907
3964
|
locusInfo.emitScoped = sinon.stub();
|
|
3908
3965
|
locusInfo.updateLocusUrl(fakeUrl);
|
|
3909
3966
|
|
|
@@ -3916,12 +3973,12 @@ describe('plugin-meetings', () => {
|
|
|
3916
3973
|
EVENTS.LOCUS_INFO_UPDATE_URL,
|
|
3917
3974
|
{
|
|
3918
3975
|
url: fakeUrl,
|
|
3919
|
-
isMainLocus: true
|
|
3920
|
-
}
|
|
3976
|
+
isMainLocus: true,
|
|
3977
|
+
}
|
|
3921
3978
|
);
|
|
3922
3979
|
});
|
|
3923
3980
|
it('trigger LOCUS_INFO_UPDATE_URL event with isMainLocus is false', () => {
|
|
3924
|
-
const fakeUrl =
|
|
3981
|
+
const fakeUrl = 'https://fake.com/locus';
|
|
3925
3982
|
locusInfo.emitScoped = sinon.stub();
|
|
3926
3983
|
locusInfo.updateLocusUrl(fakeUrl, false);
|
|
3927
3984
|
|
|
@@ -3934,8 +3991,8 @@ describe('plugin-meetings', () => {
|
|
|
3934
3991
|
EVENTS.LOCUS_INFO_UPDATE_URL,
|
|
3935
3992
|
{
|
|
3936
3993
|
url: fakeUrl,
|
|
3937
|
-
isMainLocus: false
|
|
3938
|
-
}
|
|
3994
|
+
isMainLocus: false,
|
|
3995
|
+
}
|
|
3939
3996
|
);
|
|
3940
3997
|
});
|
|
3941
3998
|
});
|
|
@@ -3987,8 +4044,8 @@ describe('plugin-meetings', () => {
|
|
|
3987
4044
|
|
|
3988
4045
|
sinon.stub(locusInfo, 'updateParticipants');
|
|
3989
4046
|
sinon.stub(locusInfo, 'isMeetingActive');
|
|
3990
|
-
|
|
3991
|
-
|
|
4047
|
+
sinon.stub(locusInfo, 'handleOneOnOneEvent');
|
|
4048
|
+
updateLocusInfoStub = sinon.stub(locusInfo, 'updateLocusInfo');
|
|
3992
4049
|
syncRequestStub = sinon.stub().resolves({body: {}});
|
|
3993
4050
|
|
|
3994
4051
|
mockMeeting.locusInfo = locusInfo;
|
|
@@ -965,6 +965,36 @@ describe('RemoteMediaManager', () => {
|
|
|
965
965
|
);
|
|
966
966
|
});
|
|
967
967
|
|
|
968
|
+
it('allocates 25 video slots for AllEqual25 layout', async () => {
|
|
969
|
+
const config = cloneDeep(DefaultTestConfiguration);
|
|
970
|
+
config.video.layouts['AllEqual25'] = {
|
|
971
|
+
activeSpeakerVideoPaneGroups: [
|
|
972
|
+
{id: 'main', numPanes: 25, size: 'best', priority: 255},
|
|
973
|
+
],
|
|
974
|
+
};
|
|
975
|
+
config.video.initialLayoutId = 'AllEqual25';
|
|
976
|
+
|
|
977
|
+
let slotCount = 0;
|
|
978
|
+
fakeReceiveSlotManager.allocateSlot.callsFake((mediaType: MediaType) => {
|
|
979
|
+
if (mediaType === MediaType.VideoMain) {
|
|
980
|
+
slotCount += 1;
|
|
981
|
+
return Promise.resolve(new FakeSlot(mediaType, `fake video ${slotCount}`));
|
|
982
|
+
}
|
|
983
|
+
return Promise.resolve(fakeAudioSlot);
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
remoteMediaManager = new RemoteMediaManager(
|
|
987
|
+
fakeReceiveSlotManager,
|
|
988
|
+
fakeMediaRequestManagers,
|
|
989
|
+
config
|
|
990
|
+
);
|
|
991
|
+
|
|
992
|
+
await remoteMediaManager.start();
|
|
993
|
+
|
|
994
|
+
assert.strictEqual(remoteMediaManager.getLayoutId(), 'AllEqual25');
|
|
995
|
+
assert.strictEqual(remoteMediaManager.slots.video.activeSpeaker.length, 25);
|
|
996
|
+
});
|
|
997
|
+
|
|
968
998
|
it('releases slots when switching to layout that requires less active speaker slots', async () => {
|
|
969
999
|
// start with "AllEqual" layout that needs just 9 video slots
|
|
970
1000
|
const config = cloneDeep(DefaultTestConfiguration);
|