@webex/plugin-meetings 3.8.1-next.3 → 3.8.1-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 (80) hide show
  1. package/README.md +26 -13
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/constants.js +21 -2
  5. package/dist/constants.js.map +1 -1
  6. package/dist/interpretation/index.js +1 -1
  7. package/dist/interpretation/siLanguage.js +1 -1
  8. package/dist/locus-info/index.js +38 -84
  9. package/dist/locus-info/index.js.map +1 -1
  10. package/dist/media/index.js +2 -2
  11. package/dist/media/index.js.map +1 -1
  12. package/dist/meeting/brbState.js +14 -12
  13. package/dist/meeting/brbState.js.map +1 -1
  14. package/dist/meeting/index.js +169 -66
  15. package/dist/meeting/index.js.map +1 -1
  16. package/dist/meeting/request.js +19 -0
  17. package/dist/meeting/request.js.map +1 -1
  18. package/dist/meeting/request.type.js.map +1 -1
  19. package/dist/meetings/index.js +35 -33
  20. package/dist/meetings/index.js.map +1 -1
  21. package/dist/members/index.js +8 -6
  22. package/dist/members/index.js.map +1 -1
  23. package/dist/members/request.js +3 -3
  24. package/dist/members/request.js.map +1 -1
  25. package/dist/members/util.js +18 -6
  26. package/dist/members/util.js.map +1 -1
  27. package/dist/multistream/mediaRequestManager.js +1 -1
  28. package/dist/multistream/mediaRequestManager.js.map +1 -1
  29. package/dist/multistream/remoteMedia.js +34 -5
  30. package/dist/multistream/remoteMedia.js.map +1 -1
  31. package/dist/multistream/remoteMediaGroup.js +42 -2
  32. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  33. package/dist/multistream/sendSlotManager.js +32 -2
  34. package/dist/multistream/sendSlotManager.js.map +1 -1
  35. package/dist/reachability/index.js +5 -10
  36. package/dist/reachability/index.js.map +1 -1
  37. package/dist/types/constants.d.ts +19 -0
  38. package/dist/types/locus-info/index.d.ts +0 -9
  39. package/dist/types/meeting/brbState.d.ts +0 -1
  40. package/dist/types/meeting/index.d.ts +28 -4
  41. package/dist/types/meeting/request.d.ts +9 -1
  42. package/dist/types/meeting/request.type.d.ts +74 -0
  43. package/dist/types/members/index.d.ts +8 -3
  44. package/dist/types/members/request.d.ts +1 -1
  45. package/dist/types/members/util.d.ts +5 -2
  46. package/dist/types/multistream/remoteMedia.d.ts +20 -1
  47. package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
  48. package/dist/types/multistream/sendSlotManager.d.ts +16 -0
  49. package/dist/types/reachability/index.d.ts +2 -2
  50. package/dist/webinar/index.js +1 -1
  51. package/package.json +24 -24
  52. package/src/constants.ts +20 -0
  53. package/src/locus-info/index.ts +47 -82
  54. package/src/media/index.ts +2 -2
  55. package/src/meeting/brbState.ts +9 -7
  56. package/src/meeting/index.ts +126 -23
  57. package/src/meeting/request.ts +16 -0
  58. package/src/meeting/request.type.ts +64 -0
  59. package/src/meetings/index.ts +3 -2
  60. package/src/members/index.ts +7 -5
  61. package/src/members/request.ts +2 -2
  62. package/src/members/util.ts +14 -3
  63. package/src/multistream/mediaRequestManager.ts +7 -7
  64. package/src/multistream/remoteMedia.ts +34 -4
  65. package/src/multistream/remoteMediaGroup.ts +37 -2
  66. package/src/multistream/sendSlotManager.ts +34 -2
  67. package/src/reachability/index.ts +5 -13
  68. package/test/unit/spec/locus-info/index.js +177 -83
  69. package/test/unit/spec/media/index.ts +107 -0
  70. package/test/unit/spec/meeting/brbState.ts +9 -9
  71. package/test/unit/spec/meeting/index.js +606 -55
  72. package/test/unit/spec/meeting/request.js +71 -0
  73. package/test/unit/spec/meetings/index.js +1 -0
  74. package/test/unit/spec/members/index.js +32 -9
  75. package/test/unit/spec/members/request.js +2 -2
  76. package/test/unit/spec/members/utils.js +27 -7
  77. package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
  78. package/test/unit/spec/multistream/remoteMedia.ts +66 -2
  79. package/test/unit/spec/multistream/sendSlotManager.ts +59 -0
  80. package/test/unit/spec/reachability/index.ts +2 -6
