@webex/plugin-meetings 3.7.0-next.3 → 3.7.0-next.31

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 (114) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/common/errors/{webinar-registration-error.js → join-webinar-error.js} +12 -12
  4. package/dist/common/errors/join-webinar-error.js.map +1 -0
  5. package/dist/config.js +1 -1
  6. package/dist/config.js.map +1 -1
  7. package/dist/constants.js +31 -6
  8. package/dist/constants.js.map +1 -1
  9. package/dist/index.js +8 -15
  10. package/dist/index.js.map +1 -1
  11. package/dist/interpretation/index.js +1 -1
  12. package/dist/interpretation/siLanguage.js +1 -1
  13. package/dist/locus-info/index.js +13 -2
  14. package/dist/locus-info/index.js.map +1 -1
  15. package/dist/locus-info/selfUtils.js +30 -17
  16. package/dist/locus-info/selfUtils.js.map +1 -1
  17. package/dist/meeting/in-meeting-actions.js +11 -1
  18. package/dist/meeting/in-meeting-actions.js.map +1 -1
  19. package/dist/meeting/index.js +810 -779
  20. package/dist/meeting/index.js.map +1 -1
  21. package/dist/meeting/request.js +30 -0
  22. package/dist/meeting/request.js.map +1 -1
  23. package/dist/meeting/request.type.js.map +1 -1
  24. package/dist/meeting/util.js +3 -8
  25. package/dist/meeting/util.js.map +1 -1
  26. package/dist/meeting-info/meeting-info-v2.js +29 -17
  27. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  28. package/dist/meetings/index.js +6 -3
  29. package/dist/meetings/index.js.map +1 -1
  30. package/dist/member/index.js +9 -0
  31. package/dist/member/index.js.map +1 -1
  32. package/dist/member/types.js.map +1 -1
  33. package/dist/member/util.js +39 -28
  34. package/dist/member/util.js.map +1 -1
  35. package/dist/members/util.js +4 -2
  36. package/dist/members/util.js.map +1 -1
  37. package/dist/metrics/constants.js +1 -1
  38. package/dist/metrics/constants.js.map +1 -1
  39. package/dist/multistream/remoteMedia.js +30 -15
  40. package/dist/multistream/remoteMedia.js.map +1 -1
  41. package/dist/multistream/sendSlotManager.js +24 -0
  42. package/dist/multistream/sendSlotManager.js.map +1 -1
  43. package/dist/reachability/clusterReachability.js +12 -11
  44. package/dist/reachability/clusterReachability.js.map +1 -1
  45. package/dist/recording-controller/enums.js +8 -4
  46. package/dist/recording-controller/enums.js.map +1 -1
  47. package/dist/recording-controller/index.js +18 -9
  48. package/dist/recording-controller/index.js.map +1 -1
  49. package/dist/recording-controller/util.js +13 -9
  50. package/dist/recording-controller/util.js.map +1 -1
  51. package/dist/types/common/errors/{webinar-registration-error.d.ts → join-webinar-error.d.ts} +2 -2
  52. package/dist/types/constants.d.ts +23 -1
  53. package/dist/types/index.d.ts +3 -3
  54. package/dist/types/locus-info/index.d.ts +2 -1
  55. package/dist/types/meeting/in-meeting-actions.d.ts +10 -0
  56. package/dist/types/meeting/index.d.ts +9 -10
  57. package/dist/types/meeting/request.d.ts +12 -1
  58. package/dist/types/meeting/request.type.d.ts +6 -0
  59. package/dist/types/meeting/util.d.ts +1 -1
  60. package/dist/types/meeting-info/meeting-info-v2.d.ts +4 -4
  61. package/dist/types/meetings/index.d.ts +3 -0
  62. package/dist/types/member/index.d.ts +1 -0
  63. package/dist/types/member/types.d.ts +7 -0
  64. package/dist/types/members/util.d.ts +2 -0
  65. package/dist/types/metrics/constants.d.ts +1 -1
  66. package/dist/types/multistream/sendSlotManager.d.ts +8 -1
  67. package/dist/types/recording-controller/enums.d.ts +5 -2
  68. package/dist/types/recording-controller/index.d.ts +1 -0
  69. package/dist/types/recording-controller/util.d.ts +2 -1
  70. package/dist/webinar/index.js +390 -7
  71. package/dist/webinar/index.js.map +1 -1
  72. package/package.json +23 -22
  73. package/src/common/errors/join-webinar-error.ts +24 -0
  74. package/src/config.ts +1 -1
  75. package/src/constants.ts +28 -3
  76. package/src/index.ts +2 -3
  77. package/src/locus-info/index.ts +17 -2
  78. package/src/locus-info/selfUtils.ts +19 -6
  79. package/src/meeting/in-meeting-actions.ts +21 -0
  80. package/src/meeting/index.ts +147 -54
  81. package/src/meeting/request.ts +26 -1
  82. package/src/meeting/request.type.ts +7 -0
  83. package/src/meeting/util.ts +3 -9
  84. package/src/meeting-info/meeting-info-v2.ts +23 -11
  85. package/src/meetings/index.ts +8 -2
  86. package/src/member/index.ts +9 -0
  87. package/src/member/types.ts +8 -0
  88. package/src/member/util.ts +34 -24
  89. package/src/members/util.ts +1 -0
  90. package/src/metrics/constants.ts +1 -1
  91. package/src/multistream/remoteMedia.ts +28 -15
  92. package/src/multistream/sendSlotManager.ts +31 -0
  93. package/src/reachability/clusterReachability.ts +4 -1
  94. package/src/recording-controller/enums.ts +5 -2
  95. package/src/recording-controller/index.ts +17 -4
  96. package/src/recording-controller/util.ts +20 -5
  97. package/src/webinar/index.ts +235 -9
  98. package/test/unit/spec/locus-info/index.js +222 -0
  99. package/test/unit/spec/locus-info/selfConstant.js +7 -0
  100. package/test/unit/spec/locus-info/selfUtils.js +91 -1
  101. package/test/unit/spec/meeting/in-meeting-actions.ts +13 -1
  102. package/test/unit/spec/meeting/index.js +318 -81
  103. package/test/unit/spec/meeting/utils.js +11 -19
  104. package/test/unit/spec/meeting-info/meetinginfov2.js +9 -4
  105. package/test/unit/spec/meetings/index.js +9 -5
  106. package/test/unit/spec/member/util.js +52 -11
  107. package/test/unit/spec/members/utils.js +95 -0
  108. package/test/unit/spec/multistream/remoteMedia.ts +11 -7
  109. package/test/unit/spec/reachability/clusterReachability.ts +7 -0
  110. package/test/unit/spec/recording-controller/index.js +61 -5
  111. package/test/unit/spec/recording-controller/util.js +39 -3
  112. package/test/unit/spec/webinar/index.ts +504 -0
  113. package/dist/common/errors/webinar-registration-error.js.map +0 -1
  114. package/src/common/errors/webinar-registration-error.ts +0 -27
