@webex/plugin-meetings 3.8.0-next.3 → 3.8.0-next.30

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 (78) 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 +89 -5
  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 +4 -1
  17. package/dist/meeting/util.js.map +1 -1
  18. package/dist/meeting-info/meeting-info-v2.js +359 -60
  19. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  20. package/dist/meetings/index.js +60 -1
  21. package/dist/meetings/index.js.map +1 -1
  22. package/dist/member/index.js +10 -0
  23. package/dist/member/index.js.map +1 -1
  24. package/dist/member/util.js +3 -0
  25. package/dist/member/util.js.map +1 -1
  26. package/dist/metrics/constants.js +9 -0
  27. package/dist/metrics/constants.js.map +1 -1
  28. package/dist/reachability/clusterReachability.js +52 -8
  29. package/dist/reachability/clusterReachability.js.map +1 -1
  30. package/dist/reachability/index.js +70 -45
  31. package/dist/reachability/index.js.map +1 -1
  32. package/dist/reachability/reachability.types.js +14 -0
  33. package/dist/reachability/reachability.types.js.map +1 -1
  34. package/dist/reachability/request.js +19 -3
  35. package/dist/reachability/request.js.map +1 -1
  36. package/dist/recording-controller/util.js +5 -5
  37. package/dist/recording-controller/util.js.map +1 -1
  38. package/dist/types/config.d.ts +1 -0
  39. package/dist/types/constants.d.ts +1 -0
  40. package/dist/types/meeting/index.d.ts +30 -0
  41. package/dist/types/meeting-info/meeting-info-v2.d.ts +80 -0
  42. package/dist/types/meetings/index.d.ts +29 -0
  43. package/dist/types/member/index.d.ts +1 -0
  44. package/dist/types/metrics/constants.d.ts +9 -0
  45. package/dist/types/reachability/clusterReachability.d.ts +13 -1
  46. package/dist/types/reachability/index.d.ts +2 -1
  47. package/dist/types/reachability/reachability.types.d.ts +5 -0
  48. package/dist/webinar/index.js +1 -1
  49. package/package.json +22 -22
  50. package/src/config.ts +1 -0
  51. package/src/constants.ts +1 -0
  52. package/src/interpretation/index.ts +3 -3
  53. package/src/locus-info/controlsUtils.ts +2 -2
  54. package/src/meeting/index.ts +85 -7
  55. package/src/meeting/locusMediaRequest.ts +27 -4
  56. package/src/meeting/util.ts +2 -1
  57. package/src/meeting-info/meeting-info-v2.ts +247 -6
  58. package/src/meetings/index.ts +72 -1
  59. package/src/member/index.ts +11 -0
  60. package/src/member/util.ts +3 -0
  61. package/src/metrics/constants.ts +9 -0
  62. package/src/reachability/clusterReachability.ts +47 -1
  63. package/src/reachability/index.ts +15 -0
  64. package/src/reachability/reachability.types.ts +6 -0
  65. package/src/reachability/request.ts +7 -0
  66. package/src/recording-controller/util.ts +17 -13
  67. package/test/unit/spec/interpretation/index.ts +39 -1
  68. package/test/unit/spec/locus-info/controlsUtils.js +8 -0
  69. package/test/unit/spec/meeting/index.js +200 -108
  70. package/test/unit/spec/meeting/locusMediaRequest.ts +96 -58
  71. package/test/unit/spec/meeting/utils.js +55 -0
  72. package/test/unit/spec/meeting-info/meetinginfov2.js +443 -114
  73. package/test/unit/spec/meetings/index.js +78 -1
  74. package/test/unit/spec/member/index.js +7 -0
  75. package/test/unit/spec/member/util.js +24 -0
  76. package/test/unit/spec/reachability/clusterReachability.ts +47 -1
  77. package/test/unit/spec/reachability/index.ts +12 -0
  78. package/test/unit/spec/reachability/request.js +47 -2
