@webex/plugin-meetings 3.8.0-next.2 → 3.8.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.
Files changed (60) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/config.js +1 -0
  4. package/dist/config.js.map +1 -1
  5. package/dist/constants.js +1 -0
  6. package/dist/constants.js.map +1 -1
  7. package/dist/interpretation/index.js +4 -4
  8. package/dist/interpretation/index.js.map +1 -1
  9. package/dist/interpretation/siLanguage.js +1 -1
  10. package/dist/locus-info/controlsUtils.js +1 -1
  11. package/dist/locus-info/controlsUtils.js.map +1 -1
  12. package/dist/meeting/index.js +69 -4
  13. package/dist/meeting/index.js.map +1 -1
  14. package/dist/meeting/locusMediaRequest.js +21 -5
  15. package/dist/meeting/locusMediaRequest.js.map +1 -1
  16. package/dist/meeting/util.js +2 -0
  17. package/dist/meeting/util.js.map +1 -1
  18. package/dist/meetings/index.js +1 -1
  19. package/dist/meetings/index.js.map +1 -1
  20. package/dist/multistream/remoteMediaManager.js +40 -8
  21. package/dist/multistream/remoteMediaManager.js.map +1 -1
  22. package/dist/reachability/clusterReachability.js +52 -8
  23. package/dist/reachability/clusterReachability.js.map +1 -1
  24. package/dist/reachability/index.js +70 -45
  25. package/dist/reachability/index.js.map +1 -1
  26. package/dist/reachability/reachability.types.js +14 -0
  27. package/dist/reachability/reachability.types.js.map +1 -1
  28. package/dist/recording-controller/util.js +5 -5
  29. package/dist/recording-controller/util.js.map +1 -1
  30. package/dist/types/config.d.ts +1 -0
  31. package/dist/types/constants.d.ts +1 -0
  32. package/dist/types/meeting/index.d.ts +30 -0
  33. package/dist/types/multistream/remoteMediaManager.d.ts +10 -1
  34. package/dist/types/reachability/clusterReachability.d.ts +13 -1
  35. package/dist/types/reachability/index.d.ts +2 -1
  36. package/dist/types/reachability/reachability.types.d.ts +5 -0
  37. package/dist/webinar/index.js +1 -1
  38. package/package.json +22 -22
  39. package/src/config.ts +1 -0
  40. package/src/constants.ts +1 -0
  41. package/src/interpretation/index.ts +3 -3
  42. package/src/locus-info/controlsUtils.ts +2 -2
  43. package/src/meeting/index.ts +66 -3
  44. package/src/meeting/locusMediaRequest.ts +27 -4
  45. package/src/meeting/util.ts +1 -1
  46. package/src/meetings/index.ts +1 -1
  47. package/src/multistream/remoteMediaManager.ts +32 -10
  48. package/src/reachability/clusterReachability.ts +47 -1
  49. package/src/reachability/index.ts +15 -0
  50. package/src/reachability/reachability.types.ts +6 -0
  51. package/src/recording-controller/util.ts +17 -13
  52. package/test/unit/spec/interpretation/index.ts +39 -1
  53. package/test/unit/spec/locus-info/controlsUtils.js +8 -0
  54. package/test/unit/spec/meeting/index.js +185 -108
  55. package/test/unit/spec/meeting/locusMediaRequest.ts +96 -58
  56. package/test/unit/spec/meeting/utils.js +44 -0
  57. package/test/unit/spec/meetings/index.js +13 -0
  58. package/test/unit/spec/multistream/remoteMediaManager.ts +397 -118
  59. package/test/unit/spec/reachability/clusterReachability.ts +47 -1
  60. package/test/unit/spec/reachability/index.ts +12 -0
@@ -22,16 +22,54 @@ describe('plugin-meetings', () => {
22
22
  });
23
23
 