@@ -305,7 +305,7 @@ describe('plugin-meetings', () => {
305
305
  {state: newControls.rdcControl}
306
306
  );
307
307
  });
308
-
308
+
309
309
  it('should trigger the CONTROLS_POLLING_QA_CHANGED event when necessary', () => {
310
310
  locusInfo.controls = {};
311
311
  locusInfo.emitScoped = sinon.stub();
@@ -834,39 +834,6 @@ describe('plugin-meetings', () => {
834
834
  );
835
835
  });
836
836
 
837
- it('should update the deltaParticipants object', () => {
838
- const prev = locusInfo.deltaParticipants;
839
-
840
- locusInfo.updateParticipantDeltas(newParticipants);
841
-
842
- assert.notEqual(locusInfo.deltaParticipants, prev);
843
- });
844
-
845
- it('should update the delta property on all changed states', () => {
846
- locusInfo.updateParticipantDeltas(newParticipants);
847
-
848
- const [exampleParticipant] = locusInfo.deltaParticipants;
849
-
850
- assert.isTrue(exampleParticipant.delta.audioStatus);
851
- assert.isTrue(exampleParticipant.delta.videoSlidesStatus);
852
- assert.isTrue(exampleParticipant.delta.videoStatus);
853
- });
854
-
855
- it('should include the person details of the changed participant', () => {
856
- locusInfo.updateParticipantDeltas(newParticipants);
857
-
858
- const [exampleParticipant] = locusInfo.deltaParticipants;
859
-
860
- assert.equal(exampleParticipant.person, newParticipants[0].person);
861
- });
862
-
863
- it('should clear deltaParticipants when no changes occured', () => {
864
- locusInfo.participants = [...newParticipants];
865
-
866
- locusInfo.updateParticipantDeltas(locusInfo.participants);
867
-
868
- assert.isTrue(locusInfo.deltaParticipants.length === 0);
869
- });
870
837
 
871
838
  it('should call with participant display name', () => {
872
839
  const failureParticipant = [
@@ -2108,6 +2075,38 @@ describe('plugin-meetings', () => {
2108
2075
  assert.isFunction(locusParser.onDeltaAction);
2109
2076
  });
2110
2077
 
2078
+ it("#updateLocusInfo invokes updateLocusUrl before updateMeetingInfo", () => {
2079
+ const callOrder = [];
2080
+ sinon.stub(locusInfo, "updateControls");
2081
+ sinon.stub(locusInfo, "updateConversationUrl");
2082
+ sinon.stub(locusInfo, "updateCreated");
2083
+ sinon.stub(locusInfo, "updateFullState");
2084
+ sinon.stub(locusInfo, "updateHostInfo");
2085
+ sinon.stub(locusInfo, "updateMeetingInfo").callsFake(() => {
2086
+ callOrder.push("updateMeetingInfo");
2087
+ });
2088
+ sinon.stub(locusInfo, "updateMediaShares");
2089
+ sinon.stub(locusInfo, "updateParticipantsUrl");
2090
+ sinon.stub(locusInfo, "updateReplace");
2091
+ sinon.stub(locusInfo, "updateSelf");
2092
+ sinon.stub(locusInfo, "updateLocusUrl").callsFake(() => {
2093
+ callOrder.push("updateLocusUrl");
2094
+ });
2095
+ sinon.stub(locusInfo, "updateAclUrl");
2096
+ sinon.stub(locusInfo, "updateBasequence");
2097
+ sinon.stub(locusInfo, "updateSequence");
2098
+ sinon.stub(locusInfo, "updateMemberShip");
2099
+ sinon.stub(locusInfo, "updateIdentifiers");
2100
+ sinon.stub(locusInfo, "updateEmbeddedApps");
2101
+ sinon.stub(locusInfo, "updateResources");
2102
+ sinon.stub(locusInfo, "compareAndUpdate");
2103
+
2104
+ locusInfo.updateLocusInfo(locus);
2105
+
2106
+ // Ensure updateLocusUrl is called before updateMeetingInfo if both are called
2107
+ assert.deepEqual(callOrder, ['updateLocusUrl', 'updateMeetingInfo']);
2108
+ });
2109
+
2111
2110
  it('#updateLocusInfo ignores breakout LEFT message', () => {
2112
2111
  const newLocus = {
2113
2112
  self: {
@@ -2159,10 +2158,11 @@ describe('plugin-meetings', () => {
2159
2158
  assert.notCalled(locusInfo.compareAndUpdate);
2160
2159
  });
2161
2160
 
2161
+
2162
+
2162
2163
  it('onFullLocus() updates the working-copy of locus parser', () => {
2163
2164
  const eventType = 'fakeEvent';
2164
2165
 
2165
- sandbox.stub(locusInfo, 'updateParticipantDeltas');
2166
2166
  sandbox.stub(locusInfo, 'updateLocusInfo');
2167
2167
  sandbox.stub(locusInfo, 'updateParticipants');
2168
2168
  sandbox.stub(locusInfo, 'isMeetingActive');
@@ -2182,7 +2182,6 @@ describe('plugin-meetings', () => {
2182
2182
  const oldWorkingCopy = locusParser.workingCopy;
2183
2183
 
2184
2184
  const spies = [
2185
- sandbox.stub(locusInfo, 'updateParticipantDeltas'),
2186
2185
  sandbox.stub(locusInfo, 'updateLocusInfo'),
2187
2186
  sandbox.stub(locusInfo, 'updateParticipants'),
2188
2187
  sandbox.stub(locusInfo, 'isMeetingActive'),
@@ -2257,7 +2256,7 @@ describe('plugin-meetings', () => {
2257
2256
 
2258
2257
  it('applyLocusDeltaData gets delta locus on DESYNC action if we have a syncUrl', () => {
2259
2258
  const {DESYNC} = LocusDeltaParser.loci;
2260
- const fakeDeltaLocus = {id: 'fake delta locus'};
2259
+ const fakeDeltaLocus = {baseSequence: {}, id: 'fake delta locus'};
2261
2260
  const meeting = {
2262
2261
  meetingRequest: {
2263
2262
  getLocusDTO: sandbox.stub().resolves({body: fakeDeltaLocus}),
@@ -2392,25 +2391,22 @@ describe('plugin-meetings', () => {
2392
2391
  };
2393
2392
  });
2394
2393
 
2395
- it('applyLocusDeltaData gets full locus on DESYNC action if we do not have a syncUrl and destroys the meeting if that fails', () => {
2394
+ it('applyLocusDeltaData gets full locus on DESYNC action if we do not have a syncUrl and destroys the meeting if that fails', async () => {
2396
2395
  meeting.meetingRequest.getLocusDTO.rejects(new Error('fake error'));
2397
2396
 
2398
2397
  locusInfo.locusParser.workingCopy = {}; // no syncUrl
2399
2398
 
2400
- // Since we have a promise inside a function we want to test that's not returned,
2401
- // we will wait and stub it's last function to resolve this waiting promise.
2402
- return new Promise((resolve) => {
2403
- webex.meetings.destroy.callsFake(() => resolve());
2404
- locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
2405
- }).then(() => {
2406
- assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {url: 'fullSyncUrl'});
2399
+ locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
2407
2400
 
2408
- assert.notCalled(meeting.locusInfo.handleLocusDelta);
2409
- assert.notCalled(meeting.locusInfo.onFullLocus);
2410
- assert.notCalled(locusInfo.locusParser.resume);
2401
+ await testUtils.flushPromises();
2411
2402
 
2412
- assert.calledOnceWithExactly(webex.meetings.destroy, meeting, 'LOCUS_DTO_SYNC_FAILED');
2413
- });
2403
+ assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {url: 'fullSyncUrl'});
2404
+
2405
+ assert.notCalled(meeting.locusInfo.handleLocusDelta);
2406
+ assert.notCalled(meeting.locusInfo.onFullLocus);
2407
+ assert.notCalled(locusInfo.locusParser.resume);
2408
+
2409
+ assert.calledOnceWithExactly(webex.meetings.destroy, meeting, 'LOCUS_DTO_SYNC_FAILED');
2414
2410
  });
2415
2411
 
2416
2412
  it('applyLocusDeltaData first tries a delta sync on DESYNC action and if that fails, does a full locus sync', () => {
@@ -2447,39 +2443,62 @@ describe('plugin-meetings', () => {
2447
2443
  });
2448
2444
  });
2449
2445
 
2450
- it('applyLocusDeltaData destroys the meeting if both delta sync and full sync fail', () => {
2446
+ it('applyLocusDeltaData first tries a delta sync on DESYNC action and if that fails with 403, it does not do a full locus sync', async () => {
2447
+ const fake403Error = new Error('fake error');
2448
+ fake403Error.statusCode = 403;
2449
+
2450
+ meeting.meetingRequest.getLocusDTO.onCall(0).rejects(fake403Error);
2451
+
2452
+ locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
2453
+
2454
+ await testUtils.flushPromises();
2455
+
2456
+ assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {url: 'deltaSyncUrl'});
2457
+
2458
+ assert.calledWith(sendBehavioralMetricStub, 'js_sdk_locus_delta_sync_failed', {
2459
+ correlationId: meeting.correlationId,
2460
+ url: 'deltaSyncUrl',
2461
+ reason: 'fake error',
2462
+ errorName: 'Error',
2463
+ stack: sinon.match.any,
2464
+ code: sinon.match.any,
2465
+ });
2466
+
2467
+ assert.notCalled(meeting.locusInfo.handleLocusDelta);
2468
+ assert.notCalled(meeting.locusInfo.onFullLocus);
2469
+ assert.notCalled(locusInfo.locusParser.resume);
2470
+ });
2471
+
2472
+ it('applyLocusDeltaData destroys the meeting if both delta sync and full sync fail', async () => {
2451
2473
  meeting.meetingRequest.getLocusDTO.rejects(new Error('fake error'));
2452
2474
 
2453
- // Since we have a promise inside a function we want to test that's not returned,
2454
- // we will wait and stub it's last function to resolve this waiting promise.
2455
- return new Promise((resolve) => {
2456
- webex.meetings.destroy.callsFake(() => resolve());
2457
- locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
2458
- }).then(() => {
2459
- assert.calledTwice(meeting.meetingRequest.getLocusDTO);
2475
+ locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
2460
2476
 
2461
- assert.deepEqual(meeting.meetingRequest.getLocusDTO.getCalls()[0].args, [
2462
- {url: 'deltaSyncUrl'},
2463
- ]);
2464
- assert.deepEqual(meeting.meetingRequest.getLocusDTO.getCalls()[1].args, [
2465
- {url: 'fullSyncUrl'},
2466
- ]);
2477
+ await testUtils.flushPromises();
2467
2478
 
2468
- assert.calledWith(sendBehavioralMetricStub, 'js_sdk_locus_delta_sync_failed', {
2469
- correlationId: meeting.correlationId,
2470
- url: 'deltaSyncUrl',
2471
- reason: 'fake error',
2472
- errorName: 'Error',
2473
- stack: sinon.match.any,
2474
- code: sinon.match.any,
2475
- });
2479
+ assert.calledTwice(meeting.meetingRequest.getLocusDTO);
2476
2480
 
2477
- assert.notCalled(meeting.locusInfo.handleLocusDelta);
2478
- assert.notCalled(meeting.locusInfo.onFullLocus);
2479
- assert.notCalled(locusInfo.locusParser.resume);
2481
+ assert.deepEqual(meeting.meetingRequest.getLocusDTO.getCalls()[0].args, [
2482
+ {url: 'deltaSyncUrl'},
2483
+ ]);
2484
+ assert.deepEqual(meeting.meetingRequest.getLocusDTO.getCalls()[1].args, [
2485
+ {url: 'fullSyncUrl'},
2486
+ ]);
2480
2487
 
2481
- assert.calledOnceWithExactly(webex.meetings.destroy, meeting, 'LOCUS_DTO_SYNC_FAILED');
2488
+ assert.calledWith(sendBehavioralMetricStub, 'js_sdk_locus_delta_sync_failed', {
2489
+ correlationId: meeting.correlationId,
2490
+ url: 'deltaSyncUrl',
2491
+ reason: 'fake error',
2492
+ errorName: 'Error',
2493
+ stack: sinon.match.any,
2494
+ code: sinon.match.any,
2482
2495
  });
2496
+
2497
+ assert.notCalled(meeting.locusInfo.handleLocusDelta);
2498
+ assert.notCalled(meeting.locusInfo.onFullLocus);
2499
+ assert.notCalled(locusInfo.locusParser.resume);
2500
+
2501
+ assert.calledOnceWithExactly(webex.meetings.destroy, meeting, 'LOCUS_DTO_SYNC_FAILED');
2483
2502
  });
2484
2503
  });
2485
2504
 
@@ -2509,9 +2528,7 @@ describe('plugin-meetings', () => {
2509
2528
  });
2510
2529
 
2511
2530
  it('onDeltaLocus merges delta participants with existing participants', () => {
2512
- const FAKE_DELTA_PARTICIPANTS = [
2513
- {id: '1111'}, {id: '2222'}
2514
- ]
2531
+ const FAKE_DELTA_PARTICIPANTS = [{id: '1111'}, {id: '2222'}];
2515
2532
  fakeLocus.participants = FAKE_DELTA_PARTICIPANTS;
2516
2533
 
2517
2534
  sinon.spy(locusInfo, 'mergeParticipants');
@@ -2519,9 +2536,87 @@ describe('plugin-meetings', () => {
2519
2536
  const existingParticipants = locusInfo.participants;
2520
2537
 
2521
2538
  locusInfo.onDeltaLocus(fakeLocus);
2522
- assert.calledOnceWithExactly(locusInfo.mergeParticipants, existingParticipants, FAKE_DELTA_PARTICIPANTS);
2539
+ assert.calledOnceWithExactly(
2540
+ locusInfo.mergeParticipants,
2541
+ existingParticipants,
2542
+ FAKE_DELTA_PARTICIPANTS
2543
+ );
2523
2544
  assert.calledWith(locusInfo.updateParticipants, FAKE_DELTA_PARTICIPANTS, false);
2524
2545
  });
2546
+
2547
+ [true, false].forEach((isDelta) =>
2548
+ it(`applyLocusDeltaData - handles empty ${
2549
+ isDelta ? 'delta' : 'full'
2550
+ } DTO in response`, async () => {
2551
+ const {DESYNC} = LocusDeltaParser.loci;
2552
+ const fakeFullLocusDto = {};
2553
+ const meeting = {
2554
+ meetingRequest: {
2555
+ getLocusDTO: sandbox.stub().resolves({body: fakeFullLocusDto}),
2556
+ },
2557
+ locusInfo: {
2558
+ onFullLocus: sandbox.stub(),
2559
+ handleLocusDelta: sandbox.stub(),
2560
+ },
2561
+ locusUrl: 'fake locus FULL url',
2562
+ };
2563
+
2564
+ sinon.stub(locusInfo.locusParser, 'resume').resolves();
2565
+
2566
+ if (isDelta) {
2567
+ locusInfo.locusParser.workingCopy = {syncUrl: 'fake locus DELTA url'};
2568
+ } else {
2569
+ locusInfo.locusParser.workingCopy = {}; // no syncUrl (to trigger FULL DTO request)
2570
+ }
2571
+
2572
+ await locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
2573
+
2574
+ await testUtils.flushPromises();
2575
+
2576
+ if (isDelta) {
2577
+ assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {
2578
+ url: 'fake locus DELTA url',
2579
+ });
2580
+ } else {
2581
+ assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {
2582
+ url: 'fake locus FULL url',
2583
+ });
2584
+ }
2585
+ assert.notCalled(meeting.locusInfo.handleLocusDelta);
2586
+ assert.notCalled(meeting.locusInfo.onFullLocus);
2587
+ assert.calledOnce(locusInfo.locusParser.resume);
2588
+ })
2589
+ );
2590
+
2591
+ it(`applyLocusDeltaData - handles the case when we get FULL DTO when we asked for DELTA DTO`, async () => {
2592
+ const {DESYNC} = LocusDeltaParser.loci;
2593
+ const fakeFullLocusDto = {someStuff: 'data'}; // non-empty DTO, without baseSequence
2594
+ const meeting = {
2595
+ meetingRequest: {
2596
+ getLocusDTO: sandbox.stub().resolves({body: fakeFullLocusDto}),
2597
+ },
2598
+ locusInfo: {
2599
+ onFullLocus: sandbox.stub(),
2600
+ handleLocusDelta: sandbox.stub(),
2601
+ },
2602
+ locusUrl: 'fake locus FULL url',
2603
+ };
2604
+
2605
+ sinon.stub(locusInfo.locusParser, 'resume').resolves();
2606
+
2607
+ locusInfo.locusParser.workingCopy = {syncUrl: 'fake locus DELTA url'};
2608
+
2609
+ await locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
2610
+
2611
+ await testUtils.flushPromises();
2612
+
2613
+ assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {
2614
+ url: 'fake locus DELTA url',
2615
+ });
2616
+ assert.notCalled(meeting.locusInfo.handleLocusDelta);
2617
+ assert.calledOnceWithExactly(meeting.locusInfo.onFullLocus, fakeFullLocusDto);
2618
+ assert.calledOnce(locusInfo.locusParser.resume);
2619
+ });
2525
2620
  });
2526
2621
 
2527
2622
  describe('#updateLocusCache', () => {
@@ -2934,10 +3029,9 @@ describe('plugin-meetings', () => {
2934
3029
  beforeEach(() => {
2935
3030
  clock = sinon.useFakeTimers();
2936
3031
 
2937
- sinon.stub(locusInfo, 'updateParticipantDeltas');
2938
3032
  sinon.stub(locusInfo, 'updateParticipants');
2939
- sinon.stub(locusInfo, 'isMeetingActive'),
2940
- sinon.stub(locusInfo, 'handleOneOnOneEvent'),
3033
+ sinon.stub(locusInfo, 'isMeetingActive');
3034
+ sinon.stub(locusInfo, 'handleOneOnOneEvent');
2941
3035
  (updateLocusInfoStub = sinon.stub(locusInfo, 'updateLocusInfo'));
2942
3036
  syncRequestStub = sinon.stub().resolves({body: {}});
2943
3037
 
@@ -137,6 +137,113 @@ describe('createMediaConnection', () => {
137
137
  );
138
138
  });
139
139
 
140
+ it('should set direction to sendonly for both audio and video when only send flags are true', () => {
141
+ const roapMediaConnectionConstructorStub = sinon
142
+ .stub(InternalMediaCoreModule, 'RoapMediaConnection')
143
+ .returns(fakeRoapMediaConnection);
144
+
145
+ StaticConfig.set({bandwidth: {audio: 123, video: 456, startBitrate: 999}});
146
+
147
+ const ENABLE_EXTMAP = false;
148
+ const ENABLE_RTX = true;
149
+
150
+ Media.createMediaConnection(false, 'sendonly-debug-id', 'meetingId', {
151
+ mediaProperties: {
152
+ mediaDirection: {
153
+ sendAudio: true,
154
+ receiveAudio: false,
155
+ sendVideo: true,
156
+ receiveVideo: false,
157
+ sendShare: false,
158
+ receiveShare: false,
159
+ },
160
+ audioStream: fakeAudioStream,
161
+ videoStream: fakeVideoStream,
162
+ shareVideoTrack: null,
163
+ shareAudioTrack: null,
164
+ },
165
+ remoteQualityLevel: 'HIGH',
166
+ enableRtx: ENABLE_RTX,
167
+ enableExtmap: ENABLE_EXTMAP,
168
+ turnServerInfo: undefined,
169
+ iceCandidatesTimeout: undefined,
170
+ });
171
+
172
+ assert.calledWith(
173
+ roapMediaConnectionConstructorStub,
174
+ sinon.match.any,
175
+ {
176
+ localTracks: {
177
+ audio: fakeTrack,
178
+ video: fakeTrack,
179
+ screenShareVideo: undefined,
180
+ screenShareAudio: undefined,
181
+ },
182
+ direction: {
183
+ audio: 'sendonly',
184
+ video: 'sendonly',
185
+ screenShareVideo: 'inactive',
186
+ },
187
+ remoteQualityLevel: 'HIGH',
188
+ },
189
+ 'sendonly-debug-id'
190
+ );
191
+ });
192
+
193
+ it('should set direction to recvonly for both audio and video when only receive flags are true', () => {
194
+ const roapMediaConnectionConstructorStub = sinon
195
+ .stub(InternalMediaCoreModule, 'RoapMediaConnection')
196
+ .returns(fakeRoapMediaConnection);
197
+
198
+ StaticConfig.set({bandwidth: {audio: 123, video: 456, startBitrate: 999}});
199
+
200
+ const ENABLE_EXTMAP = true;
201
+ const ENABLE_RTX = false;
202
+
203
+ Media.createMediaConnection(false, 'recvonly-debug-id', 'meetingId', {
204
+ mediaProperties: {
205
+ mediaDirection: {
206
+ sendAudio: false,
207
+ receiveAudio: true,
208
+ sendVideo: false,
209
+ receiveVideo: true,
210
+ sendShare: false,
211
+ receiveShare: false,
212
+ },
213
+ audioStream: fakeAudioStream,
214
+ videoStream: fakeVideoStream,
215
+ shareVideoTrack: null,
216
+ shareAudioTrack: null,
217
+ },
218
+ remoteQualityLevel: 'HIGH',
219
+ enableRtx: ENABLE_RTX,
220
+ enableExtmap: ENABLE_EXTMAP,
221
+ turnServerInfo: undefined,
222
+ iceCandidatesTimeout: undefined,
223
+ });
224
+
225
+ assert.calledWith(
226
+ roapMediaConnectionConstructorStub,
227
+ sinon.match.any,
228
+ {
229
+ localTracks: {
230
+ audio: fakeTrack,
231
+ video: fakeTrack,
232
+ screenShareVideo: undefined,
233
+ screenShareAudio: undefined,
234
+ },
235
+ direction: {
236
+ audio: 'recvonly',
237
+ video: 'recvonly',
238
+ screenShareVideo: 'inactive',
239
+ },
240
+ remoteQualityLevel: 'HIGH',
241
+ },
242
+ 'recvonly-debug-id'
243
+ );
244
+ });
245
+
246
+
140
247
  it('creates a MultistreamRoapMediaConnection when multistream is enabled', () => {
141
248
  const multistreamRoapMediaConnectionConstructorStub = sinon
142
249
  .stub(InternalMediaCoreModule, 'MultistreamRoapMediaConnection')
@@ -3,12 +3,12 @@ import {assert, expect} from '@webex/test-helper-chai';
3
3
 
4
4
  import testUtils from '../../../utils/testUtils';
5
5
  import {BrbState, createBrbState} from '@webex/plugin-meetings/src/meeting/brbState';
6
- import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
6
+ import {MediaType} from '@webex/internal-media-core';
7
7
 
8
8
  describe('plugin-meetings', () => {
9
9
  let meeting: any;
10
10
  let brbState: BrbState;
11
- let setBrbStub: sinon.SinonStub;
11
+ let setBrbStub: sinon.SinonStub;
12
12
 
13
13
  beforeEach(async () => {
14
14
  meeting = {
@@ -23,7 +23,7 @@ describe('plugin-meetings', () => {
23
23
  setSourceStateOverride: sinon.stub(),
24
24
  },
25
25
  meetingRequest: {
26
- setBrb: () => {}
26
+ setBrb: () => {},
27
27
  },
28
28
  };
29
29
 
@@ -104,12 +104,12 @@ describe('plugin-meetings', () => {
104
104
  assert.isTrue(meeting.meetingRequest.setBrb.calledOnce);
105
105
  });
106
106
 
107
- it('sets source state override when client state does not match server state', async () => {
107
+ it('updates source state override', async () => {
108
108
  brbState.enable(true, meeting.sendSlotManager);
109
109
  brbState.handleServerBrbUpdate(true);
110
110
  await testUtils.flushPromises();
111
111
 
112
- assert.isTrue(meeting.sendSlotManager.setSourceStateOverride.calledOnce);
112
+ assert.isTrue(meeting.sendSlotManager.setSourceStateOverride.called);
113
113
  });
114
114
 
115
115
  it('handles server update', async () => {
@@ -141,12 +141,12 @@ describe('plugin-meetings', () => {
141
141
  it('should reject when sendLocalBrbStateToServer fails', async () => {
142
142
  const error = new Error('send failed');
143
143
  setBrbStub.rejects(error);
144
-
145
- await expect(
146
- brbState.enable(true, meeting.sendSlotManager)
147
- ).to.be.rejectedWith(error);
144
+
145
+ const enablePromise = brbState.enable(true, meeting.sendSlotManager);
146
+ await expect(enablePromise).to.be.rejectedWith(error);
148
147
 
149
148
  assert.isFalse(brbState.state.syncToServerInProgress);
149
+ expect(meeting.sendSlotManager.setSourceStateOverride.called).to.be.false;
150
150
  });
151
151
  });
152
152
  });