@@ -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: ''});
@@ -8590,13 +8614,19 @@ describe('plugin-meetings', () => {
8590
8614
  const fakeErrorMessage = 'test error';
8591
8615
  const fakeRootCauseName = 'root cause name';
8592
8616
  const fakeErrorName = 'test error name';
8617
+ let clock;
8593
8618
 
8594
8619
  beforeEach(() => {
8620
+ clock = sinon.useFakeTimers();
8595
8621
  meeting.setupMediaConnectionListeners();
8596
8622
  webex.internal.newMetrics.submitClientEvent.resetHistory();
8597
8623
  Metrics.sendBehavioralMetric.resetHistory();
8598
8624
  });
8599
8625
 
8626
+ afterEach(() => {
8627
+ clock.restore();
8628
+ });
8629
+
8600
8630
  const checkMetricSent = (event, error) => {
8601
8631
  assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
8602
8632
  assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
@@ -8665,6 +8695,13 @@ describe('plugin-meetings', () => {
8665
8695
  });
8666
8696
 
8667
8697
  it('should send metrics for SdpAnswerHandlingError error', () => {
8698
+ meeting.sdpResponseTimer = '1234';
8699
+ meeting.deferSDPAnswer = {
8700
+ reject: sinon.stub(),
8701
+ };
8702
+
8703
+ const clearTimeoutSpy = sinon.spy(clock, 'clearTimeout');
8704
+
8668
8705
  const fakeError = new Errors.SdpAnswerHandlingError(fakeErrorMessage, {
8669
8706
  name: fakeErrorName,
8670
8707
  cause: {name: fakeRootCauseName},
@@ -8679,6 +8716,8 @@ describe('plugin-meetings', () => {
8679
8716
  fakeErrorMessage,
8680
8717
  fakeRootCauseName
8681
8718
  );
8719
+ assert.calledOnce(meeting.deferSDPAnswer.reject);
8720
+ assert.calledOnce(clearTimeoutSpy);
8682
8721
  });
8683
8722
 
8684
8723
  it('should send metrics for SdpError error', () => {
@@ -9223,22 +9262,22 @@ describe('plugin-meetings', () => {
9223
9262
  const assertBrb = (enabled) => {
9224
9263
  meeting.brbState = createBrbState(meeting, false);
9225
9264
  meeting.locusInfo.emit(
9226
- { function: 'test', file: 'test' },
9265
+ {function: 'test', file: 'test'},
9227
9266
  LOCUSINFO.EVENTS.SELF_MEETING_BRB_CHANGED,
9228
- { brb: { enabled } },
9229
- )
9267
+ {brb: {enabled}}
9268
+ );
9230
9269
  assert.calledWithExactly(
9231
9270
  TriggerProxy.trigger,
9232
9271
  meeting,
9233
9272
  {file: 'meeting/index', function: 'setUpLocusInfoSelfListener'},
9234
9273
  EVENT_TRIGGERS.MEETING_SELF_BRB_UPDATE,
9235
- { payload: { brb: { enabled } } },
9274
+ {payload: {brb: {enabled}}}
9236
9275
  );
9237
- }
9276
+ };
9238
9277
 
9239
9278
  assertBrb(true);
9240
9279
  assertBrb(false);
9241
- })
9280
+ });
9242
9281
 
9243
9282
  it('listens to the interpretation changed event', () => {
9244
9283
  meeting.simultaneousInterpretation.updateSelfInterpretation = sinon.stub();
@@ -9922,6 +9961,22 @@ describe('plugin-meetings', () => {
9922
9961
  });
9923
9962
  });
9924
9963
 
9964
+ describe('#emailInput', () => {
9965
+ it('should set the email input', () => {
9966
+ assert.notOk(meeting.emailInput);
9967
+ meeting.emailInput = 'current';
9968
+ assert.equal(meeting.emailInput, 'current');
9969
+ });
9970
+ });
9971
+
9972
+ describe('#userNameInput', () => {
9973
+ it('should set the user name input', () => {
9974
+ assert.notOk(meeting.userNameInput);
9975
+ meeting.userNameInput = 'current';
9976
+ assert.equal(meeting.userNameInput, 'current');
9977
+ });
9978
+ });
9979
+
9925
9980
  describe('#setPermissionTokenPayload', () => {
9926
9981
  let now;
9927
9982
  let clock;
@@ -11326,18 +11381,21 @@ describe('plugin-meetings', () => {
11326
11381
  );
11327
11382
  });
11328
11383
 
11329
-
11330
11384
  it('connect ps data channel if ps started in webinar', async () => {
11331
11385
  meeting.joinedWith = {state: 'JOINED'};
11332
- meeting.locusInfo = {url: 'a url', info: {datachannelUrl: 'a datachannel url', practiceSessionDatachannelUrl: 'a ps datachannel url'}};
11386
+ meeting.locusInfo = {
11387
+ url: 'a url',
11388
+ info: {
11389
+ datachannelUrl: 'a datachannel url',
11390
+ practiceSessionDatachannelUrl: 'a ps datachannel url',
11391
+ },
11392
+ };
11333
11393
  meeting.webinar.isJoinPracticeSessionDataChannel = sinon.stub().returns(true);
11334
11394
  await meeting.updateLLMConnection();
11335
11395
 
11336
11396
  assert.notCalled(webex.internal.llm.disconnectLLM);
11337
11397
  assert.calledWith(webex.internal.llm.registerAndConnect, 'a url', 'a ps datachannel url');
11338
-
11339
11398
  });
11340
-
11341
11399
  });
11342
11400
 
11343
11401
  describe('#setLocus', () => {
@@ -11755,24 +11813,29 @@ describe('plugin-meetings', () => {
11755
11813
 
11756
11814
  activeSharingId.whiteboard = beneficiaryId;
11757
11815
 
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;
11816
+ eventTrigger.share.push(
11817
+ meeting.webinar.selfIsAttendee
11818
+ ? {
11819
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
11820
+ functionName: 'remoteShare',
11821
+ eventPayload: {
11822
+ memberId: null,
11823
+ url,
11824
+ shareInstanceId,
11825
+ annotationInfo: undefined,
11826
+ resourceType: undefined,
11827
+ },
11828
+ }
11829
+ : {
11830
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
11831
+ functionName: 'startWhiteboardShare',
11832
+ eventPayload: {resourceUrl, memberId: beneficiaryId},
11833
+ }
11834
+ );
11775
11835
 
11836
+ shareStatus = meeting.webinar.selfIsAttendee
11837
+ ? SHARE_STATUS.REMOTE_SHARE_ACTIVE
11838
+ : SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
11776
11839
  }
11777
11840
 
11778
11841
  if (eventTrigger.member) {
@@ -11804,24 +11867,29 @@ describe('plugin-meetings', () => {
11804
11867
  newPayload.current.content.disposition = FLOOR_ACTION.ACCEPTED;
11805
11868
  newPayload.current.content.beneficiaryId = otherBeneficiaryId;
11806
11869
 
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;
11870
+ eventTrigger.share.push(
11871
+ meeting.webinar.selfIsAttendee
11872
+ ? {
11873
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
11874
+ functionName: 'remoteShare',
11875
+ eventPayload: {
11876
+ memberId: null,
11877
+ url,
11878
+ shareInstanceId,
11879
+ annotationInfo: undefined,
11880
+ resourceType: undefined,
11881
+ },
11882
+ }
11883
+ : {
11884
+ eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_WHITEBOARD,
11885
+ functionName: 'startWhiteboardShare',
11886
+ eventPayload: {resourceUrl, memberId: beneficiaryId},
11887
+ }
11888
+ );
11824
11889
 
11890
+ shareStatus = meeting.webinar.selfIsAttendee
11891
+ ? SHARE_STATUS.REMOTE_SHARE_ACTIVE
11892
+ : SHARE_STATUS.WHITEBOARD_SHARE_ACTIVE;
11825
11893
  } else {
11826
11894
  eventTrigger.share.push({
11827
11895
  eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_WHITEBOARD,
@@ -11951,24 +12019,24 @@ describe('plugin-meetings', () => {
11951
12019
  describe('Whiteboard Share - Webinar Attendee', () => {
11952
12020
  it('Scenario #1: Whiteboard sharing as a webinar attendee', () => {
11953
12021
  // Set the webinar attendee flag
11954
- meeting.webinar = { selfIsAttendee: true };
12022
+ meeting.webinar = {selfIsAttendee: true};
11955
12023
  meeting.locusInfo.info.isWebinar = true;
11956
12024
 
11957
12025
  // Step 1: Start sharing whiteboard A
11958
12026
  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
12027
+ blankPayload, // Initial payload
12028
+ true, // isGranting: Granting share
12029
+ false, // isContent: Whiteboard (not content)
12030
+ USER_IDS.REMOTE_A, // Beneficiary ID: Remote user A
11963
12031
  RESOURCE_URLS.WHITEBOARD_A // Resource URL: Whiteboard A
11964
12032
  );
11965
12033
 
11966
12034
  // Step 2: Stop sharing whiteboard A
11967
12035
  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
12036
+ data1.payload, // Updated payload from Step 1
12037
+ false, // isGranting: Stopping share
12038
+ false, // isContent: Whiteboard
12039
+ USER_IDS.REMOTE_A // Beneficiary ID: Remote user A
11972
12040
  );
11973
12041
 
11974
12042
  // Validate the payload changes and status updates
@@ -11979,7 +12047,6 @@ describe('plugin-meetings', () => {
11979
12047
  });
11980
12048
  });
11981
12049
 
11982
-
11983
12050
  describe('Whiteboard A --> Whiteboard B', () => {
11984
12051
  it('Scenario #1: you share both whiteboards', () => {
11985
12052
  const data1 = generateData(
@@ -12632,6 +12699,31 @@ describe('plugin-meetings', () => {
12632
12699
  });
12633
12700
  });
12634
12701
  });
12702
+
12703
+ describe('handleShareVideoStreamMuteStateChange', () => {
12704
+ it('should emit MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE event with correct fields', () => {
12705
+ meeting.isMultistream = true;
12706
+ meeting.statsAnalyzer = {shareVideoEncoderImplementation: 'OpenH264'};
12707
+ meeting.mediaProperties.shareVideoStream = {
12708
+ getSettings: sinon.stub().returns({displaySurface: 'monitor', frameRate: 30}),
12709
+ };
12710
+
12711
+ meeting.handleShareVideoStreamMuteStateChange(true);
12712
+
12713
+ assert.calledOnceWithExactly(
12714
+ Metrics.sendBehavioralMetric,
12715
+ BEHAVIORAL_METRICS.MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE,
12716
+ {
12717
+ correlationId: meeting.correlationId,
12718
+ muted: true,
12719
+ encoderImplementation: 'OpenH264',
12720
+ displaySurface: 'monitor',
12721
+ isMultistream: true,
12722
+ frameRate: 30,
12723
+ }
12724
+ );
12725
+ });
12726
+ });
12635
12727
  });
12636
12728
 
12637
12729
  describe('#startKeepAlive', () => {
@@ -13290,7 +13382,7 @@ describe('plugin-meetings', () => {
13290
13382
  await meeting.roapMessageReceived(fakeMessage);
13291
13383
 
13292
13384
  assert.fail('Expected MultistreamNotSupportedError to be thrown');
13293
- } catch(e) {
13385
+ } catch (e) {
13294
13386
  assert.isTrue(e instanceof MultistreamNotSupportedError);
13295
13387
  }
13296
13388