@@ -26,7 +26,7 @@ describe('plugin-meetings', () => {
26
26
  webex.meetings.reachability = {
27
27
  getReachabilityReportToAttachToRoap: sinon.stub().resolves({}),
28
28
  getClientMediaPreferences: sinon.stub().resolves({}),
29
- };
29
+ };
30
30
 
31
31
  const logger = {
32
32
  info: sandbox.stub(),
@@ -165,21 +165,6 @@ describe('plugin-meetings', () => {
165
165
  assert(LoggerProxy.logger.log.called, 'log called');
166
166
  });
167
167
  });
168
-
169
- describe('#handleDeviceLogging', () => {
170
- it('should not log if called without devices', () => {
171
- MeetingUtil.handleDeviceLogging();
172
- assert(!LoggerProxy.logger.log.called, 'log not called');
173
- });
174
-
175
- it('should log device settings', () => {
176
- const mockDevices = [{deviceId: 'device-1'}, {deviceId: 'device-2'}];
177
-
178
- assert(MeetingUtil.handleDeviceLogging, 'is defined');
179
- MeetingUtil.handleDeviceLogging(mockDevices);
180
- assert(LoggerProxy.logger.log.called, 'log called');
181
- });
182
- });
183
168
  });
184
169
 
185
170
  describe('addSequence', () => {
@@ -424,17 +409,17 @@ describe('plugin-meetings', () => {
424
409
  const FAKE_CLIENT_MEDIA_PREFERENCES = {
425
410
  id: 'fake client media preferences',
426
411
  };
427
-
412
+
428
413
  webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(FAKE_REACHABILITY_REPORT);
429
414
  webex.meetings.reachability.getClientMediaPreferences.resolves(FAKE_CLIENT_MEDIA_PREFERENCES);
430
-
415
+
431
416
  sinon
432
417
  .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
433
418
  .get(() => true);
434
419
  sinon
435
420
  .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
436
421
  .get(() => true);
437
-
422
+
438
423
  await MeetingUtil.joinMeeting(meeting, {
439
424
  reachability: 'reachability',
440
425
  roapMessage: 'roapMessage',
@@ -775,6 +760,13 @@ describe('plugin-meetings', () => {
775
760
  });
776
761
  });
777
762
 
763
+ describe('canStartBreakout', () => {
764
+ it('works as expected', () => {
765
+ assert.deepEqual(MeetingUtil.canStartBreakout(['DISABLE_BREAKOUT_START']), false);
766
+ assert.deepEqual(MeetingUtil.canStartBreakout([]), true);
767
+ });
768
+ });
769
+
778
770
  describe('canBroadcastMessageToBreakout', () => {
779
771
  it('works as expected', () => {
780
772
  assert.deepEqual(
@@ -18,7 +18,7 @@ import MeetingInfo, {
18
18
  MeetingInfoV2CaptchaError,
19
19
  MeetingInfoV2AdhocMeetingError,
20
20
  MeetingInfoV2PolicyError,
21
- MeetingInfoV2WebinarRegistrationError,
21
+ MeetingInfoV2JoinWebinarError,
22
22
  } from '@webex/plugin-meetings/src/meeting-info/meeting-info-v2';
23
23
  import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
24
24
  import Metrics from '@webex/plugin-meetings/src/metrics';
@@ -895,9 +895,14 @@ describe('plugin-meetings', () => {
895
895
  {errorCode: 403021},
896
896
  {errorCode: 403022},
897
897
  {errorCode: 403024},
898
+ {errorCode: 403137},
899
+ {errorCode: 423007},
900
+ {errorCode: 403026},
901
+ {errorCode: 403037},
902
+ {errorCode: 403137},
898
903
  ],
899
904
  ({errorCode}) => {
900
- it(`should throw a MeetingInfoV2WebinarRegistrationError for error code ${errorCode}`, async () => {
905
+ it(`should throw a MeetingInfoV2JoinWebinarError for error code ${errorCode}`, async () => {
901
906
  const message = 'a message';
902
907
  const meetingInfoData = {meetingInfo: {registrationUrl: 'registrationUrl'}};
903
908
 
@@ -909,7 +914,7 @@ describe('plugin-meetings', () => {
909
914
  await meetingInfo.createAdhocSpaceMeeting(conversationUrl, installedOrgID);
910
915
  assert.fail('createAdhocSpaceMeeting should have thrown, but has not done that');
911
916
  } catch (err) {
912
- assert.instanceOf(err, MeetingInfoV2WebinarRegistrationError);
917
+ assert.instanceOf(err, MeetingInfoV2JoinWebinarError);
913
918
  assert.deepEqual(err.message, `${message}, code=${errorCode}`);
914
919
  assert.equal(err.wbxAppApiCode, errorCode);
915
920
  assert.deepEqual(err.meetingInfo, meetingInfoData);
@@ -917,7 +922,7 @@ describe('plugin-meetings', () => {
917
922
  assert(Metrics.sendBehavioralMetric.calledOnce);
918
923
  assert.calledWith(
919
924
  Metrics.sendBehavioralMetric,
920
- BEHAVIORAL_METRICS.WEBINAR_REGISTRATION_ERROR,
925
+ BEHAVIORAL_METRICS.JOIN_WEBINAR_ERROR,
921
926
  {code: errorCode}
922
927
  );
923
928
 
@@ -131,9 +131,9 @@ describe('plugin-meetings', () => {
131
131
  logger,
132
132
  people: {
133
133
  _getMe: sinon.stub().resolves({
134
- type: 'validuser',
134
+ type: 'validuser',
135
135
  }),
136
- }
136
+ },
137
137
  });
138
138
 
139
139
  startReachabilityStub = sinon.stub(webex.meetings, 'startReachability').resolves();
@@ -1985,6 +1985,8 @@ describe('plugin-meetings', () => {
1985
1985
  const meetingIds = {
1986
1986
  meetingId: meeting.id,
1987
1987
  correlationId: meeting.correlationId,
1988
+ roles: meeting.roles,
1989
+ callStateForMetrics: meeting.callStateForMetrics,
1988
1990
  };
1989
1991
 
1990
1992
  webex.meetings.destroy(meeting, test1);
@@ -2021,6 +2023,8 @@ describe('plugin-meetings', () => {
2021
2023
 
2022
2024
  assert.equal(deletedMeetingInfo.id, meetingIds.meetingId);
2023
2025
  assert.equal(deletedMeetingInfo.correlationId, meetingIds.correlationId);
2026
+ assert.equal(deletedMeetingInfo.roles, meetingIds.roles);
2027
+ assert.equal(deletedMeetingInfo.callStateForMetrics, meetingIds.callStateForMetrics);
2024
2028
  });
2025
2029
  });
2026
2030
 
@@ -2092,7 +2096,7 @@ describe('plugin-meetings', () => {
2092
2096
  );
2093
2097
  });
2094
2098
 
2095
- const setup = ({me = { type: 'validuser'}, user} = {}) => {
2099
+ const setup = ({me = {type: 'validuser'}, user} = {}) => {
2096
2100
  loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
2097
2101
  assert.deepEqual(webex.internal.services._getCatalog().getAllowedDomains(), []);
2098
2102
 
@@ -2113,9 +2117,9 @@ describe('plugin-meetings', () => {
2113
2117
 
2114
2118
  it('should not call request.getMeetingPreferences if user is a guest', async () => {
2115
2119
  setup({me: {type: 'appuser'}});
2116
-
2120
+
2117
2121
  await webex.meetings.fetchUserPreferredWebexSite();
2118
-
2122
+
2119
2123
  assert.equal(webex.meetings.preferredWebexSite, '');
2120
2124
  assert.deepEqual(webex.internal.services._getCatalog().getAllowedDomains(), []);
2121
2125
  assert.notCalled(webex.internal.services.getMeetingPreferences);
@@ -5,13 +5,13 @@ import {_SEND_RECEIVE_, _RECEIVE_ONLY_} from '../../../../src/constants';
5
5
 
6
6
  describe('plugin-meetings', () => {
7
7
  describe('isHandRaised', () => {
8
- it('throws error when there is no participant', () => {
8
+ it('throws an error when there is no participant', () => {
9
9
  assert.throws(() => {
10
10
  MemberUtil.isHandRaised();
11
11
  }, 'Raise hand could not be processed, participant is undefined.');
12
12
  });
13
13
 
14
- it('returns false when controls is not there', () => {
14
+ it('returns false when controls are not present', () => {
15
15
  const participant = {};
16
16
 
17
17
  assert.isFalse(MemberUtil.isHandRaised(participant));
@@ -51,7 +51,7 @@ describe('plugin-meetings', () => {
51
51
  });
52
52
 
53
53
  describe('MemberUtil.canReclaimHost', () => {
54
- it('throws error when there is no participant', () => {
54
+ it('throws an error when there is no participant', () => {
55
55
  assert.throws(() => {
56
56
  MemberUtil.canReclaimHost();
57
57
  }, 'canReclaimHostRole could not be processed, participant is undefined.');
@@ -352,8 +352,49 @@ describe('plugin-meetings', () => {
352
352
  });
353
353
  });
354
354
 
355
+ describe('MemberUtil.isBrb', () => {
356
+ it('returns true when brb is enabled', () => {
357
+ const participant = {
358
+ controls: {
359
+ brb: {
360
+ enabled: true,
361
+ },
362
+ },
363
+ };
364
+
365
+ assert.isTrue(MemberUtil.isBrb(participant));
366
+ });
367
+
368
+ it('returns false when brb is disabled', () => {
369
+ const participant = {
370
+ controls: {
371
+ brb: {
372
+ enabled: false,
373
+ },
374
+ },
375
+ };
376
+
377
+ assert.isFalse(MemberUtil.isBrb(participant));
378
+ });
379
+
380
+
381
+ it('returns false when brb is not present', () => {
382
+ const participant = {
383
+ controls: {},
384
+ };
385
+
386
+ assert.isFalse(MemberUtil.isBrb(participant));
387
+ });
388
+
389
+ it('returns false when controls is not present', () => {
390
+ const participant = {};
391
+
392
+ assert.isFalse(MemberUtil.isBrb(participant));
393
+ });
394
+ });
395
+
355
396
  describe('MemberUtil.isBreakoutsSupported', () => {
356
- it('throws error when there is no participant', () => {
397
+ it('throws an error when there is no participant', () => {
357
398
  assert.throws(() => {
358
399
  MemberUtil.isBreakoutsSupported();
359
400
  }, 'Breakout support could not be processed, participant is undefined.');
@@ -377,7 +418,7 @@ describe('plugin-meetings', () => {
377
418
  });
378
419
 
379
420
  describe('MemberUtil.isLiveAnnotationSupported', () => {
380
- it('throws error when there is no participant', () => {
421
+ it('throws an error when there is no participant', () => {
381
422
  assert.throws(() => {
382
423
  MemberUtil.isLiveAnnotationSupported();
383
424
  }, 'LiveAnnotation support could not be processed, participant is undefined.');
@@ -401,7 +442,7 @@ describe('plugin-meetings', () => {
401
442
  });
402
443
 
403
444
  describe('MemberUtil.isInterpretationSupported', () => {
404
- it('throws error when there is no participant', () => {
445
+ it('throws an error when there is no participant', () => {
405
446
  assert.throws(() => {
406
447
  MemberUtil.isInterpretationSupported();
407
448
  }, 'Interpretation support could not be processed, participant is undefined.');
@@ -432,7 +473,7 @@ describe('plugin-meetings', () => {
432
473
  };
433
474
 
434
475
  describe('MemberUtil.isAudioMuted', () => {
435
- it('throws error when there is no participant', () => {
476
+ it('throws an error when there is no participant', () => {
436
477
  assert.throws(() => {
437
478
  MemberUtil.isAudioMuted();
438
479
  }, 'Audio could not be processed, participant is undefined.');
@@ -475,7 +516,7 @@ describe('plugin-meetings', () => {
475
516
  });
476
517
 
477
518
  describe('MemberUtil.isVideoMuted', () => {
478
- it('throws error when there is no participant', () => {
519
+ it('throws an error when there is no participant', () => {
479
520
  assert.throws(() => {
480
521
  MemberUtil.isVideoMuted();
481
522
  }, 'Video could not be processed, participant is undefined.');
@@ -519,7 +560,7 @@ describe('plugin-meetings', () => {
519
560
  });
520
561
 
521
562
  describe('extractMediaStatus', () => {
522
- it('throws error when there is no participant', () => {
563
+ it('throws an error when there is no participant', () => {
523
564
  assert.throws(() => {
524
565
  MemberUtil.extractMediaStatus()
525
566
  }, 'Media status could not be extracted, participant is undefined.');
@@ -529,7 +570,7 @@ describe('extractMediaStatus', () => {
529
570
  const participant = {
530
571
  status: {}
531
572
  };
532
-
573
+
533
574
  const mediaStatus = MemberUtil.extractMediaStatus(participant)
534
575
 
535
576
  assert.deepEqual(mediaStatus, {audio: undefined, video: undefined});
@@ -542,7 +583,7 @@ describe('extractMediaStatus', () => {
542
583
  videoStatus: 'SENDRECV'
543
584
  }
544
585
  };
545
-
586
+
546
587
  const mediaStatus = MemberUtil.extractMediaStatus(participant)
547
588
 
548
589
  assert.deepEqual(mediaStatus, {audio: 'RECVONLY', video: 'SENDRECV'});
@@ -262,5 +262,100 @@ describe('plugin-meetings', () => {
262
262
  testParams(false);
263
263
  });
264
264
  });
265
+
266
+ describe('#getAddMemberBody', () => {
267
+ it('returns the correct body with email address and roles', () => {
268
+ const options = {
269
+ invitee: {
270
+ emailAddress: 'test@example.com',
271
+ roles: ['role1', 'role2'],
272
+ },
273
+ alertIfActive: true,
274
+ };
275
+
276
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
277
+ invitees: [
278
+ {
279
+ address: 'test@example.com',
280
+ roles: ['role1', 'role2'],
281
+ },
282
+ ],
283
+ alertIfActive: true,
284
+ });
285
+ });
286
+
287
+ it('returns the correct body with phone number and no roles', () => {
288
+ const options = {
289
+ invitee: {
290
+ phoneNumber: '1234567890',
291
+ },
292
+ alertIfActive: false,
293
+ };
294
+
295
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
296
+ invitees: [
297
+ {
298
+ address: '1234567890',
299
+ },
300
+ ],
301
+ alertIfActive: false,
302
+ });
303
+ });
304
+
305
+ it('returns the correct body with fallback to email', () => {
306
+ const options = {
307
+ invitee: {
308
+ email: 'fallback@example.com',
309
+ },
310
+ alertIfActive: true,
311
+ };
312
+
313
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
314
+ invitees: [
315
+ {
316
+ address: 'fallback@example.com',
317
+ },
318
+ ],
319
+ alertIfActive: true,
320
+ });
321
+ });
322
+
323
+ it('handles missing `alertIfActive` gracefully', () => {
324
+ const options = {
325
+ invitee: {
326
+ emailAddress: 'test@example.com',
327
+ roles: ['role1'],
328
+ },
329
+ };
330
+
331
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
332
+ invitees: [
333
+ {
334
+ address: 'test@example.com',
335
+ roles: ['role1'],
336
+ },
337
+ ],
338
+ alertIfActive: undefined,
339
+ });
340
+ });
341
+
342
+ it('ignores roles if not provided', () => {
343
+ const options = {
344
+ invitee: {
345
+ emailAddress: 'test@example.com',
346
+ },
347
+ alertIfActive: false,
348
+ };
349
+
350
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
351
+ invitees: [
352
+ {
353
+ address: 'test@example.com',
354
+ },
355
+ ],
356
+ alertIfActive: false,
357
+ });
358
+ });
359
+ });
265
360
  });
266
361
  });
@@ -249,14 +249,18 @@ describe('RemoteMedia', () => {
249
249
 
250
250
  forEach(
251
251
  [
252
- {height: 134, fs: 60},
253
- {height: 135, fs: 240},
254
- {height: 269, fs: 240},
255
- {height: 270, fs: 920},
256
- {height: 539, fs: 920},
257
- {height: 540, fs: 3600},
252
+ {height: 90, fs: 60}, // 90p
253
+ {height: 98, fs: 60},
254
+ {height: 99, fs: 240}, // 180p
255
+ {height: 180, fs: 240},
256
+ {height: 197, fs: 240},
257
+ {height: 198, fs: 920}, // 360p
258
+ {height: 360, fs: 920},
259
+ {height: 395, fs: 920},
260
+ {height: 396, fs: 3600}, // 720p
258
261
  {height: 720, fs: 3600},
259
- {height: 721, fs: 8192},
262
+ {height: 721, fs: 8192}, // 1080p
263
+ {height: 1080, fs: 8192},
260
264
  ],
261
265
  ({height, fs}) => {
262
266
  it(`sets the max fs to ${fs} correctly when height is ${height}`, () => {
@@ -15,6 +15,7 @@ describe('ClusterReachability', () => {
15
15
  let previousRTCPeerConnection;
16
16
  let clusterReachability;
17
17
  let fakePeerConnection;
18
+ let gatherIceCandidatesSpy;
18
19
 
19
20
  const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData)[]> = {
20
21
  [Events.resultReady]: [],
@@ -44,6 +45,8 @@ describe('ClusterReachability', () => {
44
45
  xtls: ['stun:xtls1.webex.com', 'stun:xtls2.webex.com:443'],
45
46
  });
46
47
 
48
+ gatherIceCandidatesSpy = sinon.spy(clusterReachability, 'gatherIceCandidates');
49
+
47
50
  resetEmittedEvents();
48
51
 
49
52
  clusterReachability.on(Events.resultReady, (data: ResultEventData) => {
@@ -151,6 +154,10 @@ describe('ClusterReachability', () => {
151
154
  assert.calledOnceWithExactly(fakePeerConnection.createOffer, {offerToReceiveAudio: true});
152
155
  assert.calledOnce(fakePeerConnection.setLocalDescription);
153
156
 
157
+ // Make sure that gatherIceCandidates is called before setLocalDescription
158
+ // as setLocalDescription triggers the ICE gathering process
159
+ assert.isTrue(gatherIceCandidatesSpy.calledBefore(fakePeerConnection.setLocalDescription));
160
+
154
161
  clusterReachability.abort();
155
162
  await promise;
156
163
 
@@ -221,7 +221,21 @@ describe('plugin-meetings', () => {
221
221
 
222
222
  assert.calledWith(request.request, {
223
223
  uri: `test/loci/id/recording`,
224
- body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'start'}},
224
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'start'}, recordingType: 'cloud'},
225
+ method: HTTP_VERBS.PUT,
226
+ });
227
+
228
+ assert.deepEqual(result, request.request.firstCall.returnValue);
229
+ });
230
+
231
+ it('can start premise recording when the correct display hint is present', () => {
232
+ controller.setDisplayHints(['PREMISE_RECORDING_CONTROL_START']);
233
+
234
+ const result = controller.startRecording();
235
+
236
+ assert.calledWith(request.request, {
237
+ uri: `test/loci/id/recording`,
238
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'start'}, recordingType: 'premise'},
225
239
  method: HTTP_VERBS.PUT,
226
240
  });
227
241
 
@@ -238,14 +252,28 @@ describe('plugin-meetings', () => {
238
252
  assert.isRejected(result);
239
253
  });
240
254
 
241
- it('can start recording when the correct display hint is present', () => {
255
+ it('can stop recording when the correct display hint is present', () => {
242
256
  controller.setDisplayHints(['RECORDING_CONTROL_STOP']);
243
257
 
244
258
  const result = controller.stopRecording();
245
259
 
246
260
  assert.calledWith(request.request, {
247
261
  uri: `test/loci/id/recording`,
248
- body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'stop'}},
262
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'stop'}, recordingType: 'cloud'},
263
+ method: HTTP_VERBS.PUT,
264
+ });
265
+
266
+ assert.deepEqual(result, request.request.firstCall.returnValue);
267
+ });
268
+
269
+ it('can stop premise recording when the correct display hint is present', () => {
270
+ controller.setDisplayHints(['PREMISE_RECORDING_CONTROL_STOP']);
271
+
272
+ const result = controller.stopRecording();
273
+
274
+ assert.calledWith(request.request, {
275
+ uri: `test/loci/id/recording`,
276
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'stop'}, recordingType: 'premise'},
249
277
  method: HTTP_VERBS.PUT,
250
278
  });
251
279
 
@@ -269,7 +297,21 @@ describe('plugin-meetings', () => {
269
297
 
270
298
  assert.calledWith(request.request, {
271
299
  uri: `test/loci/id/recording`,
272
- body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'pause'}},
300
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'pause'}, recordingType: 'cloud'},
301
+ method: HTTP_VERBS.PUT,
302
+ });
303
+
304
+ assert.deepEqual(result, request.request.firstCall.returnValue);
305
+ });
306
+
307
+ it('can pause premise recording when the correct display hint is present', () => {
308
+ controller.setDisplayHints(['PREMISE_RECORDING_CONTROL_PAUSE']);
309
+
310
+ const result = controller.pauseRecording();
311
+
312
+ assert.calledWith(request.request, {
313
+ uri: `test/loci/id/recording`,
314
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'pause'}, recordingType: 'premise'},
273
315
  method: HTTP_VERBS.PUT,
274
316
  });
275
317
 
@@ -293,7 +335,21 @@ describe('plugin-meetings', () => {
293
335
 
294
336
  assert.calledWith(request.request, {
295
337
  uri: `test/loci/id/recording`,
296
- body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'resume'}},
338
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'resume'}, recordingType: 'cloud'},
339
+ method: HTTP_VERBS.PUT,
340
+ });
341
+
342
+ assert.deepEqual(result, request.request.firstCall.returnValue);
343
+ });
344
+
345
+ it('can resume premise recording when the correct display hint is present', () => {
346
+ controller.setDisplayHints(['PREMISE_RECORDING_CONTROL_RESUME']);
347
+
348
+ const result = controller.resumeRecording();
349
+
350
+ assert.calledWith(request.request, {
351
+ uri: `test/loci/id/recording`,
352
+ body: {meetingInfo: {locusSessionId: 'testId'}, recording: {action: 'resume'}, recordingType: 'premise'},
297
353
  method: HTTP_VERBS.PUT,
298
354
  });
299
355
 
@@ -1,5 +1,5 @@
1
1
  import RecordingUtil from '@webex/plugin-meetings/src/recording-controller/util';
2
- import RecordingAction from '@webex/plugin-meetings/src/recording-controller/enums';
2
+ import { RecordingAction } from '@webex/plugin-meetings/src/recording-controller/enums';
3
3
  import {SELF_POLICY} from '@webex/plugin-meetings/src/constants';
4
4
 
5
5
  import {assert} from 'chai';
@@ -29,6 +29,15 @@ describe('plugin-meetings', () => {
29
29
  );
30
30
  });
31
31
 
32
+ it('can start premise recording when the correct display hint is present', () => {
33
+ locusInfo.parsedLocus.info.userDisplayHints.push('PREMISE_RECORDING_CONTROL_START');
34
+
35
+ assert.equal(
36
+ RecordingUtil.canUserStart(locusInfo.parsedLocus.info.userDisplayHints),
37
+ true
38
+ );
39
+ });
40
+
32
41
  it('can start recording when the correct display hint is present and the policy is true', () => {
33
42
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_START');
34
43
 
@@ -69,6 +78,15 @@ describe('plugin-meetings', () => {
69
78
  );
70
79
  });
71
80
 
81
+ it('can pause premise recording when the correct display hint is present', () => {
82
+ locusInfo.parsedLocus.info.userDisplayHints.push('PREMISE_RECORDING_CONTROL_PAUSE');
83
+
84
+ assert.equal(
85
+ RecordingUtil.canUserPause(locusInfo.parsedLocus.info.userDisplayHints),
86
+ true
87
+ );
88
+ });
89
+
72
90
  it('can pause recording when the correct display hint is present and the policy is true', () => {
73
91
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_PAUSE');
74
92
 
@@ -109,6 +127,15 @@ describe('plugin-meetings', () => {
109
127
  );
110
128
  });
111
129
 
130
+ it('can stop premise recording when the correct display hint is present', () => {
131
+ locusInfo.parsedLocus.info.userDisplayHints.push('PREMISE_RECORDING_CONTROL_STOP');
132
+
133
+ assert.equal(
134
+ RecordingUtil.canUserStop(locusInfo.parsedLocus.info.userDisplayHints),
135
+ true
136
+ );
137
+ });
138
+
112
139
  it('can stop recording when the correct display hint is present and the policy is true', () => {
113
140
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_STOP', {
114
141
  [SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD]: true,
@@ -142,7 +169,7 @@ describe('plugin-meetings', () => {
142
169
  });
143
170
 
144
171
  describe('canUserResume', () => {
145
- it('can start recording when the correct display hint is present', () => {
172
+ it('can resume recording when the correct display hint is present', () => {
146
173
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_RESUME');
147
174
 
148
175
  assert.equal(
@@ -151,7 +178,16 @@ describe('plugin-meetings', () => {
151
178
  );
152
179
  });
153
180
 
154
- it('can start recording when the correct display hint is present and the policy is true', () => {
181
+ it('can resume premise recording when the correct display hint is present', () => {
182
+ locusInfo.parsedLocus.info.userDisplayHints.push('PREMISE_RECORDING_CONTROL_RESUME');
183
+
184
+ assert.equal(
185
+ RecordingUtil.canUserResume(locusInfo.parsedLocus.info.userDisplayHints),
186
+ true
187
+ );
188
+ });
189
+
190
+ it('can resume recording when the correct display hint is present and the policy is true', () => {
155
191
  locusInfo.parsedLocus.info.userDisplayHints.push('RECORDING_CONTROL_RESUME');
156
192
 
157
193
  assert.equal(