@webex/plugin-meetings 3.0.0-beta.43 → 3.0.0-beta.44

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.
Files changed (43) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +10 -2
  3. package/dist/breakouts/index.js.map +1 -1
  4. package/dist/constants.js +6 -1
  5. package/dist/constants.js.map +1 -1
  6. package/dist/locus-info/controlsUtils.js +6 -2
  7. package/dist/locus-info/controlsUtils.js.map +1 -1
  8. package/dist/locus-info/index.js +35 -1
  9. package/dist/locus-info/index.js.map +1 -1
  10. package/dist/locus-info/selfUtils.js +28 -0
  11. package/dist/locus-info/selfUtils.js.map +1 -1
  12. package/dist/meeting/index.js +38 -3
  13. package/dist/meeting/index.js.map +1 -1
  14. package/dist/meeting/muteState.js +45 -20
  15. package/dist/meeting/muteState.js.map +1 -1
  16. package/dist/members/index.js +15 -3
  17. package/dist/members/index.js.map +1 -1
  18. package/dist/members/util.js +33 -12
  19. package/dist/members/util.js.map +1 -1
  20. package/dist/types/constants.d.ts +5 -0
  21. package/dist/types/locus-info/index.d.ts +7 -0
  22. package/dist/types/meeting/index.d.ts +12 -2
  23. package/dist/types/meeting/muteState.d.ts +16 -0
  24. package/dist/types/members/index.d.ts +7 -2
  25. package/package.json +18 -18
  26. package/src/breakouts/index.ts +6 -0
  27. package/src/constants.ts +5 -0
  28. package/src/locus-info/controlsUtils.ts +8 -0
  29. package/src/locus-info/index.ts +42 -1
  30. package/src/locus-info/selfUtils.ts +34 -0
  31. package/src/meeting/index.ts +45 -4
  32. package/src/meeting/muteState.ts +49 -30
  33. package/src/members/index.ts +12 -4
  34. package/src/members/util.ts +21 -8
  35. package/test/unit/spec/breakouts/index.ts +2 -2
  36. package/test/unit/spec/locus-info/controlsUtils.js +104 -46
  37. package/test/unit/spec/locus-info/index.js +131 -16
  38. package/test/unit/spec/locus-info/selfConstant.js +9 -5
  39. package/test/unit/spec/locus-info/selfUtils.js +39 -16
  40. package/test/unit/spec/meeting/index.js +208 -79
  41. package/test/unit/spec/meeting/muteState.js +72 -6
  42. package/test/unit/spec/members/index.js +75 -0
  43. package/test/unit/spec/members/utils.js +112 -0
@@ -23,7 +23,15 @@ import {
23
23
  PC_BAIL_TIMEOUT,
24
24
  } from '@webex/plugin-meetings/src/constants';
25
25
  import * as InternalMediaCoreModule from '@webex/internal-media-core';
26
- import {ConnectionState, Event, Errors, ErrorType, LocalTrackEvents, RemoteTrackType, MediaType} from '@webex/internal-media-core';
26
+ import {
27
+ ConnectionState,
28
+ Event,
29
+ Errors,
30
+ ErrorType,
31
+ LocalTrackEvents,
32
+ RemoteTrackType,
33
+ MediaType,
34
+ } from '@webex/internal-media-core';
27
35
  import * as StatsAnalyzerModule from '@webex/plugin-meetings/src/statsAnalyzer';
28
36
  import * as MuteStateModule from '@webex/plugin-meetings/src/meeting/muteState';
29
37
  import EventsScope from '@webex/plugin-meetings/src/common/events/events-scope';
@@ -197,9 +205,9 @@ describe('plugin-meetings', () => {
197
205
  Metrics.initialSetup(null, webex);
198
206
  MediaUtil.createMediaStream = sinon.stub().callsFake((tracks) => {
199
207
  return {
200
- getTracks: () => tracks
208
+ getTracks: () => tracks,
201
209
  };
202
- });;
210
+ });
203
211
 
204
212
  uuid1 = uuid.v4();
205
213
  uuid2 = uuid.v4();
