@webex/plugin-meetings 3.11.0-next.3 → 3.11.0-next.4
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/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +14 -5
- package/dist/meeting/index.js.map +1 -1
- package/dist/types/meeting/index.d.ts +5 -3
- package/dist/webinar/index.js +1 -1
- package/package.json +1 -1
- package/src/meeting/index.ts +16 -5
- package/test/unit/spec/meeting/index.js +105 -0
|
@@ -70,6 +70,7 @@ export type AddMediaOptions = {
|
|
|
70
70
|
remoteMediaManagerConfig?: RemoteMediaManagerConfiguration;
|
|
71
71
|
bundlePolicy?: BundlePolicy;
|
|
72
72
|
allowMediaInLobby?: boolean;
|
|
73
|
+
allowPublishMediaInLobby?: boolean;
|
|
73
74
|
additionalMediaOptions?: AdditionalMediaOptions;
|
|
74
75
|
};
|
|
75
76
|
export type AdditionalMediaOptions = {
|
|
@@ -405,6 +406,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
405
406
|
keepAliveTimerId: NodeJS.Timeout;
|
|
406
407
|
lastVideoLayoutInfo: any;
|
|
407
408
|
locusInfo: any;
|
|
409
|
+
isUserUnadmitted?: boolean;
|
|
410
|
+
joinedWith?: any;
|
|
411
|
+
selfId?: string;
|
|
412
|
+
roles: any[];
|
|
408
413
|
locusMediaRequest?: LocusMediaRequest;
|
|
409
414
|
mediaProperties: MediaProperties;
|
|
410
415
|
mediaRequestManagers: {
|
|
@@ -438,7 +443,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
438
443
|
endCallInitJoinReq: any;
|
|
439
444
|
endJoinReqResp: any;
|
|
440
445
|
endLocalSDPGenRemoteSDPRecvDelay: any;
|
|
441
|
-
joinedWith: any;
|
|
442
446
|
locusId: any;
|
|
443
447
|
startCallInitJoinReq: any;
|
|
444
448
|
startJoinReqResp: any;
|
|
@@ -453,12 +457,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
453
457
|
permissionTokenReceivedLocalTime: number;
|
|
454
458
|
resourceId: any;
|
|
455
459
|
resourceUrl: string;
|
|
456
|
-
selfId: string;
|
|
457
460
|
state: any;
|
|
458
461
|
localAudioStreamMuteStateHandler: () => void;
|
|
459
462
|
localVideoStreamMuteStateHandler: () => void;
|
|
460
463
|
localOutputTrackChangeHandler: () => void;
|
|
461
|
-
roles: any[];
|
|
462
464
|
environment: string;
|
|
463
465
|
namespace: string;
|
|
464
466
|
allowMediaInLobby: boolean;
|
package/dist/webinar/index.js
CHANGED
package/package.json
CHANGED
package/src/meeting/index.ts
CHANGED
|
@@ -250,6 +250,7 @@ export type AddMediaOptions = {
|
|
|
250
250
|
remoteMediaManagerConfig?: RemoteMediaManagerConfiguration; // applies only to multistream meetings
|
|
251
251
|
bundlePolicy?: BundlePolicy; // applies only to multistream meetings
|
|
252
252
|
allowMediaInLobby?: boolean; // allows adding media when in the lobby
|
|
253
|
+
allowPublishMediaInLobby?: boolean; // allows publishing media when in the lobby, if not specified, default value false is used
|
|
253
254
|
additionalMediaOptions?: AdditionalMediaOptions; // allows adding additional options like send/receive audio/video
|
|
254
255
|
};
|
|
255
256
|
|
|
@@ -623,6 +624,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
623
624
|
keepAliveTimerId: NodeJS.Timeout;
|
|
624
625
|
lastVideoLayoutInfo: any;
|
|
625
626
|
locusInfo: any;
|
|
627
|
+
// this group of properties is populated via updateMeetingObject() that's registered as a callback with LocusInfo
|
|
628
|
+
isUserUnadmitted?: boolean;
|
|
629
|
+
joinedWith?: any;
|
|
630
|
+
selfId?: string;
|
|
631
|
+
roles: any[];
|
|
632
|
+
// ... there is more ... see SelfUtils.parse()
|
|
633
|
+
// end of the group
|
|
626
634
|
locusMediaRequest?: LocusMediaRequest;
|
|
627
635
|
mediaProperties: MediaProperties;
|
|
628
636
|
mediaRequestManagers: {
|
|
@@ -657,7 +665,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
657
665
|
endCallInitJoinReq: any;
|
|
658
666
|
endJoinReqResp: any;
|
|
659
667
|
endLocalSDPGenRemoteSDPRecvDelay: any;
|
|
660
|
-
joinedWith: any;
|
|
661
668
|
locusId: any;
|
|
662
669
|
startCallInitJoinReq: any;
|
|
663
670
|
startJoinReqResp: any;
|
|
@@ -672,12 +679,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
672
679
|
permissionTokenReceivedLocalTime: number;
|
|
673
680
|
resourceId: any;
|
|
674
681
|
resourceUrl: string;
|
|
675
|
-
selfId: string;
|
|
676
682
|
state: any;
|
|
677
683
|
localAudioStreamMuteStateHandler: () => void;
|
|
678
684
|
localVideoStreamMuteStateHandler: () => void;
|
|
679
685
|
localOutputTrackChangeHandler: () => void;
|
|
680
|
-
roles: any[];
|
|
681
686
|
environment: string;
|
|
682
687
|
namespace = MEETINGS;
|
|
683
688
|
allowMediaInLobby: boolean;
|
|
@@ -8026,6 +8031,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8026
8031
|
remoteMediaManagerConfig,
|
|
8027
8032
|
bundlePolicy = 'max-bundle',
|
|
8028
8033
|
additionalMediaOptions = {},
|
|
8034
|
+
allowPublishMediaInLobby = false,
|
|
8029
8035
|
} = options;
|
|
8030
8036
|
|
|
8031
8037
|
const {
|
|
@@ -8046,7 +8052,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8046
8052
|
const ipver = MeetingUtil.getIpVersion(this.webex); // used just for metrics
|
|
8047
8053
|
|
|
8048
8054
|
// If the user is unjoined or guest waiting in lobby dont allow the user to addMedia
|
|
8049
|
-
// @ts-ignore - isUserUnadmitted coming from SelfUtil
|
|
8050
8055
|
if (this.isUserUnadmitted && !this.wirelessShare && !this.allowMediaInLobby) {
|
|
8051
8056
|
throw new UserInLobbyError();
|
|
8052
8057
|
}
|
|
@@ -8091,7 +8096,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8091
8096
|
this.brbState = createBrbState(this, false);
|
|
8092
8097
|
|
|
8093
8098
|
try {
|
|
8094
|
-
|
|
8099
|
+
// if we're in a lobby and allowPublishMediaInLobby==false, we don't want to
|
|
8100
|
+
// setup local streams for publishing, because if we ever end up admitted to the meeting
|
|
8101
|
+
// but Locus event about it for us is delayed or missed, others could see/hear our user's video/audio
|
|
8102
|
+
// while the user would still think they're in the lobby
|
|
8103
|
+
if (allowPublishMediaInLobby || !this.isUserUnadmitted) {
|
|
8104
|
+
await this.setUpLocalStreamReferences(localStreams);
|
|
8105
|
+
}
|
|
8095
8106
|
|
|
8096
8107
|
this.setMercuryListener();
|
|
8097
8108
|
|
|
@@ -3028,6 +3028,111 @@ describe('plugin-meetings', () => {
|
|
|
3028
3028
|
checkWorking({allowMediaInLobby: true});
|
|
3029
3029
|
});
|
|
3030
3030
|
|
|
3031
|
+
const setupLobbyTest = () => {
|
|
3032
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
3033
|
+
.stub()
|
|
3034
|
+
.resolves({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});
|
|
3035
|
+
|
|
3036
|
+
meeting.meetingState = 'ACTIVE';
|
|
3037
|
+
meeting.locusInfo.parsedLocus = {self: {state: 'IDLE'}};
|
|
3038
|
+
meeting.isUserUnadmitted = true;
|
|
3039
|
+
|
|
3040
|
+
// Mock locusMediaRequest
|
|
3041
|
+
meeting.locusMediaRequest = {
|
|
3042
|
+
send: sinon.stub().resolves(),
|
|
3043
|
+
isConfluenceCreated: sinon.stub().returns(false),
|
|
3044
|
+
};
|
|
3045
|
+
|
|
3046
|
+
sinon.stub(RemoteMediaManagerModule, 'RemoteMediaManager').returns({
|
|
3047
|
+
start: sinon.stub().resolves(),
|
|
3048
|
+
on: sinon.stub(),
|
|
3049
|
+
logAllReceiveSlots: sinon.stub(),
|
|
3050
|
+
});
|
|
3051
|
+
|
|
3052
|
+
meeting.isMultistream = true;
|
|
3053
|
+
|
|
3054
|
+
const createFakeStream = (id) => ({
|
|
3055
|
+
on: sinon.stub(),
|
|
3056
|
+
off: sinon.stub(),
|
|
3057
|
+
userMuted: false,
|
|
3058
|
+
systemMuted: false,
|
|
3059
|
+
get muted() {
|
|
3060
|
+
return this.userMuted || this.systemMuted;
|
|
3061
|
+
},
|
|
3062
|
+
setUnmuteAllowed: sinon.stub(),
|
|
3063
|
+
setUserMuted: sinon.stub(),
|
|
3064
|
+
outputStream: {
|
|
3065
|
+
getTracks: () => [{id}],
|
|
3066
|
+
},
|
|
3067
|
+
getSettings: sinon.stub().returns({}),
|
|
3068
|
+
});
|
|
3069
|
+
|
|
3070
|
+
return {
|
|
3071
|
+
fakeMicrophoneStream: createFakeStream('fake mic'),
|
|
3072
|
+
fakeCameraStream: createFakeStream('fake camera'),
|
|
3073
|
+
};
|
|
3074
|
+
};
|
|
3075
|
+
|
|
3076
|
+
it('should not publish any local streams when in the lobby and allowPublishMediaInLobby is false', async () => {
|
|
3077
|
+
const {fakeMicrophoneStream, fakeCameraStream} = setupLobbyTest();
|
|
3078
|
+
|
|
3079
|
+
const publishStreamStub = sinon.stub();
|
|
3080
|
+
fakeMediaConnection.createSendSlot = sinon.stub().returns({
|
|
3081
|
+
publishStream: publishStreamStub,
|
|
3082
|
+
unpublishStream: sinon.stub(),
|
|
3083
|
+
setNamedMediaGroups: sinon.stub(),
|
|
3084
|
+
});
|
|
3085
|
+
|
|
3086
|
+
await meeting.addMedia({
|
|
3087
|
+
allowMediaInLobby: true,
|
|
3088
|
+
allowPublishMediaInLobby: false,
|
|
3089
|
+
audioEnabled: true,
|
|
3090
|
+
videoEnabled: true,
|
|
3091
|
+
localStreams: {
|
|
3092
|
+
microphone: fakeMicrophoneStream,
|
|
3093
|
+
camera: fakeCameraStream,
|
|
3094
|
+
},
|
|
3095
|
+
});
|
|
3096
|
+
|
|
3097
|
+
assert.notCalled(publishStreamStub);
|
|
3098
|
+
});
|
|
3099
|
+
|
|
3100
|
+
it('should publish local streams when in the lobby and allowPublishMediaInLobby is true', async () => {
|
|
3101
|
+
const {fakeMicrophoneStream, fakeCameraStream} = setupLobbyTest();
|
|
3102
|
+
|
|
3103
|
+
const audioSlot = {
|
|
3104
|
+
publishStream: sinon.stub(),
|
|
3105
|
+
unpublishStream: sinon.stub(),
|
|
3106
|
+
setNamedMediaGroups: sinon.stub(),
|
|
3107
|
+
};
|
|
3108
|
+
const videoSlot = {
|
|
3109
|
+
publishStream: sinon.stub(),
|
|
3110
|
+
unpublishStream: sinon.stub(),
|
|
3111
|
+
setNamedMediaGroups: sinon.stub(),
|
|
3112
|
+
};
|
|
3113
|
+
|
|
3114
|
+
fakeMediaConnection.createSendSlot = sinon.stub().callsFake((mediaType) => {
|
|
3115
|
+
if (mediaType === 'AUDIO-MAIN') {
|
|
3116
|
+
return audioSlot;
|
|
3117
|
+
}
|
|
3118
|
+
return videoSlot;
|
|
3119
|
+
});
|
|
3120
|
+
|
|
3121
|
+
await meeting.addMedia({
|
|
3122
|
+
allowMediaInLobby: true,
|
|
3123
|
+
allowPublishMediaInLobby: true,
|
|
3124
|
+
audioEnabled: true,
|
|
3125
|
+
videoEnabled: true,
|
|
3126
|
+
localStreams: {
|
|
3127
|
+
microphone: fakeMicrophoneStream,
|
|
3128
|
+
camera: fakeCameraStream,
|
|
3129
|
+
},
|
|
3130
|
+
});
|
|
3131
|
+
|
|
3132
|
+
assert.calledOnceWithExactly(audioSlot.publishStream, fakeMicrophoneStream);
|
|
3133
|
+
assert.calledOnceWithExactly(videoSlot.publishStream, fakeCameraStream);
|
|
3134
|
+
});
|
|
3135
|
+
|
|
3031
3136
|
it('should create rtcMetrics and pass them to Media.createMediaConnection()', async () => {
|
|
3032
3137
|
const setIntervalOriginal = window.setInterval;
|
|
3033
3138
|
window.setInterval = sinon.stub().returns(1);
|