@webex/plugin-meetings 3.1.0-next.5 → 3.1.0-next.6

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.
@@ -454,6 +454,7 @@ export default class Meeting extends StatelessWebexPlugin {
454
454
  private deferSDPAnswer?;
455
455
  private sdpResponseTimer?;
456
456
  private hasMediaConnectionConnectedAtLeastOnce;
457
+ private joinWithMediaRetryInfo?;
457
458
  /**
458
459
  * @param {Object} attrs
459
460
  * @param {Object} options
@@ -1078,10 +1079,7 @@ export default class Meeting extends StatelessWebexPlugin {
1078
1079
  joinWithMedia(options?: {
1079
1080
  joinOptions?: any;
1080
1081
  mediaOptions?: AddMediaOptions;
1081
- }): Promise<{
1082
- join: any;
1083
- media: void;
1084
- }>;
1082
+ }): any;
1085
1083
  /**
1086
1084
  * Initiates the reconnection of the media in the meeting
1087
1085
  *
@@ -62,7 +62,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
62
62
  updateCanManageWebcast: function updateCanManageWebcast(canManageWebcast) {
63
63
  this.set('canManageWebcast', canManageWebcast);
64
64
  },
65
- version: "3.1.0-next.5"
65
+ version: "3.1.0-next.6"
66
66
  });
67
67
  var _default = exports.default = Webinar;
68
68
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -43,7 +43,7 @@
43
43
  "@webex/eslint-config-legacy": "0.0.0",
44
44
  "@webex/jest-config-legacy": "0.0.0",
45
45
  "@webex/legacy-tools": "0.0.0",
46
- "@webex/plugin-meetings": "3.1.0-next.5",
46
+ "@webex/plugin-meetings": "3.1.0-next.6",
47
47
  "@webex/plugin-rooms": "3.0.0-next.16",
48
48
  "@webex/test-helper-chai": "3.0.0-next.14",
49
49
  "@webex/test-helper-mocha": "3.0.0-next.14",
@@ -70,7 +70,7 @@
70
70
  "@webex/internal-plugin-metrics": "3.0.0-next.14",
71
71
  "@webex/internal-plugin-support": "3.0.0-next.16",
72
72
  "@webex/internal-plugin-user": "3.0.0-next.14",
73
- "@webex/internal-plugin-voicea": "3.1.0-next.5",
73
+ "@webex/internal-plugin-voicea": "3.1.0-next.6",
74
74
  "@webex/media-helpers": "3.0.1-next.17",
75
75
  "@webex/plugin-people": "3.0.0-next.16",
76
76
  "@webex/plugin-rooms": "3.0.0-next.16",
@@ -91,5 +91,5 @@
91
91
  "//": [
92
92
  "TODO: upgrade jwt-decode when moving to node 18"
93
93
  ],
94
- "version": "3.1.0-next.5"
94
+ "version": "3.1.0-next.6"
95
95
  }
@@ -678,6 +678,7 @@ export default class Meeting extends StatelessWebexPlugin {
678
678
  private deferSDPAnswer?: Defer; // used for waiting for a response
679
679
  private sdpResponseTimer?: ReturnType<typeof setTimeout>;
680
680
  private hasMediaConnectionConnectedAtLeastOnce: boolean;
681
+ private joinWithMediaRetryInfo?: {isRetry: boolean; prevJoinResponse?: any};
681
682
 
682
683
  /**
683
684
  * @param {Object} attrs
@@ -1459,6 +1460,15 @@ export default class Meeting extends StatelessWebexPlugin {
1459
1460
  * @memberof Meeting
1460
1461
  */
1461
1462
  this.hasMediaConnectionConnectedAtLeastOnce = false;
1463
+
1464
+ /**
1465
+ * Information needed for a retry of a call to joinWithMedia
1466
+ * @instance
1467
+ * @type {{isRetry: boolean; prevJoinResponse?: any}}
1468
+ * @private
1469
+ * @memberof Meeting
1470
+ */
1471
+ this.joinWithMediaRetryInfo = {isRetry: false, prevJoinResponse: undefined};
1462
1472
  }
1463
1473
 