@@ -281,12 +289,14 @@ describe('plugin-meetings', () => {
281
289
  let providedFindMemberIdByCsiCallback;
282
290
 
283
291
  beforeEach(() => {
284
- mockReceiveSlotManagerCtor = sinon.stub(ReceiveSlotManagerModule, 'ReceiveSlotManager').callsFake((createSlotCallback, findMemberIdByCsiCallback) => {
285
- providedCreateSlotCallback = createSlotCallback;
286
- providedFindMemberIdByCsiCallback = findMemberIdByCsiCallback;
292
+ mockReceiveSlotManagerCtor = sinon
293
+ .stub(ReceiveSlotManagerModule, 'ReceiveSlotManager')
294
+ .callsFake((createSlotCallback, findMemberIdByCsiCallback) => {
295
+ providedCreateSlotCallback = createSlotCallback;
296
+ providedFindMemberIdByCsiCallback = findMemberIdByCsiCallback;
287
297
 
288
- return {updateMemberIds: sinon.stub()};
289
- });
298
+ return {updateMemberIds: sinon.stub()};
299
+ });
290
300
 
291
301
  meeting = new Meeting(
292
302
  {
@@ -317,7 +327,10 @@ describe('plugin-meetings', () => {
317
327
  await providedCreateSlotCallback(MediaType.VideoMain);
318
328
 
319
329
  assert.calledOnce(meeting.mediaProperties.webrtcMediaConnection.createReceiveSlot);
320
- assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.createReceiveSlot, MediaType.VideoMain);
330
+ assert.calledWith(
331
+ meeting.mediaProperties.webrtcMediaConnection.createReceiveSlot,
332
+ MediaType.VideoMain
333
+ );
321
334
  });
322
335
 
323
336
  it('rejects createSlotCallback if there is no webrtc media connection', () => {
@@ -333,7 +346,7 @@ describe('plugin-meetings', () => {
333
346
 
334
347
  const fakeMember = {id: 'aaa-bbb'};
335
348
 
336
- sinon.stub(meeting.members, 'findMemberByCsi').returns(fakeMember)
349
+ sinon.stub(meeting.members, 'findMemberByCsi').returns(fakeMember);
337
350
 
338
351
  const memberId = providedFindMemberIdByCsiCallback(123);
339
352
 
@@ -345,7 +358,7 @@ describe('plugin-meetings', () => {
345
358
  it('returns undefined if findMemberByCsi does not find the member', () => {
346
359
  assert.isDefined(providedFindMemberIdByCsiCallback);
347
360
 
348
- sinon.stub(meeting.members, 'findMemberByCsi').returns(undefined)
361
+ sinon.stub(meeting.members, 'findMemberByCsi').returns(undefined);
349
362
 
350
363
  const memberId = providedFindMemberIdByCsiCallback(123);
351
364
 
@@ -353,7 +366,7 @@ describe('plugin-meetings', () => {
353
366
  assert.calledWith(meeting.members.findMemberByCsi, 123);
354
367
  assert.equal(memberId, undefined);
355
368
  });
356
- })
369
+ });
357
370
  });
358
371
  describe('#invite', () => {
359
372
  it('should have #invite', () => {
@@ -402,6 +415,18 @@ describe('plugin-meetings', () => {
402
415
  assert.calledOnce(meeting.members.admitMembers);
403
416
  assert.calledWith(meeting.members.admitMembers, [uuid1]);
404
417
  });
418
+ it('should call from a breakout session if caller is in a breakout session', async () => {
419
+ const locusUrls = {authorizingLocusUrl: 'authorizingLocusUrl', mainLocusUrl: 'mainLocusUrl'};
420
+ await meeting.admit([uuid1], locusUrls);
421
+ assert.calledOnce(meeting.members.admitMembers);
422
+ assert.calledWith(meeting.members.admitMembers, [uuid1], locusUrls);
423
+
424
+ meeting.breakouts.set('locusUrl', 'authorizingLocusUrl');
425
+ meeting.breakouts.set('mainLocusUrl', 'mainLocusUrl');
426
+ await meeting.admit([uuid1]);
427
+ const args = meeting.members.admitMembers.getCall(1).args;
428
+ assert.deepEqual(args, [[uuid1], locusUrls]);
429
+ });
405
430
  });
406
431
  describe('#getMembers', () => {
407
432
  it('should have #getMembers', () => {
@@ -866,7 +891,7 @@ describe('plugin-meetings', () => {
866
891
  relayType: REACTION_RELAY_TYPES.REACTION,
867
892
  reaction: fakeReactionPayload,
868
893
  sender: fakeSenderPayload,
869
- }
894
+ },
870
895
  };
871
896
  meeting.processRelayEvent(fakeRelayEvent);
872
897
  assert.calledWith(
@@ -879,8 +904,8 @@ describe('plugin-meetings', () => {
879
904
  EVENT_TRIGGERS.MEETING_RECEIVE_REACTIONS,
880
905
  fakeProcessedReaction
881
906
  );
882
- })
883
- })
907
+ });
908
+ });
884
909
  describe('#join', () => {
885
910
  let sandbox = null;
886
911
  const joinMeetingResult = 'JOIN_MEETINGS_OPTION_RESULT';
@@ -931,7 +956,11 @@ describe('plugin-meetings', () => {
931
956
  await meeting.join();
932
957
 
933
958
  assert.calledOnce(meeting.updateLLMConnection);
934
- assert.calledOnceWithExactly(meeting.webex.internal.llm.on, 'event:relay.event', meeting.processRelayEvent);
959
+ assert.calledOnceWithExactly(
960
+ meeting.webex.internal.llm.on,
961
+ 'event:relay.event',
962
+ meeting.processRelayEvent
963
+ );
935
964
  });
936
965
 
937
966
  it('should not call updateLLMConnection upon joining if config value is not set', async () => {
@@ -1285,9 +1314,7 @@ describe('plugin-meetings', () => {
1285
1314
 
1286
1315
  it('should attach the media and return WebExMeetingsErrors when connection does not reach CONNECTED state', async () => {
1287
1316
  meeting.meetingState = 'ACTIVE';
1288
- fakeMediaConnection.getConnectionState = sinon
1289
- .stub()
1290
- .returns(ConnectionState.Connecting);
1317
+ fakeMediaConnection.getConnectionState = sinon.stub().returns(ConnectionState.Connecting);
1291
1318
  const clock = sinon.useFakeTimers();
1292
1319
  const media = meeting.addMedia({
1293
1320
  mediaSettings: {},
@@ -1714,11 +1741,10 @@ describe('plugin-meetings', () => {
1714
1741
  const fakeLocalDisplayTrack = {
1715
1742
  on: sinon.stub().callsFake((event, listener) => {
1716
1743
  listeners[event] = listener;
1717
- })
1744
+ }),
1718
1745
  };
1719
1746
  sinon.stub(InternalMediaCoreModule, 'LocalDisplayTrack').returns(fakeLocalDisplayTrack);
1720
1747
 
1721
-
1722
1748
  sandbox.stub(mediaProperties, 'setLocalShareTrack');
1723
1749
  sandbox.stub(mediaProperties, 'setMediaSettings');
1724
1750
  sandbox.stub(meeting, 'stopShare').resolves(true);
@@ -2144,7 +2170,7 @@ describe('plugin-meetings', () => {
2144
2170
  screenshareVideo: {
2145
2171
  id: 'fake share track',
2146
2172
  getSettings: sinon.stub().returns({}),
2147
- on: sinon.stub()
2173
+ on: sinon.stub(),
2148
2174
  },
2149
2175
  };
2150
2176
 
@@ -2232,7 +2258,7 @@ describe('plugin-meetings', () => {
2232
2258
  const eventListeners = {};
2233
2259
 
2234
2260
  meeting.webex.meetings.reachability = {
2235
- isAnyClusterReachable: sandbox.stub().resolves(true)
2261
+ isAnyClusterReachable: sandbox.stub().resolves(true),
2236
2262
  };
2237
2263
 
2238
2264
  const fakeMediaConnection = {
@@ -2250,7 +2276,7 @@ describe('plugin-meetings', () => {
2250
2276
  if (eventListeners[Event.ROAP_STARTED]) {
2251
2277
  eventListeners[Event.ROAP_STARTED]();
2252
2278
  } else {
2253
- throw new Error('ROAP_STARTED listener not registered')
2279
+ throw new Error('ROAP_STARTED listener not registered');
2254
2280
  }
2255
2281
  return Promise.resolve();
2256
2282
  }),
@@ -2260,7 +2286,9 @@ describe('plugin-meetings', () => {
2260
2286
  meeting.mediaProperties.getCurrentConnectionType = sinon.stub().resolves('udp');
2261
2287
  Media.createMediaConnection = sinon.stub().returns(fakeMediaConnection);
2262
2288
 
2263
- const requestScreenShareFloorStub = sandbox.stub(meeting, 'requestScreenShareFloor').resolves({});
2289
+ const requestScreenShareFloorStub = sandbox
2290
+ .stub(meeting, 'requestScreenShareFloor')
2291
+ .resolves({});
2264
2292
 
2265
2293
  let myPromiseResolved = false;
2266
2294
 
@@ -2322,7 +2350,7 @@ describe('plugin-meetings', () => {
2322
2350
  });
2323
2351
 
2324
2352
  meeting.webex.meetings.reachability = {
2325
- isAnyClusterReachable: sinon.stub().resolves(true)
2353
+ isAnyClusterReachable: sinon.stub().resolves(true),
2326
2354
  };
2327
2355
 
2328
2356
  fakeMediaConnection = {
@@ -2340,7 +2368,7 @@ describe('plugin-meetings', () => {
2340
2368
  if (eventListeners[Event.ROAP_STARTED]) {
2341
2369
  eventListeners[Event.ROAP_STARTED]();
2342
2370
  } else {
2343
- throw new Error('ROAP_STARTED listener not registered')
2371
+ throw new Error('ROAP_STARTED listener not registered');
2344
2372
  }
2345
2373
  return Promise.resolve();
2346
2374
  }),
@@ -2394,7 +2422,9 @@ describe('plugin-meetings', () => {
2394
2422
  let myPromiseResolved = false;
2395
2423
 
2396
2424
  // simulate a case when no roap transaction is triggered by updateSendReceiveOptions
2397
- meeting.mediaProperties.webrtcMediaConnection.updateSendReceiveOptions = sinon.stub().resolves({});
2425
+ meeting.mediaProperties.webrtcMediaConnection.updateSendReceiveOptions = sinon
2426
+ .stub()
2427
+ .resolves({});
2398
2428
 
2399
2429
  meeting
2400
2430
  .updateShare({
@@ -3615,7 +3645,11 @@ describe('plugin-meetings', () => {
3615
3645
  };
3616
3646
  meeting.requestScreenShareFloor = sinon.stub().resolves({});
3617
3647
  meeting.releaseScreenShareFloor = sinon.stub().resolves({});
3618
- meeting.mediaProperties.mediaDirection = {sendAudio: false, sendVideo: false, sendShare: false};
3648
+ meeting.mediaProperties.mediaDirection = {
3649
+ sendAudio: false,
3650
+ sendVideo: false,
3651
+ sendShare: false,
3652
+ };
3619
3653
  meeting.mediaProperties.webrtcMediaConnection = {
3620
3654
  publishTrack: sinon.stub().resolves({}),
3621
3655
  unpublishTrack: sinon.stub().resolves({}),
@@ -3625,26 +3659,34 @@ describe('plugin-meetings', () => {
3625
3659
  on: sinon.stub(),
3626
3660
  off: sinon.stub(),
3627
3661
  stop: sinon.stub(),
3628
- originalTrack
3662
+ originalTrack,
3629
3663
  });
3630
3664
 
3631
3665
  // setup mock constructors for webrtc-core local track classes in such a way
3632
3666
  // that they return the original track correctly (this is needed for unpublish() API tests)
3633
- LocalDisplayTrackConstructorStub = sinon.stub(InternalMediaCoreModule, 'LocalDisplayTrack').callsFake((stream) => {
3634
- fakeLocalDisplayTrack = createFakeLocalTrack(stream.getTracks()[0])
3635
- return fakeLocalDisplayTrack;
3636
- });
3637
- LocalMicrophoneTrackConstructorStub = sinon.stub(InternalMediaCoreModule, 'LocalMicrophoneTrack').callsFake((stream) => {
3638
- fakeLocalMicrophoneTrack = createFakeLocalTrack(stream.getTracks()[0])
3639
- return fakeLocalMicrophoneTrack;
3640
- });
3641
- LocalCameraTrackConstructorStub = sinon.stub(InternalMediaCoreModule, 'LocalCameraTrack').callsFake((stream) => {
3642
- fakeLocalCameraTrack = createFakeLocalTrack(stream.getTracks()[0])
3643
- return fakeLocalCameraTrack;
3644
- });
3667
+ LocalDisplayTrackConstructorStub = sinon
3668
+ .stub(InternalMediaCoreModule, 'LocalDisplayTrack')
3669
+ .callsFake((stream) => {
3670
+ fakeLocalDisplayTrack = createFakeLocalTrack(stream.getTracks()[0]);
3671
+ return fakeLocalDisplayTrack;
3672
+ });
3673
+ LocalMicrophoneTrackConstructorStub = sinon
3674
+ .stub(InternalMediaCoreModule, 'LocalMicrophoneTrack')
3675
+ .callsFake((stream) => {
3676
+ fakeLocalMicrophoneTrack = createFakeLocalTrack(stream.getTracks()[0]);
3677
+ return fakeLocalMicrophoneTrack;
3678
+ });
3679
+ LocalCameraTrackConstructorStub = sinon
3680
+ .stub(InternalMediaCoreModule, 'LocalCameraTrack')
3681
+ .callsFake((stream) => {
3682
+ fakeLocalCameraTrack = createFakeLocalTrack(stream.getTracks()[0]);
3683
+ return fakeLocalCameraTrack;
3684
+ });
3645
3685
 
3646
- createMuteStateStub = sinon.stub(MuteStateModule, 'createMuteState').returns({id: 'fake mute state instance'});
3647
- })
3686
+ createMuteStateStub = sinon
3687
+ .stub(MuteStateModule, 'createMuteState')
3688
+ .returns({id: 'fake mute state instance'});
3689
+ });
3648
3690
  describe('#publishTracks', () => {
3649
3691
  it('fails if there is no media connection', async () => {
3650
3692
  meeting.mediaProperties.webrtcMediaConnection = undefined;
@@ -3655,21 +3697,37 @@ describe('plugin-meetings', () => {
3655
3697
  assert.calledWith(MediaUtil.createMediaStream, [audioTrack]);
3656
3698
  assert.calledOnce(LocalMicrophoneTrackConstructorStub);
3657
3699
 
3658
- assert.calledWith(createMuteStateStub, 'audio', meeting, meeting.mediaProperties.mediaDirection);
3659
- assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, fakeLocalMicrophoneTrack);
3700
+ assert.calledWith(
3701
+ createMuteStateStub,
3702
+ 'audio',
3703
+ meeting,
3704
+ meeting.mediaProperties.mediaDirection
3705
+ );
3706
+ assert.calledWith(
3707
+ meeting.mediaProperties.webrtcMediaConnection.publishTrack,
3708
+ fakeLocalMicrophoneTrack
3709
+ );
3660
3710
  assert.equal(meeting.mediaProperties.audioTrack, fakeLocalMicrophoneTrack);
3661
3711
  assert.equal(meeting.mediaProperties.mediaDirection.sendAudio, true);
3662
- }
3712
+ };
3663
3713
 
3664
3714
  const checkVideoPublished = () => {
3665
3715
  assert.calledWith(MediaUtil.createMediaStream, [videoTrack]);
3666
3716
  assert.calledOnce(LocalCameraTrackConstructorStub);
3667
3717
 
3668
- assert.calledWith(createMuteStateStub, 'video', meeting, meeting.mediaProperties.mediaDirection);
3669
- assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, fakeLocalCameraTrack);
3718
+ assert.calledWith(
3719
+ createMuteStateStub,
3720
+ 'video',
3721
+ meeting,
3722
+ meeting.mediaProperties.mediaDirection
3723
+ );
3724
+ assert.calledWith(
3725
+ meeting.mediaProperties.webrtcMediaConnection.publishTrack,
3726
+ fakeLocalCameraTrack
3727
+ );
3670
3728
  assert.equal(meeting.mediaProperties.videoTrack, fakeLocalCameraTrack);
3671
3729
  assert.equal(meeting.mediaProperties.mediaDirection.sendVideo, true);
3672
- }
3730
+ };
3673
3731
 
3674
3732
  const checkScreenShareVideoPublished = () => {
3675
3733
  assert.calledOnce(meeting.requestScreenShareFloor);
@@ -3677,10 +3735,13 @@ describe('plugin-meetings', () => {
3677
3735
  assert.calledWith(MediaUtil.createMediaStream, [videoShareTrack]);
3678
3736
  assert.calledOnce(LocalDisplayTrackConstructorStub);
3679
3737
 
3680
- assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, fakeLocalDisplayTrack);
3738
+ assert.calledWith(
3739
+ meeting.mediaProperties.webrtcMediaConnection.publishTrack,
3740
+ fakeLocalDisplayTrack
3741
+ );
3681
3742
  assert.equal(meeting.mediaProperties.shareTrack, fakeLocalDisplayTrack);
3682
3743
  assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
3683
- }
3744
+ };
3684
3745
 
3685
3746
  it('requests screen share floor and publishes the screen share video track', async () => {
3686
3747
  await meeting.publishTracks({screenShare: {video: videoShareTrack}});
@@ -3711,7 +3772,7 @@ describe('plugin-meetings', () => {
3711
3772
  camera: videoTrack,
3712
3773
  screenShare: {
3713
3774
  video: videoShareTrack,
3714
- }
3775
+ },
3715
3776
  });
3716
3777
 
3717
3778
  assert.calledTwice(createMuteStateStub);
@@ -3719,7 +3780,7 @@ describe('plugin-meetings', () => {
3719
3780
  checkAudioPublished();
3720
3781
  checkVideoPublished();
3721
3782
  checkScreenShareVideoPublished();
3722
- })
3783
+ });
3723
3784
  });
3724
3785
 
3725
3786
  describe('unpublishTracks', () => {
@@ -3727,36 +3788,47 @@ describe('plugin-meetings', () => {
3727
3788
  await meeting.publishTracks({
3728
3789
  microphone: audioTrack,
3729
3790
  camera: videoTrack,
3730
- screenShare: {video: videoShareTrack}
3791
+ screenShare: {video: videoShareTrack},
3731
3792
  });
3732
3793
  });
3733
3794
 
3734
3795
  const checkAudioUnpublished = () => {
3735
- assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack, fakeLocalMicrophoneTrack);
3796
+ assert.calledWith(
3797
+ meeting.mediaProperties.webrtcMediaConnection.unpublishTrack,
3798
+ fakeLocalMicrophoneTrack
3799
+ );
3736
3800
 
3737
3801
  assert.equal(meeting.mediaProperties.audioTrack, null);
3738
3802
  assert.equal(meeting.mediaProperties.mediaDirection.sendAudio, false);
3739
3803
  };
3740
3804
 
3741
3805
  const checkVideoUnpublished = () => {
3742
- assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack, fakeLocalCameraTrack);
3806
+ assert.calledWith(
3807
+ meeting.mediaProperties.webrtcMediaConnection.unpublishTrack,
3808
+ fakeLocalCameraTrack
3809
+ );
3743
3810
 
3744
3811
  assert.equal(meeting.mediaProperties.videoTrack, null);
3745
3812
  assert.equal(meeting.mediaProperties.mediaDirection.sendVideo, false);
3746
- }
3813
+ };
3747
3814
 
3748
3815
  const checkScreenShareVideoUnpublished = () => {
3749
- assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack, fakeLocalDisplayTrack);
3816
+ assert.calledWith(
3817
+ meeting.mediaProperties.webrtcMediaConnection.unpublishTrack,
3818
+ fakeLocalDisplayTrack
3819
+ );
3750
3820
 
3751
3821
  assert.calledOnce(meeting.requestScreenShareFloor);
3752
3822
 
3753
3823
  assert.equal(meeting.mediaProperties.shareTrack, null);
3754
3824
  assert.equal(meeting.mediaProperties.mediaDirection.sendShare, false);
3755
- }
3825
+ };
3756
3826
 
3757
3827
  it('fails if there is no media connection', async () => {
3758
3828
  meeting.mediaProperties.webrtcMediaConnection = undefined;
3759
- await assert.isRejected(meeting.unpublishTracks([audioTrack, videoTrack, videoShareTrack]));
3829
+ await assert.isRejected(
3830
+ meeting.unpublishTracks([audioTrack, videoTrack, videoShareTrack])
3831
+ );
3760
3832
  });
3761
3833
 
3762
3834
  it('un-publishes the tracks correctly (all 3 together)', async () => {
@@ -3780,15 +3852,15 @@ describe('plugin-meetings', () => {
3780
3852
 
3781
3853
  assert.calledOnce(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack);
3782
3854
  checkVideoUnpublished();
3783
- })
3855
+ });
3784
3856
 
3785
3857
  it('un-publishes the screen share video track correctly', async () => {
3786
3858
  await meeting.unpublishTracks([videoShareTrack]);
3787
3859
 
3788
3860
  assert.calledOnce(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack);
3789
3861
  checkScreenShareVideoUnpublished();
3790
- })
3791
- })
3862
+ });
3863
+ });
3792
3864
  });
3793
3865
  });
3794
3866
 
@@ -3985,12 +4057,11 @@ describe('plugin-meetings', () => {
3985
4057
  const listeners = {};
3986
4058
  const fakeLocalDisplayTrack = {
3987
4059
  on: sinon.stub().callsFake((event, listener) => {
3988
- listeners[event] = listener;
3989
- })
4060
+ listeners[event] = listener;
4061
+ }),
3990
4062
  };
3991
4063
  sinon.stub(InternalMediaCoreModule, 'LocalDisplayTrack').returns(fakeLocalDisplayTrack);
3992
4064
 
3993
-
3994
4065
  meeting.mediaProperties.setLocalShareTrack = sinon.stub().returns(true);
3995
4066
  meeting.stopShare = sinon.stub().resolves(true);
3996
4067
  meeting.mediaProperties.mediaDirection = {};
@@ -4394,7 +4465,11 @@ describe('plugin-meetings', () => {
4394
4465
 
4395
4466
  const payload = 'payload';
4396
4467
 
4397
- meeting.locusInfo.emit({function: 'test', file: 'test'}, 'SELF_MEETING_BREAKOUTS_CHANGED', payload);
4468
+ meeting.locusInfo.emit(
4469
+ {function: 'test', file: 'test'},
4470
+ 'SELF_MEETING_BREAKOUTS_CHANGED',
4471
+ payload
4472
+ );
4398
4473
 
4399
4474
  assert.calledOnceWithExactly(meeting.breakouts.updateBreakoutSessions, payload);
4400
4475
  assert.calledWith(
@@ -4451,11 +4526,15 @@ describe('plugin-meetings', () => {
4451
4526
  describe('#setupLocusControlsListener', () => {
4452
4527
  it('listens to the locus breakouts update event', () => {
4453
4528
  const locus = {
4454
- breakout: 'breakout'
4529
+ breakout: 'breakout',
4455
4530
  };
4456
4531
 
4457
4532
  meeting.breakouts.updateBreakout = sinon.stub();
4458
- meeting.locusInfo.emit({function: 'test', file: 'test'}, 'CONTROLS_MEETING_BREAKOUT_UPDATED', locus);
4533
+ meeting.locusInfo.emit(
4534
+ {function: 'test', file: 'test'},
4535
+ 'CONTROLS_MEETING_BREAKOUT_UPDATED',
4536
+ locus
4537
+ );
4459
4538
 
4460
4539
  assert.calledOnceWithExactly(meeting.breakouts.updateBreakout, locus.breakout);
4461
4540
  assert.calledWith(
@@ -4477,11 +4556,12 @@ describe('plugin-meetings', () => {
4477
4556
 
4478
4557
  meeting.breakouts.locusUrlUpdate = sinon.stub();
4479
4558
 
4480
- meeting.locusInfo.emit({function: 'test', file: 'test'}, 'LOCUS_INFO_UPDATE_URL', newLocusUrl);
4481
- assert.calledWith(
4482
- meeting.members.locusUrlUpdate,
4559
+ meeting.locusInfo.emit(
4560
+ {function: 'test', file: 'test'},
4561
+ 'LOCUS_INFO_UPDATE_URL',
4483
4562
  newLocusUrl
4484
4563
  );
4564
+ assert.calledWith(meeting.members.locusUrlUpdate, newLocusUrl);
4485
4565
  assert.calledOnceWithExactly(meeting.breakouts.locusUrlUpdate, newLocusUrl);
4486
4566
  assert.calledWith(meeting.members.locusUrlUpdate, newLocusUrl);
4487
4567
  assert.calledWith(meeting.recordingController.setLocusUrl, newLocusUrl);
@@ -4495,14 +4575,17 @@ describe('plugin-meetings', () => {
4495
4575
  describe('#setUpLocusServicesListener', () => {
4496
4576
  it('listens to the locus services update event', (done) => {
4497
4577
  const newLocusServices = {
4498
- services: {
4499
- record: {
4500
- url: 'url',
4501
- }
4578
+ services: {
4579
+ record: {
4580
+ url: 'url',
4502
4581
  },
4582
+ },
4503
4583
  };
4504
4584
 
4505
- meeting.recordingController = {setServiceUrl: sinon.stub().returns(undefined), setSessionId: sinon.stub().returns(undefined)};
4585
+ meeting.recordingController = {
4586
+ setServiceUrl: sinon.stub().returns(undefined),
4587
+ setSessionId: sinon.stub().returns(undefined),
4588
+ };
4506
4589
 
4507
4590
  meeting.locusInfo.emit(
4508
4591
  {function: 'test', file: 'test'},
@@ -4510,7 +4593,10 @@ describe('plugin-meetings', () => {
4510
4593
  newLocusServices
4511
4594
  );
4512
4595
 
4513
- assert.calledWith(meeting.recordingController.setServiceUrl, newLocusServices.services.record.url);
4596
+ assert.calledWith(
4597
+ meeting.recordingController.setServiceUrl,
4598
+ newLocusServices.services.record.url
4599
+ );
4514
4600
  assert.calledOnce(meeting.recordingController.setSessionId);
4515
4601
  done();
4516
4602
  });
@@ -6296,6 +6382,49 @@ describe('plugin-meetings', () => {
6296
6382
  });
6297
6383
  });
6298
6384
  });
6385
+
6386
+ describe('SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED locus event', () => {
6387
+ let spy;
6388
+
6389
+ beforeEach('setup sinon', () => {
6390
+ spy = sinon.spy();
6391
+ });
6392
+
6393
+ const testEmit = async (muted) => {
6394
+ await meeting.locusInfo.emitScoped(
6395
+ {},
6396
+ LOCUSINFO.EVENTS.SELF_REMOTE_VIDEO_MUTE_STATUS_UPDATED,
6397
+ {
6398
+ muted,
6399
+ }
6400
+ );
6401
+
6402
+ assert.calledWith(
6403
+ TriggerProxy.trigger,
6404
+ sinon.match.instanceOf(Meeting),
6405
+ {
6406
+ file: 'meeting/index',
6407
+ function: 'setUpLocusInfoSelfListener',
6408
+ },
6409
+ muted
6410
+ ? EVENT_TRIGGERS.MEETING_SELF_VIDEO_MUTED_BY_OTHERS
6411
+ : EVENT_TRIGGERS.MEETING_SELF_VIDEO_UNMUTED_BY_OTHERS,
6412
+ {
6413
+ payload: {
6414
+ muted,
6415
+ },
6416
+ }
6417
+ );
6418
+ };
6419
+
6420
+ it('emits the expected event when muted', async () => {
6421
+ await testEmit(true);
6422
+ });
6423
+
6424
+ it('emits the expected event when not muted', async () => {
6425
+ await testEmit(false);
6426
+ });
6427
+ });
6299
6428
  });
6300
6429
  });
6301
6430
  });