24
24
  describe('#initialize', () => {
25
+ beforeEach(() => {
26
+ interpretation.querySupportLanguages = sinon.stub();
27
+ interpretation.set({
28
+ canManageInterpreters: undefined,
29
+ hostSIEnabled: undefined,
30
+ locusUrl: undefined
31
+ });
32
+ });
33
+
34
+ afterEach(() => {
35
+ interpretation.querySupportLanguages.reset();
36
+ });
37
+
25
38
  it('creates SimultaneousInterpretation as expected', () => {
26
39
  assert.equal(interpretation.namespace, 'Meetings');
27
40
  });
28
41
  it('call querySupportLanguages correctly when meet the conditions', () => {
29
- interpretation.querySupportLanguages = sinon.stub();
30
42
  interpretation.set({
31
43
  canManageInterpreters: true,
44
+ hostSIEnabled: true,
45
+ locusUrl: "MOCK_LOCUS_URL"
32
46
  });
33
47
  assert.called(interpretation.querySupportLanguages);
34
48
  });
49
+
50
+ it('does not call querySupportLanguages when canManageInterpreters is not set', () => {
51
+ interpretation.set({
52
+ hostSIEnabled: true,
53
+ locusUrl: "MOCK_LOCUS_URL"
54
+ });
55
+ assert.notCalled(interpretation.querySupportLanguages);
56
+ });
57
+
58
+ it('does not call querySupportLanguages when hostSIEnabled is not set', () => {
59
+ interpretation.set({
60
+ canManageInterpreters: true,
61
+ locusUrl: "MOCK_LOCUS_URL"
62
+ });
63
+ assert.notCalled(interpretation.querySupportLanguages);
64
+ });
65
+
66
+ it('does not call querySupportLanguages when locusUrl is not set', () => {
67
+ interpretation.set({
68
+ canManageInterpreters: true,
69
+ hostSIEnabled: true,
70
+ });
71
+ assert.notCalled(interpretation.querySupportLanguages);
72
+ });
35
73
  });
36
74
 