1464
1474
  /**
@@ -4527,6 +4537,7 @@ export default class Meeting extends StatelessWebexPlugin {
4527
4537
  } = {}
4528
4538
  ) {
4529
4539
  const {mediaOptions, joinOptions = {}} = options;
4540
+ const {isRetry, prevJoinResponse} = this.joinWithMediaRetryInfo;
4530
4541
 
4531
4542
  if (!mediaOptions?.allowMediaInLobby) {
4532
4543
  return Promise.reject(
@@ -4538,6 +4549,7 @@ export default class Meeting extends StatelessWebexPlugin {
4538
4549
  LoggerProxy.logger.info('Meeting:index#joinWithMedia called');
4539
4550
 
4540
4551
  let joined = false;
4552
+ let joinResponse = prevJoinResponse;
4541
4553
 
4542
4554
  try {
4543
4555
  let turnServerInfo;
@@ -4550,7 +4562,14 @@ export default class Meeting extends StatelessWebexPlugin {
4550
4562
  ({turnDiscoverySkippedReason} = turnDiscoveryRequest);
4551
4563
  joinOptions.roapMessage = turnDiscoveryRequest.roapMessage;
4552
4564
 
4553
- const joinResponse = await this.join(joinOptions);
4565
+ if (!joinResponse) {
4566
+ LoggerProxy.logger.info(
4567
+ 'Meeting:index#joinWithMedia ---> calling join with joinOptions, ',
4568
+ joinOptions
4569
+ );
4570
+
4571
+ joinResponse = await this.join(joinOptions);
4572
+ }
4554
4573
 
4555
4574
  joined = true;
4556
4575
 
@@ -4568,6 +4587,8 @@ export default class Meeting extends StatelessWebexPlugin {
4568
4587
 
4569
4588
  const mediaResponse = await this.addMedia(mediaOptions, turnServerInfo);
4570
4589
 
4590
+ this.joinWithMediaRetryInfo = {isRetry: false, prevJoinResponse: undefined};
4591
+
4571
4592
  return {
4572
4593
  join: joinResponse,
4573
4594
  media: mediaResponse,
@@ -4579,7 +4600,7 @@ export default class Meeting extends StatelessWebexPlugin {
4579
4600
 
4580
4601
  this.roap.abortTurnDiscovery();
4581
4602
 
4582
- if (joined) {
4603
+ if (joined && isRetry) {
4583
4604
  try {
4584
4605
  await this.leave({resourceId: joinOptions?.resourceId, reason: 'joinWithMedia failure'});
4585
4606
  } catch (e) {
@@ -4596,12 +4617,23 @@ export default class Meeting extends StatelessWebexPlugin {
4596
4617
  reason: error.message,
4597
4618
  stack: error.stack,
4598
4619
  leaveErrorReason: leaveError?.message,
4620
+ isRetry,
4599
4621
  },
4600
4622
  {
4601
4623
  type: error.name,
4602
4624
  }
4603
4625
  );
4604
4626
 
4627
+ if (!isRetry) {
4628
+ LoggerProxy.logger.warn('Meeting:index#joinWithMedia --> retrying call to joinWithMedia');
4629
+ this.joinWithMediaRetryInfo.isRetry = true;
4630
+ this.joinWithMediaRetryInfo.prevJoinResponse = joinResponse;
4631
+
4632
+ return this.joinWithMedia(options);
4633
+ }
4634
+
4635
+ this.joinWithMediaRetryInfo = {isRetry: false, prevJoinResponse: undefined};
4636
+
4605
4637
  throw error;
4606
4638
  }
4607
4639
  }
@@ -6790,6 +6822,7 @@ export default class Meeting extends StatelessWebexPlugin {
6790
6822
  connectionType,
6791
6823
  isMultistream: this.isMultistream,
6792
6824
  retriedWithTurnServer: this.retriedWithTurnServer,
6825
+ isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
6793
6826
  ...reachabilityStats,
6794
6827
  });
6795
6828
  // @ts-ignore
@@ -6821,6 +6854,7 @@ export default class Meeting extends StatelessWebexPlugin {
6821
6854
  turnServerUsed: this.turnServerUsed,
6822
6855
  retriedWithTurnServer: this.retriedWithTurnServer,
6823
6856
  isMultistream: this.isMultistream,
6857
+ isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
6824
6858
  signalingState:
6825
6859
  this.mediaProperties.webrtcMediaConnection?.multistreamConnection?.pc?.pc
6826
6860
  ?.signalingState ||
@@ -658,6 +658,9 @@ describe('plugin-meetings', () => {
658
658
  assert.calledOnceWithExactly(meeting.addMedia, mediaOptions, fakeTurnServerInfo);
659
659
 
660
660
  assert.deepEqual(result, {join: fakeJoinResult, media: test4});
661
+
662
+ // resets joinWithMediaRetryInfo
663
+ assert.deepEqual(meeting.joinWithMediaRetryInfo, {isRetry: false, prevJoinResponse: undefined});
661
664
  });
662
665
 
663
666
  it("should not call handleTurnDiscoveryHttpResponse if we don't send a TURN discovery request with join", async () => {
@@ -719,8 +722,9 @@ describe('plugin-meetings', () => {
719
722
 
720
723
  await assert.isRejected(meeting.joinWithMedia({mediaOptions: {allowMediaInLobby: true}}));
721
724
 
722
- assert.calledOnceWithExactly(abortTurnDiscoveryStub);
725
+ assert.calledTwice(abortTurnDiscoveryStub);
723
726
 
727
+ assert.calledTwice(Metrics.sendBehavioralMetric);
724
728
  assert.calledWith(
725
729
  Metrics.sendBehavioralMetric,
726
730
  BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
@@ -730,11 +734,67 @@ describe('plugin-meetings', () => {
730
734
  reason: error.message,
731
735
  stack: error.stack,
732
736
  leaveErrorReason: undefined,
737
+ isRetry: false,
733
738
  },
734
739
  {
735
740
  type: error.name,
736
741
  }
737
742
  );
743
+ assert.calledWith(
744
+ Metrics.sendBehavioralMetric,
745
+ BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
746
+ {
747
+ correlation_id: meeting.correlationId,
748
+ locus_id: undefined,
749
+ reason: error.message,
750
+ stack: error.stack,
751
+ leaveErrorReason: undefined,
752
+ isRetry: true,
753
+ },
754
+ {
755
+ type: error.name,
756
+ }
757
+ );
758
+
759
+ // resets joinWithMediaRetryInfo
760
+ assert.deepEqual(meeting.joinWithMediaRetryInfo, {isRetry: false, prevJoinResponse: undefined});
761
+ });
762
+
763
+ it('should resolve if join() fails the first time but succeeds the second time', async () => {
764
+ const error = new Error('fake');
765
+ meeting.join = sinon.stub().onFirstCall().returns(Promise.reject(error)).onSecondCall().returns(Promise.resolve(fakeJoinResult));
766
+ const leaveStub = sinon.stub(meeting, 'leave').resolves();
767
+
768
+ const result = await meeting.joinWithMedia({
769
+ joinOptions,
770
+ mediaOptions,
771
+ });
772
+
773
+ assert.calledOnce(abortTurnDiscoveryStub);
774
+ assert.calledTwice(meeting.join);
775
+ assert.notCalled(leaveStub);
776
+
777
+ assert.calledOnce(Metrics.sendBehavioralMetric);
778
+ assert.calledWith(
779
+ Metrics.sendBehavioralMetric.firstCall,
780
+ BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
781
+ {
782
+ correlation_id: meeting.correlationId,
783
+ locus_id: meeting.locusUrl.split('/').pop(),
784
+ reason: error.message,
785
+ stack: error.stack,
786
+ leaveErrorReason: undefined,
787
+ isRetry: false,
788
+ },
789
+ {
790
+ type: error.name,
791
+ }
792
+ );
793
+
794
+ assert.deepEqual(result, {join: fakeJoinResult, media: test4});
795
+
796
+ // resets joinWithMediaRetryInfo
797
+ assert.deepEqual(meeting.joinWithMediaRetryInfo, {isRetry: false, prevJoinResponse: undefined});
738
798
  });
739
799
 
740
800
  it('should fail if called with allowMediaInLobby:false', async () => {
@@ -767,8 +827,26 @@ describe('plugin-meetings', () => {
767
827
  reason: 'joinWithMedia failure',
768
828
  });
769
829
 
830
+
831
+ // Behavioral metric is sent on both calls of joinWithMedia
832
+ assert.calledTwice(Metrics.sendBehavioralMetric);
770
833
  assert.calledWith(
771
- Metrics.sendBehavioralMetric,
834
+ Metrics.sendBehavioralMetric.firstCall,
835
+ BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
836
+ {
837
+ correlation_id: meeting.correlationId,
838
+ locus_id: meeting.locusUrl.split('/').pop(),
839
+ reason: addMediaError.message,
840
+ stack: addMediaError.stack,
841
+ leaveErrorReason: undefined,
842
+ isRetry: false,
843
+ },
844
+ {
845
+ type: addMediaError.name,
846
+ }
847
+ );
848
+ assert.calledWith(
849
+ Metrics.sendBehavioralMetric.secondCall,
772
850
  BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
773
851
  {
774
852
  correlation_id: meeting.correlationId,
@@ -776,6 +854,47 @@ describe('plugin-meetings', () => {
776
854
  reason: addMediaError.message,
777
855
  stack: addMediaError.stack,
778
856
  leaveErrorReason: leaveError.message,
857
+ isRetry: true,
858
+ },
859
+ {
860
+ type: addMediaError.name,
861
+ }
862
+ );
863
+ });
864
+
865
+ it('should not call leave() if addMedia fails the first time and succeeds the second time and should only call join() once', async () => {
866
+ const addMediaError = new Error('fake addMedia error');
867
+ const leaveError = new Error('leave error');
868
+ const leaveStub = sinon.stub(meeting, 'leave').rejects(leaveError);
869
+
870
+ meeting.addMedia = sinon
871
+ .stub()
872
+ .onFirstCall()
873
+ .rejects(addMediaError)
874
+ .onSecondCall()
875
+ .resolves(test4);
876
+
877
+ const result = await meeting.joinWithMedia({
878
+ joinOptions,
879
+ mediaOptions,
880
+ });
881
+
882
+ assert.deepEqual(result, {join: fakeJoinResult, media: test4});
883
+
884
+ assert.calledOnce(meeting.join);
885
+ assert.notCalled(leaveStub);
886
+
887
+ assert.calledOnce(Metrics.sendBehavioralMetric);
888
+ assert.calledWith(
889
+ Metrics.sendBehavioralMetric.firstCall,
890
+ BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
891
+ {
892
+ correlation_id: meeting.correlationId,
893
+ locus_id: meeting.locusUrl.split('/').pop(),
894
+ reason: addMediaError.message,
895
+ stack: addMediaError.stack,
896
+ leaveErrorReason: undefined,
897
+ isRetry: false,
779
898
  },
780
899
  {
781
900
  type: addMediaError.name,
@@ -1630,6 +1749,7 @@ describe('plugin-meetings', () => {
1630
1749
  turnServerUsed: true,
1631
1750
  retriedWithTurnServer: false,
1632
1751
  isMultistream: false,
1752
+ isJoinWithMediaRetry: false,
1633
1753
  signalingState: 'unknown',
1634
1754
  connectionState: 'unknown',
1635
1755
  iceConnectionState: 'unknown',
@@ -1734,6 +1854,7 @@ describe('plugin-meetings', () => {
1734
1854
  turnServerUsed: true,
1735
1855
  retriedWithTurnServer: false,
1736
1856
  isMultistream: false,
1857
+ isJoinWithMediaRetry: false,
1737
1858
  signalingState: 'unknown',
1738
1859
  connectionState: 'unknown',
1739
1860
  iceConnectionState: 'unknown',
@@ -2212,6 +2333,7 @@ describe('plugin-meetings', () => {
2212
2333
  turnServerUsed: true,
2213
2334
  retriedWithTurnServer: true,
2214
2335
  isMultistream: false,
2336
+ isJoinWithMediaRetry: false,
2215
2337
  signalingState: 'unknown',
2216
2338
  connectionState: 'unknown',
2217
2339
  iceConnectionState: 'unknown',
@@ -2395,6 +2517,7 @@ describe('plugin-meetings', () => {
2395
2517
  connectionType: 'udp',
2396
2518
  isMultistream: false,
2397
2519
  retriedWithTurnServer: true,
2520
+ isJoinWithMediaRetry: false,
2398
2521
  },
2399
2522
  ]);
2400
2523
  meeting.roap.doTurnDiscovery;
@@ -2537,6 +2660,7 @@ describe('plugin-meetings', () => {
2537
2660
  connectionType: 'udp',
2538
2661
  isMultistream: false,
2539
2662
  retriedWithTurnServer: false,
2663
+ isJoinWithMediaRetry: false,
2540
2664
  someReachabilityMetric1: 'some value1',
2541
2665
  someReachabilityMetric2: 'some value2',
2542
2666
  }
@@ -2595,6 +2719,7 @@ describe('plugin-meetings', () => {
2595
2719
  turnServerUsed: true,
2596
2720
  retriedWithTurnServer: false,
2597
2721
  isMultistream: false,
2722
+ isJoinWithMediaRetry: false,
2598
2723
  signalingState: 'unknown',
2599
2724
  connectionState: 'unknown',
2600
2725
  iceConnectionState: 'unknown',