37
75
  describe('#cleanUp', () => {
@@ -269,6 +269,14 @@ describe('plugin-meetings', () => {
269
269
  assert.equal(updates.hasPracticeSessionEnabledChanged, true);
270
270
  });
271
271
 
272
+ it('returns hasPracticeSessionEnabledChanged = false when enabled is false and previous state is false', () => {
273
+ const newControls = {practiceSession: {enabled: false}};
274
+
275
+ const {updates} = ControlsUtils.getControls(defaultControls, newControls);
276
+
277
+ assert.equal(updates.hasPracticeSessionEnabledChanged, false);
278
+ });
279
+
272
280
  it('returns hasEntryExitToneChanged = true when mode changed', () => {
273
281
  const newControls = {
274
282
  entryExitTone: {
@@ -93,13 +93,14 @@ import CaptchaError from '../../../../src/common/errors/captcha-error';
93
93
  import PermissionError from '../../../../src/common/errors/permission';
94
94
  import JoinWebinarError from '../../../../src/common/errors/join-webinar-error';
95
95
  import IntentToJoinError from '../../../../src/common/errors/intent-to-join';
96
- import MultistreamNotSupportedError from '../../../../src/common/errors/multistream-not-supported-error';;
96
+ import MultistreamNotSupportedError from '../../../../src/common/errors/multistream-not-supported-error';
97
97
  import testUtils from '../../../utils/testUtils';
98
98
  import {
99
99
  MeetingInfoV2CaptchaError,
100
100
  MeetingInfoV2PasswordError,
101
101
  MeetingInfoV2PolicyError,
102
- MeetingInfoV2JoinWebinarError, MeetingInfoV2JoinForbiddenError,
102
+ MeetingInfoV2JoinWebinarError,
103
+ MeetingInfoV2JoinForbiddenError,
103
104
  } from '../../../../src/meeting-info/meeting-info-v2';
104
105
  import {
105
106
  DTLS_HANDSHAKE_FAILED_CLIENT_CODE,
@@ -115,7 +116,8 @@ import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
115
116
 
116
117
  import {EVENT_TRIGGERS as VOICEAEVENTS} from '@webex/internal-plugin-voicea';
117
118
  import { createBrbState } from '@webex/plugin-meetings/src/meeting/brbState';
118
- import JoinForbiddenError from '../../../../src/common/errors/join-forbidden-error';
119
+ import JoinForbiddenError from '../../../../src/common/errors/join-forbidden-error';
120
+ import { EventEmitter } from 'stream';
119
121
 
120
122
  describe('plugin-meetings', () => {
121
123
  const logger = {
@@ -208,6 +210,8 @@ describe('plugin-meetings', () => {
208
210
  let membersSpy;
209
211
  let meetingRequestSpy;
210
212
  let correlationId;
213
+ let isoLocalClientMeetingJoinTime;
214
+ let uploadEvent;
211
215
 
212
216
  beforeEach(() => {
213
217
  webex = new MockWebex({
@@ -277,6 +281,8 @@ describe('plugin-meetings', () => {
277
281
  test4 = `test4-${uuid.v4()}`;
278
282
  testDestination = `testDestination-${uuid.v4()}`;
279
283
  correlationId = uuid.v4();
284
+ uploadEvent = new EventEmitter();
285
+ uploadEvent.addListener('progress', () => {})
280
286
 
281
287
  meeting = new Meeting(
282
288
  {
@@ -667,7 +673,7 @@ describe('plugin-meetings', () => {
667
673
  beforeEach(() => {
668
674
  meeting.join = sinon.stub().callsFake((joinOptions) => {
669
675
  meeting.isMultistream = joinOptions.enableMultistream;
670
- return Promise.resolve(fakeJoinResult)
676
+ return Promise.resolve(fakeJoinResult);
671
677
  });
672
678
  addMediaInternalStub = sinon
673
679
  .stub(meeting, 'addMediaInternal')
@@ -1070,7 +1076,11 @@ describe('plugin-meetings', () => {
1070
1076
  mediaOptions,
1071
1077
  });
1072
1078
 
1073
- assert.deepEqual(result, {join: fakeJoinResult, media: undefined, multistreamEnabled: false});
1079
+ assert.deepEqual(result, {
1080
+ join: fakeJoinResult,
1081
+ media: undefined,
1082
+ multistreamEnabled: false,
1083
+ });
1074
1084
 
1075
1085
  assert.calledOnce(meeting.join);
1076
1086
 
@@ -1174,7 +1184,10 @@ describe('plugin-meetings', () => {
1174
1184
  type: addMediaError.name,
1175
1185
  }
1176
1186
  );
1177
- assert.calledOnceWithExactly(meeting.leave, {resourceId: undefined, reason: 'joinWithMedia failure'})
1187
+ assert.calledOnceWithExactly(meeting.leave, {
1188
+ resourceId: undefined,
1189
+ reason: 'joinWithMedia failure',
1190
+ });
1178
1191
  });
1179
1192
  });
1180
1193
 
@@ -1680,10 +1693,6 @@ describe('plugin-meetings', () => {
1680
1693
  sandbox.stub(MeetingUtil, 'joinMeeting').returns(Promise.resolve(joinMeetingResult));
1681
1694
  });
1682
1695
 
1683
- afterEach(() => {
1684
- assert.exists(meeting.isoLocalClientMeetingJoinTime);
1685
- });
1686
-
1687
1696
  it('should join the meeting and return promise', async () => {
1688
1697
  const join = meeting.join({pstnAudioType: 'dial-in'});
1689
1698
  meeting.config.enableAutomaticLLM = true;
@@ -3550,18 +3559,18 @@ describe('plugin-meetings', () => {
3550
3559
  it('counts the number of members that are in the meeting for MEDIA_QUALITY event', async () => {
3551
3560
  let fakeMembersCollection = {
3552
3561
  members: {
3553
- member1: { isInMeeting: true },
3554
- member2: { isInMeeting: true },
3555
- member3: { isInMeeting: false },
3562
+ member1: {isInMeeting: true},
3563
+ member2: {isInMeeting: true},
3564
+ member3: {isInMeeting: false},
3556
3565
  },
3557
3566
  };
3558
- sinon.stub(meeting, 'getMembers').returns({ membersCollection: fakeMembersCollection });
3559
- const fakeData = { intervalMetadata: {}, networkType: 'wifi' };
3567
+ sinon.stub(meeting, 'getMembers').returns({membersCollection: fakeMembersCollection});
3568
+ const fakeData = {intervalMetadata: {}, networkType: 'wifi'};
3560
3569
 
3561
3570
  statsAnalyzerStub.emit(
3562
- { file: 'test', function: 'test' },
3571
+ {file: 'test', function: 'test'},
3563
3572
  StatsAnalyzerEventNames.MEDIA_QUALITY,
3564
- { data: fakeData }
3573
+ {data: fakeData}
3565
3574
  );
3566
3575
 
3567
3576
  assert.calledWithMatch(webex.internal.newMetrics.submitMQE, {
@@ -3570,15 +3579,17 @@ describe('plugin-meetings', () => {
3570
3579
  meetingId: meeting.id,
3571
3580
  },
3572
3581
  payload: {
3573
- intervals: [sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 2))],
3582
+ intervals: [
3583
+ sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 2)),
3584
+ ],
3574
3585
  },
3575
3586
  });
3576
3587
  fakeMembersCollection.members.member2.isInMeeting = false;
3577
3588
 
3578
3589
  statsAnalyzerStub.emit(
3579
- { file: 'test', function: 'test' },
3590
+ {file: 'test', function: 'test'},
3580
3591
  StatsAnalyzerEventNames.MEDIA_QUALITY,
3581
- { data: fakeData }
3592
+ {data: fakeData}
3582
3593
  );
3583
3594
 
3584
3595
  assert.calledWithMatch(webex.internal.newMetrics.submitMQE, {
@@ -3587,7 +3598,9 @@ describe('plugin-meetings', () => {
3587
3598
  meetingId: meeting.id,
3588
3599
  },
3589
3600
  payload: {
3590
- intervals: [sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 1))],
3601
+ intervals: [
3602
+ sinon.match.has('intervalMetadata', sinon.match.has('meetingUserCount', 1)),
3603
+ ],
3591
3604
  },
3592
3605
  });
3593
3606
  });
@@ -3842,7 +3855,6 @@ describe('plugin-meetings', () => {
3842
3855
  });
3843
3856
 
3844
3857
  describe('when in a multistream meeting', () => {
3845
-
3846
3858
  beforeEach(() => {
3847
3859
  meeting.isMultistream = true;
3848
3860
  });
@@ -3853,7 +3865,7 @@ describe('plugin-meetings', () => {
3853
3865
  await brbResult;
3854
3866
  assert.exists(brbResult.then);
3855
3867
  assert.calledOnce(meeting.brbState.enable);
3856
- })
3868
+ });
3857
3869
 
3858
3870
  it('should disable #beRightBack and return a promise', async () => {
3859
3871
  const brbResult = meeting.beRightBack(false);
@@ -3861,7 +3873,7 @@ describe('plugin-meetings', () => {
3861
3873
  await brbResult;
3862
3874
  assert.exists(brbResult.then);
3863
3875
  assert.calledOnce(meeting.brbState.enable);
3864
- })
3876
+ });
3865
3877
 
3866
3878
  it('should throw an error and reject the promise if setBrb fails', async () => {
3867
3879
  const error = new Error('setBrb failed');
@@ -3874,7 +3886,7 @@ describe('plugin-meetings', () => {
3874
3886
  assert.equal(err.message, 'setBrb failed');
3875
3887
  assert.isRejected((Promise.reject()));
3876
3888
  }
3877
- })
3889
+ });
3878
3890
  });
3879
3891
  });
3880
3892
 
@@ -4006,7 +4018,7 @@ describe('plugin-meetings', () => {
4006
4018
  initiateOffer: sinon.stub().resolves({}),
4007
4019
  update: sinon.stub().resolves({}),
4008
4020
  on: sinon.stub(),
4009
- roapMessageReceived: sinon.stub()
4021
+ roapMessageReceived: sinon.stub(),
4010
4022
  };
4011
4023
 
4012
4024
  fakeMultistreamRoapMediaConnection = {
@@ -4035,7 +4047,7 @@ describe('plugin-meetings', () => {
4035
4047
 
4036
4048
  locusMediaRequestStub = sinon
4037
4049
  .stub(WebexPlugin.prototype, 'request')
4038
- .resolves({body: {locus: {fullState: {}}}});
4050
+ .resolves({body: {locus: {fullState: {}}}, upload: sinon.match.instanceOf(EventEmitter), download: sinon.match.instanceOf(EventEmitter)});
4039
4051
 
4040
4052
  // setup some things and mocks so that the call to join() works
4041
4053
  // (we need to call join() because it creates the LocusMediaRequest instance
@@ -4144,6 +4156,8 @@ describe('plugin-meetings', () => {
4144
4156
  id: 'fake clientMediaPreferences',
4145
4157
  },
4146
4158
  },
4159
+ upload: sinon.match.instanceOf(EventEmitter),
4160
+ download: sinon.match.instanceOf(EventEmitter),
4147
4161
  });
4148
4162
  };
4149
4163
 
@@ -4171,6 +4185,8 @@ describe('plugin-meetings', () => {
4171
4185
  },
4172
4186
  ],
4173
4187
  },
4188
+ upload: sinon.match.instanceOf(EventEmitter),
4189
+ download: sinon.match.instanceOf(EventEmitter),
4174
4190
  });
4175
4191
  };
4176
4192
 
@@ -4195,6 +4211,8 @@ describe('plugin-meetings', () => {
4195
4211
  respOnlySdp: true,
4196
4212
  usingResource: null,
4197
4213
  },
4214
+ upload: sinon.match.instanceOf(EventEmitter),
4215
+ download: sinon.match.instanceOf(EventEmitter),
4198
4216
  });
4199
4217
  };
4200
4218
 
@@ -6337,7 +6355,10 @@ describe('plugin-meetings', () => {
6337
6355
  .throws(new MeetingInfoV2JoinForbiddenError(403003, FAKE_MEETING_INFO)),
6338
6356
  };
6339
6357
 
6340
- await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinForbiddenError);
6358
+ await assert.isRejected(
6359
+ meeting.fetchMeetingInfo({sendCAevents: true}),
6360
+ JoinForbiddenError
6361
+ );
6341
6362
 
6342
6363
  assert.calledWith(
6343
6364
  meeting.attrs.meetingInfoProvider.fetchMeetingInfo,
@@ -6353,10 +6374,7 @@ describe('plugin-meetings', () => {
6353
6374
 
6354
6375
  assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
6355
6376
  assert.equal(meeting.meetingInfoFailureCode, 403003);
6356
- assert.equal(
6357
- meeting.meetingInfoFailureReason,
6358
- MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH
6359
- );
6377
+ assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH);
6360
6378
  assert.equal(meeting.requiredCaptcha, null);
6361
6379
  });
6362
6380
 
@@ -6733,15 +6751,10 @@ describe('plugin-meetings', () => {
6733
6751
  meeting.attrs.meetingInfoProvider = {
6734
6752
  fetchMeetingInfo: sinon
6735
6753
  .stub()
6736
- .throws(
6737
- new MeetingInfoV2JoinWebinarError(403021, FAKE_MEETING_INFO, 'a message')
6738
- ),
6754
+ .throws(new MeetingInfoV2JoinWebinarError(403021, FAKE_MEETING_INFO, 'a message')),
6739
6755
  };
6740
6756
 
6741
- await assert.isRejected(
6742
- meeting.fetchMeetingInfo({sendCAevents: true}),
6743
- JoinWebinarError
6744
- );
6757
+ await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError);
6745
6758
 
6746
6759
  assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
6747
6760
  assert.equal(
@@ -6756,15 +6769,10 @@ describe('plugin-meetings', () => {
6756
6769
  meeting.attrs.meetingInfoProvider = {
6757
6770
  fetchMeetingInfo: sinon
6758
6771
  .stub()
6759
- .throws(
6760
- new MeetingInfoV2JoinWebinarError(403026, FAKE_MEETING_INFO, 'a message')
6761
- ),
6772
+ .throws(new MeetingInfoV2JoinWebinarError(403026, FAKE_MEETING_INFO, 'a message')),
6762
6773
  };
6763
6774
 
6764
- await assert.isRejected(
6765
- meeting.fetchMeetingInfo({sendCAevents: true}),
6766
- JoinWebinarError
6767
- );
6775
+ await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError);
6768
6776
 
6769
6777
  assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
6770
6778
  assert.equal(
@@ -6779,15 +6787,10 @@ describe('plugin-meetings', () => {
6779
6787
  meeting.attrs.meetingInfoProvider = {
6780
6788
  fetchMeetingInfo: sinon
6781
6789
  .stub()
6782
- .throws(
6783
- new MeetingInfoV2JoinWebinarError(403037, FAKE_MEETING_INFO, 'a message')
6784
- ),
6790
+ .throws(new MeetingInfoV2JoinWebinarError(403037, FAKE_MEETING_INFO, 'a message')),
6785
6791
  };
6786
6792
 
6787
- await assert.isRejected(
6788
- meeting.fetchMeetingInfo({sendCAevents: true}),
6789
- JoinWebinarError
6790
- );
6793
+ await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError);
6791
6794
 
6792
6795
  assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
6793
6796
  assert.equal(
@@ -7524,6 +7527,27 @@ describe('plugin-meetings', () => {
7524
7527
  });
7525
7528
  });
7526
7529
 
7530
+ describe('#setIsoLocalClientMeetingJoinTime', () => {
7531
+ it('should fallback to system clock ISO string when given an undefined value', () => {
7532
+ const currentSystemTime = new Date().toISOString();
7533
+ meeting.isoLocalClientMeetingJoinTime = undefined;
7534
+ assert.equal(meeting.isoLocalClientMeetingJoinTime, currentSystemTime);
7535
+ });
7536
+
7537
+ it('should fallback to system clock ISO string when given an invalid value', () => {
7538
+ const currentSystemTime = new Date().toISOString();
7539
+ meeting.isoLocalClientMeetingJoinTime = 'invalid-date';
7540
+ assert.equal(meeting.isoLocalClientMeetingJoinTime, currentSystemTime);
7541
+ });
7542
+
7543
+ it('should set the isoLocalClientMeetingJoinTime correctly for a valid date string', () => {
7544
+ const validDateString = 'Tue, 01 Apr 2025 13:00:36 GMT';
7545
+ const expectedISOString = new Date(validDateString).toISOString();
7546
+ meeting.isoLocalClientMeetingJoinTime = validDateString;
7547
+ assert.equal(meeting.isoLocalClientMeetingJoinTime, expectedISOString);
7548
+ });
7549
+ });
7550
+
7527
7551
  describe('#updateCallStateForMetrics', () => {
7528
7552
  it('should update the callState, overriding existing values', () => {
7529
7553
  assert.deepEqual(meeting.callStateForMetrics, {correlationId, sessionCorrelationId: ''});
@@ -9223,22 +9247,22 @@ describe('plugin-meetings', () => {
9223
9247
  const assertBrb = (enabled) => {
9224
9248
  meeting.brbState = createBrbState(meeting, false);
9225
9249
  meeting.locusInfo.emit(
9226
- { function: 'test', file: 'test' },
9250
+ {function: 'test', file: 'test'},
9227
9251
  LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED,
9228
- { brb: { enabled } },
9229
- )
9252
+ {brb: {enabled}}
9253
+ );
9230
9254
  assert.calledWithExactly(
9231
9255
  TriggerProxy.trigger,
9232
9256
  meeting,
9233
9257
  {file: 'meeting/index', function: 'setUpLocusInfoSelfListener'},
9234
9258
  EVENT_TRIGGERS.MEETING_SELF_BRB_UPDATE,
9235
- { payload: { brb: { enabled } } },
9259
+ {payload: {brb: {enabled}}}
9236
9260
  );
9237
- }
9261
+ };
9238
9262
 
9239
9263
  assertBrb(true);
9240
9264
  assertBrb(false);
9241
- })
9265
+ });
9242
9266
 
9243
9267
  it('listens to the interpretation changed event', () => {
9244
9268
  meeting.simultaneousInterpretation.updateSelfInterpretation = sinon.stub();
@@ -9922,6 +9946,22 @@ describe('plugin-meetings', () => {
9922
9946
  });
9923
9947
  });
9924
9948
 
9949
+ describe('#emailInput', () => {
9950
+ it('should set the email input', () => {
9951
+ assert.notOk(meeting.emailInput);
9952
+ meeting.emailInput = 'current';
9953
+ assert.equal(meeting.emailInput, 'current');
9954
+ });
9955
+ });
9956
+
9957
+ describe('#userNameInput', () => {
9958
+ it('should set the user name input', () => {
9959
+ assert.notOk(meeting.userNameInput);
9960
+ meeting.userNameInput = 'current';
9961
+ assert.equal(meeting.userNameInput, 'current');
9962
+ });
9963
+ });
9964
+
9925
9965
  describe('#setPermissionTokenPayload', () => {
9926
9966
  let now;
9927
9967
  let clock;
@@ -11326,18 +11366,21 @@ describe('plugin-meetings', () => {
11326
11366
  );
11327
11367
  });
11328
11368
 
11329
-
11330
11369
  it('connect ps data channel if ps started in webinar', async () => {
11331
11370
  meeting.joinedWith = {state: 'JOINED'};
11332
- meeting.locusInfo = {url: 'a url', info: {datachannelUrl: 'a datachannel url', practiceSessionDatachannelUrl: 'a ps datachannel url'}};
11371
+ meeting.locusInfo = {
11372
+ url: 'a url',
11373
+ info: {
11374
+ datachannelUrl: 'a datachannel url',
11375
+ practiceSessionDatachannelUrl: 'a ps datachannel url',
11376
+ },
11377
+ };
11333
11378
  meeting.webinar.isJoinPracticeSessionDataChannel = sinon.stub().returns(true);
11334
11379
  await meeting.updateLLMConnection();
11335
11380
 
11336
11381
  assert.notCalled(webex.internal.llm.disconnectLLM);
11337
11382
  assert.calledWith(webex.internal.llm.registerAndConnect, 'a url', 'a ps datachannel url');
11338
-
11339
11383
  });
11340
-
11341
11384
  });
11342
11385
 
11343
11386
  describe('#setLocus', () => {
@@ -11755,24 +11798,29 @@ describe('plugin-meetings', () => {
11755
11798
 
11756
11799
  activeSharingId.whiteboard = beneficiaryId;
11757
11800
 
11758
- eventTrigger.share.push(meeting.webinar.selfIsAttendee ? {
11759
- eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
11760
- functionName: 'remoteShare',
11761
- eventPayload: {
11762
- memberId: null,
11763
- url,
11764
- shareInstanceId,
11765
- annotationInfo: undefined,
11766
- resourceType: undefined,
11767
- },
11768
- } : {
11769
- eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
11770
- functionName: 'startWhiteboardShare',
11771
- eventPayload: {resourceUrl, memberId: beneficiaryId},
11772
- });
11773
-
11774
- shareStatus = meeting.webinar.selfIsAttendee ? SHARE_STATUS.REMOTE_SHARE_ACTIVE : SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
11801
+ eventTrigger.share.push(
11802
+ meeting.webinar.selfIsAttendee
11803
+ ? {
11804
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
11805
+ functionName: 'remoteShare',
11806
+ eventPayload: {
11807
+ memberId: null,
11808
+ url,
11809
+ shareInstanceId,
11810
+ annotationInfo: undefined,
11811
+ resourceType: undefined,
11812
+ },
11813
+ }
11814
+ : {
11815
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
11816
+ functionName: 'startWhiteboardShare',
11817
+ eventPayload: {resourceUrl, memberId: beneficiaryId},
11818
+ }
11819
+ );
11775
11820
 
11821
+ shareStatus = meeting.webinar.selfIsAttendee
11822
+ ? SHARE_STATUS.REMOTE_SHARE_ACTIVE
11823
+ : SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
11776
11824
  }
11777
11825
 
11778
11826
  if (eventTrigger.member) {
@@ -11804,24 +11852,29 @@ describe('plugin-meetings', () => {
11804
11852
  newPayload.current.content.disposition = FLOOR_ACTION.ACCEPTED;
11805
11853
  newPayload.current.content.beneficiaryId = otherBeneficiaryId;
11806
11854
 
11807
- eventTrigger.share.push(meeting.webinar.selfIsAttendee ? {
11808
- eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
11809
- functionName: 'remoteShare',
11810
- eventPayload: {
11811
- memberId: null,
11812
- url,
11813
- shareInstanceId,
11814
- annotationInfo: undefined,
11815
- resourceType: undefined,
11816
- },
11817
- } : {
11818
- eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
11819
- functionName: 'startWhiteboardShare',
11820
- eventPayload: {resourceUrl, memberId: beneficiaryId},
11821
- });
11822
-
11823
- shareStatus = meeting.webinar.selfIsAttendee ? SHARE_STATUS.REMOTE_SHARE_ACTIVE : SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
11855
+ eventTrigger.share.push(
11856
+ meeting.webinar.selfIsAttendee
11857
+ ? {
11858
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
11859
+ functionName: 'remoteShare',
11860
+ eventPayload: {
11861
+ memberId: null,
11862
+ url,
11863
+ shareInstanceId,
11864
+ annotationInfo: undefined,
11865
+ resourceType: undefined,
11866
+ },
11867
+ }
11868
+ : {
11869
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
11870
+ functionName: 'startWhiteboardShare',
11871
+ eventPayload: {resourceUrl, memberId: beneficiaryId},
11872
+ }
11873
+ );
11824
11874
 
11875
+ shareStatus = meeting.webinar.selfIsAttendee
11876
+ ? SHARE_STATUS.REMOTE_SHARE_ACTIVE
11877
+ : SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
11825
11878
  } else {
11826
11879
  eventTrigger.share.push({
11827
11880
  eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD,
@@ -11951,24 +12004,24 @@ describe('plugin-meetings', () => {
11951
12004
  describe('Whiteboard Share - Webinar Attendee', () => {
11952
12005
  it('Scenario #1: Whiteboard sharing as a webinar attendee', () => {
11953
12006
  // Set the webinar attendee flag
11954
- meeting.webinar = { selfIsAttendee: true };
12007
+ meeting.webinar = {selfIsAttendee: true};
11955
12008
  meeting.locusInfo.info.isWebinar = true;
11956
12009
 
11957
12010
  // Step 1: Start sharing whiteboard A
11958
12011
  const data1 = generateData(
11959
- blankPayload, // Initial payload
11960
- true, // isGranting: Granting share
11961
- false, // isContent: Whiteboard (not content)
11962
- USER_IDS.REMOTE_A, // Beneficiary ID: Remote user A
12012
+ blankPayload, // Initial payload
12013
+ true, // isGranting: Granting share
12014
+ false, // isContent: Whiteboard (not content)
12015
+ USER_IDS.REMOTE_A, // Beneficiary ID: Remote user A
11963
12016
  RESOURCE_URLS.WHITEBOARD_A // Resource URL: Whiteboard A
11964
12017
  );
11965
12018
 
11966
12019
  // Step 2: Stop sharing whiteboard A
11967
12020
  const data2 = generateData(
11968
- data1.payload, // Updated payload from Step 1
11969
- false, // isGranting: Stopping share
11970
- false, // isContent: Whiteboard
11971
- USER_IDS.REMOTE_A // Beneficiary ID: Remote user A
12021
+ data1.payload, // Updated payload from Step 1
12022
+ false, // isGranting: Stopping share
12023
+ false, // isContent: Whiteboard
12024
+ USER_IDS.REMOTE_A // Beneficiary ID: Remote user A
11972
12025
  );
11973
12026
 
11974
12027
  // Validate the payload changes and status updates
@@ -11979,7 +12032,6 @@ describe('plugin-meetings', () => {
11979
12032
  });
11980
12033
  });
11981
12034
 
11982
-
11983
12035
  describe('Whiteboard A --> Whiteboard B', () => {
11984
12036
  it('Scenario #1: you share both whiteboards', () => {
11985
12037
  const data1 = generateData(
@@ -12632,6 +12684,31 @@ describe('plugin-meetings', () => {
12632
12684
  });
12633
12685
  });
12634
12686
  });
12687
+
12688
+ describe('handleShareVideoStreamMuteStateChange', () => {
12689
+ it('should emit MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE event with correct fields', () => {
12690
+ meeting.isMultistream = true;
12691
+ meeting.statsAnalyzer = {shareVideoEncoderImplementation: 'OpenH264'};
12692
+ meeting.mediaProperties.shareVideoStream = {
12693
+ getSettings: sinon.stub().returns({displaySurface: 'monitor', frameRate: 30}),
12694
+ };
12695
+
12696
+ meeting.handleShareVideoStreamMuteStateChange(true);
12697
+
12698
+ assert.calledOnceWithExactly(
12699
+ Metrics.sendBehavioralMetric,
12700
+ BEHAVIORAL_METRICS.MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE,
12701
+ {
12702
+ correlationId: meeting.correlationId,
12703
+ muted: true,
12704
+ encoderImplementation: 'OpenH264',
12705
+ displaySurface: 'monitor',
12706
+ isMultistream: true,
12707
+ frameRate: 30,
12708
+ }
12709
+ );
12710
+ });
12711
+ });
12635
12712
  });
12636
12713
 
12637
12714
  describe('#startKeepAlive', () => {
@@ -13290,7 +13367,7 @@ describe('plugin-meetings', () => {
13290
13367
  await meeting.roapMessageReceived(fakeMessage);
13291
13368
 
13292
13369
  assert.fail('Expected MultistreamNotSupportedError to be thrown');
13293
- } catch(e) {
13370
+ } catch (e) {
13294
13371
  assert.isTrue(e instanceof MultistreamNotSupportedError);
13295
13372
  }
13296
13373