@webex/plugin-meetings 3.1.0 → 3.3.0

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 (206) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/common/errors/{reconnection-in-progress.js → reconnection-not-started.js} +27 -15
  4. package/dist/common/errors/reconnection-not-started.js.map +1 -0
  5. package/dist/constants.js +12 -3
  6. package/dist/constants.js.map +1 -1
  7. package/dist/index.js +80 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/interpretation/index.js +1 -1
  10. package/dist/interpretation/siLanguage.js +1 -1
  11. package/dist/locus-info/controlsUtils.js +7 -1
  12. package/dist/locus-info/controlsUtils.js.map +1 -1
  13. package/dist/locus-info/index.js +10 -0
  14. package/dist/locus-info/index.js.map +1 -1
  15. package/dist/media/properties.js +102 -57
  16. package/dist/media/properties.js.map +1 -1
  17. package/dist/meeting/in-meeting-actions.js +6 -0
  18. package/dist/meeting/in-meeting-actions.js.map +1 -1
  19. package/dist/meeting/index.js +543 -467
  20. package/dist/meeting/index.js.map +1 -1
  21. package/dist/meeting/locusMediaRequest.js +27 -0
  22. package/dist/meeting/locusMediaRequest.js.map +1 -1
  23. package/dist/meeting/util.js +9 -16
  24. package/dist/meeting/util.js.map +1 -1
  25. package/dist/meeting/voicea-meeting.js +37 -49
  26. package/dist/meeting/voicea-meeting.js.map +1 -1
  27. package/dist/meeting-info/util.js +304 -267
  28. package/dist/meeting-info/util.js.map +1 -1
  29. package/dist/meeting-info/utilv2.js +334 -298
  30. package/dist/meeting-info/utilv2.js.map +1 -1
  31. package/dist/meetings/index.js +6 -27
  32. package/dist/meetings/index.js.map +1 -1
  33. package/dist/reachability/index.js +6 -0
  34. package/dist/reachability/index.js.map +1 -1
  35. package/dist/reconnection-manager/index.js +138 -109
  36. package/dist/reconnection-manager/index.js.map +1 -1
  37. package/dist/roap/request.js +3 -27
  38. package/dist/roap/request.js.map +1 -1
  39. package/dist/statsAnalyzer/index.js +4 -0
  40. package/dist/statsAnalyzer/index.js.map +1 -1
  41. package/dist/statsAnalyzer/mqaUtil.js +3 -0
  42. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  43. package/dist/types/common/errors/reconnection-not-started.d.ts +13 -0
  44. package/dist/{constants.d.ts → types/constants.d.ts} +11 -2
  45. package/dist/types/index.d.ts +19 -0
  46. package/dist/{media → types/media}/properties.d.ts +26 -2
  47. package/dist/{meeting → types/meeting}/in-meeting-actions.d.ts +6 -0
  48. package/dist/{meeting → types/meeting}/index.d.ts +5 -6
  49. package/dist/{meeting → types/meeting}/locusMediaRequest.d.ts +1 -0
  50. package/dist/{meeting → types/meeting}/util.d.ts +3 -0
  51. package/dist/{meeting → types/meeting}/voicea-meeting.d.ts +3 -2
  52. package/dist/{meeting-info → types/meeting-info}/index.d.ts +1 -1
  53. package/dist/{meeting-info → types/meeting-info}/meeting-info-v2.d.ts +1 -1
  54. package/dist/types/meeting-info/util.d.ts +49 -0
  55. package/dist/types/meeting-info/utilv2.d.ts +65 -0
  56. package/dist/{meetings → types/meetings}/index.d.ts +1 -16
  57. package/dist/{reconnection-manager → types/reconnection-manager}/index.d.ts +4 -14
  58. package/dist/webinar/index.js +1 -1
  59. package/package.json +22 -22
  60. package/src/common/errors/reconnection-not-started.ts +25 -0
  61. package/src/constants.ts +12 -4
  62. package/src/index.ts +30 -0
  63. package/src/locus-info/controlsUtils.ts +11 -0
  64. package/src/locus-info/index.ts +16 -0
  65. package/src/media/properties.ts +67 -15
  66. package/src/meeting/in-meeting-actions.ts +12 -0
  67. package/src/meeting/index.ts +121 -98
  68. package/src/meeting/locusMediaRequest.ts +31 -0
  69. package/src/meeting/util.ts +9 -16
  70. package/src/meeting/voicea-meeting.ts +44 -46
  71. package/src/meeting-info/util.ts +241 -233
  72. package/src/meeting-info/utilv2.ts +250 -244
  73. package/src/meetings/index.ts +8 -25
  74. package/src/reachability/index.ts +3 -0
  75. package/src/reconnection-manager/index.ts +128 -105
  76. package/src/roap/request.ts +1 -24
  77. package/src/statsAnalyzer/index.ts +4 -0
  78. package/src/statsAnalyzer/mqaUtil.ts +5 -0
  79. package/test/unit/spec/locus-info/controlsUtils.js +20 -0
  80. package/test/unit/spec/locus-info/index.js +21 -0
  81. package/test/unit/spec/media/properties.ts +145 -140
  82. package/test/unit/spec/meeting/in-meeting-actions.ts +6 -0
  83. package/test/unit/spec/meeting/index.js +243 -97
  84. package/test/unit/spec/meeting/locusMediaRequest.ts +49 -0
  85. package/test/unit/spec/meeting/utils.js +3 -10
  86. package/test/unit/spec/meeting/voicea-meeting.ts +5 -14
  87. package/test/unit/spec/meetings/index.js +27 -8
  88. package/test/unit/spec/reconnection-manager/index.js +127 -39
  89. package/test/unit/spec/roap/request.ts +0 -37
  90. package/test/unit/spec/stats-analyzer/index.js +11 -0
  91. package/dist/common/errors/reconnection-in-progress.d.ts +0 -9
  92. package/dist/common/errors/reconnection-in-progress.js.map +0 -1
  93. package/dist/index.d.ts +0 -7
  94. package/dist/meeting-info/util.d.ts +0 -2
  95. package/dist/meeting-info/utilv2.d.ts +0 -2
  96. package/src/common/errors/reconnection-in-progress.ts +0 -8
  97. /package/dist/{annotation → types/annotation}/annotation.types.d.ts +0 -0
  98. /package/dist/{annotation → types/annotation}/constants.d.ts +0 -0
  99. /package/dist/{annotation → types/annotation}/index.d.ts +0 -0
  100. /package/dist/{breakouts → types/breakouts}/breakout.d.ts +0 -0
  101. /package/dist/{breakouts → types/breakouts}/collection.d.ts +0 -0
  102. /package/dist/{breakouts → types/breakouts}/edit-lock-error.d.ts +0 -0
  103. /package/dist/{breakouts → types/breakouts}/events.d.ts +0 -0
  104. /package/dist/{breakouts → types/breakouts}/index.d.ts +0 -0
  105. /package/dist/{breakouts → types/breakouts}/request.d.ts +0 -0
  106. /package/dist/{breakouts → types/breakouts}/utils.d.ts +0 -0
  107. /package/dist/{common → types/common}/browser-detection.d.ts +0 -0
  108. /package/dist/{common → types/common}/collection.d.ts +0 -0
  109. /package/dist/{common → types/common}/config.d.ts +0 -0
  110. /package/dist/{common → types/common}/errors/captcha-error.d.ts +0 -0
  111. /package/dist/{common → types/common}/errors/intent-to-join.d.ts +0 -0
  112. /package/dist/{common → types/common}/errors/join-meeting.d.ts +0 -0
  113. /package/dist/{common → types/common}/errors/media.d.ts +0 -0
  114. /package/dist/{common → types/common}/errors/no-meeting-info.d.ts +0 -0
  115. /package/dist/{common → types/common}/errors/parameter.d.ts +0 -0
  116. /package/dist/{common → types/common}/errors/password-error.d.ts +0 -0
  117. /package/dist/{common → types/common}/errors/permission.d.ts +0 -0
  118. /package/dist/{common → types/common}/errors/reclaim-host-role-errors.d.ts +0 -0
  119. /package/dist/{common → types/common}/errors/reconnection.d.ts +0 -0
  120. /package/dist/{common → types/common}/errors/stats.d.ts +0 -0
  121. /package/dist/{common → types/common}/errors/webex-errors.d.ts +0 -0
  122. /package/dist/{common → types/common}/errors/webex-meetings-error.d.ts +0 -0
  123. /package/dist/{common → types/common}/events/events-scope.d.ts +0 -0
  124. /package/dist/{common → types/common}/events/events.d.ts +0 -0
  125. /package/dist/{common → types/common}/events/trigger-proxy.d.ts +0 -0
  126. /package/dist/{common → types/common}/events/util.d.ts +0 -0
  127. /package/dist/{common → types/common}/logs/logger-config.d.ts +0 -0
  128. /package/dist/{common → types/common}/logs/logger-proxy.d.ts +0 -0
  129. /package/dist/{common → types/common}/logs/request.d.ts +0 -0
  130. /package/dist/{common → types/common}/queue.d.ts +0 -0
  131. /package/dist/{config.d.ts → types/config.d.ts} +0 -0
  132. /package/dist/{controls-options-manager → types/controls-options-manager}/constants.d.ts +0 -0
  133. /package/dist/{controls-options-manager → types/controls-options-manager}/enums.d.ts +0 -0
  134. /package/dist/{controls-options-manager → types/controls-options-manager}/index.d.ts +0 -0
  135. /package/dist/{controls-options-manager → types/controls-options-manager}/types.d.ts +0 -0
  136. /package/dist/{controls-options-manager → types/controls-options-manager}/util.d.ts +0 -0
  137. /package/dist/{interceptors → types/interceptors}/index.d.ts +0 -0
  138. /package/dist/{interceptors → types/interceptors}/locusRetry.d.ts +0 -0
  139. /package/dist/{interpretation → types/interpretation}/collection.d.ts +0 -0
  140. /package/dist/{interpretation → types/interpretation}/index.d.ts +0 -0
  141. /package/dist/{interpretation → types/interpretation}/siLanguage.d.ts +0 -0
  142. /package/dist/{locus-info → types/locus-info}/controlsUtils.d.ts +0 -0
  143. /package/dist/{locus-info → types/locus-info}/embeddedAppsUtils.d.ts +0 -0
  144. /package/dist/{locus-info → types/locus-info}/fullState.d.ts +0 -0
  145. /package/dist/{locus-info → types/locus-info}/hostUtils.d.ts +0 -0
  146. /package/dist/{locus-info → types/locus-info}/index.d.ts +0 -0
  147. /package/dist/{locus-info → types/locus-info}/infoUtils.d.ts +0 -0
  148. /package/dist/{locus-info → types/locus-info}/mediaSharesUtils.d.ts +0 -0
  149. /package/dist/{locus-info → types/locus-info}/parser.d.ts +0 -0
  150. /package/dist/{locus-info → types/locus-info}/selfUtils.d.ts +0 -0
  151. /package/dist/{media → types/media}/MediaConnectionAwaiter.d.ts +0 -0
  152. /package/dist/{media → types/media}/index.d.ts +0 -0
  153. /package/dist/{media → types/media}/util.d.ts +0 -0
  154. /package/dist/{mediaQualityMetrics → types/mediaQualityMetrics}/config.d.ts +0 -0
  155. /package/dist/{meeting → types/meeting}/muteState.d.ts +0 -0
  156. /package/dist/{meeting → types/meeting}/request.d.ts +0 -0
  157. /package/dist/{meeting → types/meeting}/request.type.d.ts +0 -0
  158. /package/dist/{meeting → types/meeting}/state.d.ts +0 -0
  159. /package/dist/{meeting-info → types/meeting-info}/collection.d.ts +0 -0
  160. /package/dist/{meeting-info → types/meeting-info}/request.d.ts +0 -0
  161. /package/dist/{meetings → types/meetings}/collection.d.ts +0 -0
  162. /package/dist/{meetings → types/meetings}/meetings.types.d.ts +0 -0
  163. /package/dist/{meetings → types/meetings}/request.d.ts +0 -0
  164. /package/dist/{meetings → types/meetings}/util.d.ts +0 -0
  165. /package/dist/{member → types/member}/index.d.ts +0 -0
  166. /package/dist/{member → types/member}/types.d.ts +0 -0
  167. /package/dist/{member → types/member}/util.d.ts +0 -0
  168. /package/dist/{members → types/members}/collection.d.ts +0 -0
  169. /package/dist/{members → types/members}/index.d.ts +0 -0
  170. /package/dist/{members → types/members}/request.d.ts +0 -0
  171. /package/dist/{members → types/members}/types.d.ts +0 -0
  172. /package/dist/{members → types/members}/util.d.ts +0 -0
  173. /package/dist/{metrics → types/metrics}/constants.d.ts +0 -0
  174. /package/dist/{metrics → types/metrics}/index.d.ts +0 -0
  175. /package/dist/{multistream → types/multistream}/mediaRequestManager.d.ts +0 -0
  176. /package/dist/{multistream → types/multistream}/receiveSlot.d.ts +0 -0
  177. /package/dist/{multistream → types/multistream}/receiveSlotManager.d.ts +0 -0
  178. /package/dist/{multistream → types/multistream}/remoteMedia.d.ts +0 -0
  179. /package/dist/{multistream → types/multistream}/remoteMediaGroup.d.ts +0 -0
  180. /package/dist/{multistream → types/multistream}/remoteMediaManager.d.ts +0 -0
  181. /package/dist/{multistream → types/multistream}/sendSlotManager.d.ts +0 -0
  182. /package/dist/{networkQualityMonitor → types/networkQualityMonitor}/index.d.ts +0 -0
  183. /package/dist/{personal-meeting-room → types/personal-meeting-room}/index.d.ts +0 -0
  184. /package/dist/{personal-meeting-room → types/personal-meeting-room}/request.d.ts +0 -0
  185. /package/dist/{personal-meeting-room → types/personal-meeting-room}/util.d.ts +0 -0
  186. /package/dist/{reachability → types/reachability}/clusterReachability.d.ts +0 -0
  187. /package/dist/{reachability → types/reachability}/index.d.ts +0 -0
  188. /package/dist/{reachability → types/reachability}/request.d.ts +0 -0
  189. /package/dist/{reachability → types/reachability}/util.d.ts +0 -0
  190. /package/dist/{reactions → types/reactions}/constants.d.ts +0 -0
  191. /package/dist/{reactions → types/reactions}/reactions.d.ts +0 -0
  192. /package/dist/{reactions → types/reactions}/reactions.type.d.ts +0 -0
  193. /package/dist/{recording-controller → types/recording-controller}/enums.d.ts +0 -0
  194. /package/dist/{recording-controller → types/recording-controller}/index.d.ts +0 -0
  195. /package/dist/{recording-controller → types/recording-controller}/util.d.ts +0 -0
  196. /package/dist/{roap → types/roap}/index.d.ts +0 -0
  197. /package/dist/{roap → types/roap}/request.d.ts +0 -0
  198. /package/dist/{roap → types/roap}/turnDiscovery.d.ts +0 -0
  199. /package/dist/{rtcMetrics → types/rtcMetrics}/constants.d.ts +0 -0
  200. /package/dist/{rtcMetrics → types/rtcMetrics}/index.d.ts +0 -0
  201. /package/dist/{statsAnalyzer → types/statsAnalyzer}/global.d.ts +0 -0
  202. /package/dist/{statsAnalyzer → types/statsAnalyzer}/index.d.ts +0 -0
  203. /package/dist/{statsAnalyzer → types/statsAnalyzer}/mqaUtil.d.ts +0 -0
  204. /package/dist/{transcription → types/transcription}/index.d.ts +0 -0
  205. /package/dist/{webinar → types/webinar}/collection.d.ts +0 -0
  206. /package/dist/{webinar → types/webinar}/index.d.ts +0 -0
@@ -12,6 +12,7 @@ import {Credentials, Token, WebexPlugin} from '@webex/webex-core';
12
12
  import Support from '@webex/internal-plugin-support';
13
13
  import MockWebex from '@webex/test-helper-mock-webex';
14
14
  import StaticConfig from '@webex/plugin-meetings/src/common/config';
15
+ import ReconnectionNotStartedError from '@webex/plugin-meetings/src/common/errors/reconnection-not-started';
15
16
  import {Defer} from '@webex/common';
16
17
  import {
17
18
  FLOOR_ACTION,
@@ -658,6 +659,9 @@ describe('plugin-meetings', () => {
658
659
  assert.calledOnceWithExactly(meeting.addMedia, mediaOptions, fakeTurnServerInfo);
659
660
 
660
661
  assert.deepEqual(result, {join: fakeJoinResult, media: test4});
662
+
663
+ // resets joinWithMediaRetryInfo
664
+ assert.deepEqual(meeting.joinWithMediaRetryInfo, {isRetry: false, prevJoinResponse: undefined});
661
665
  });
662
666
 
663
667
  it("should not call handleTurnDiscoveryHttpResponse if we don't send a TURN discovery request with join", async () => {
@@ -719,8 +723,24 @@ describe('plugin-meetings', () => {
719
723
 
720
724
  await assert.isRejected(meeting.joinWithMedia({mediaOptions: {allowMediaInLobby: true}}));
721
725
 
722
- assert.calledOnceWithExactly(abortTurnDiscoveryStub);
726
+ assert.calledTwice(abortTurnDiscoveryStub);
723
727
 
728
+ assert.calledTwice(Metrics.sendBehavioralMetric);
729
+ assert.calledWith(
730
+ Metrics.sendBehavioralMetric,
731
+ BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
732
+ {
733
+ correlation_id: meeting.correlationId,
734
+ locus_id: undefined,
735
+ reason: error.message,
736
+ stack: error.stack,
737
+ leaveErrorReason: undefined,
738
+ isRetry: false,
739
+ },
740
+ {
741
+ type: error.name,
742
+ }
743
+ );
724
744
  assert.calledWith(
725
745
  Metrics.sendBehavioralMetric,
726
746
  BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
@@ -730,11 +750,52 @@ describe('plugin-meetings', () => {
730
750
  reason: error.message,
731
751
  stack: error.stack,
732
752
  leaveErrorReason: undefined,
753
+ isRetry: true,
733
754
  },
734
755
  {
735
756
  type: error.name,
736
757
  }
737
758
  );
759
+
760
+ // resets joinWithMediaRetryInfo
761
+ assert.deepEqual(meeting.joinWithMediaRetryInfo, {isRetry: false, prevJoinResponse: undefined});
762
+ });
763
+
764
+ it('should resolve if join() fails the first time but succeeds the second time', async () => {
765
+ const error = new Error('fake');
766
+ meeting.join = sinon.stub().onFirstCall().returns(Promise.reject(error)).onSecondCall().returns(Promise.resolve(fakeJoinResult));
767
+ const leaveStub = sinon.stub(meeting, 'leave').resolves();
768
+
769
+ const result = await meeting.joinWithMedia({
770
+ joinOptions,
771
+ mediaOptions,
772
+ });
773
+
774
+ assert.calledOnce(abortTurnDiscoveryStub);
775
+ assert.calledTwice(meeting.join);
776
+ assert.notCalled(leaveStub);
777
+
778
+ assert.calledOnce(Metrics.sendBehavioralMetric);
779
+ assert.calledWith(
780
+ Metrics.sendBehavioralMetric.firstCall,
781
+ BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
782
+ {
783
+ correlation_id: meeting.correlationId,
784
+ locus_id: meeting.locusUrl.split('/').pop(),
785
+ reason: error.message,
786
+ stack: error.stack,
787
+ leaveErrorReason: undefined,
788
+ isRetry: false,
789
+ },
790
+ {
791
+ type: error.name,
792
+ }
793
+ );
794
+
795
+ assert.deepEqual(result, {join: fakeJoinResult, media: test4});
796
+
797
+ // resets joinWithMediaRetryInfo
798
+ assert.deepEqual(meeting.joinWithMediaRetryInfo, {isRetry: false, prevJoinResponse: undefined});
738
799
  });
739
800
 
740
801
  it('should fail if called with allowMediaInLobby:false', async () => {
@@ -767,8 +828,26 @@ describe('plugin-meetings', () => {
767
828
  reason: 'joinWithMedia failure',
768
829
  });
769
830
 
831
+
832
+ // Behavioral metric is sent on both calls of joinWithMedia
833
+ assert.calledTwice(Metrics.sendBehavioralMetric);
770
834
  assert.calledWith(
771
- Metrics.sendBehavioralMetric,
835
+ Metrics.sendBehavioralMetric.firstCall,
836
+ BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
837
+ {
838
+ correlation_id: meeting.correlationId,
839
+ locus_id: meeting.locusUrl.split('/').pop(),
840
+ reason: addMediaError.message,
841
+ stack: addMediaError.stack,
842
+ leaveErrorReason: undefined,
843
+ isRetry: false,
844
+ },
845
+ {
846
+ type: addMediaError.name,
847
+ }
848
+ );
849
+ assert.calledWith(
850
+ Metrics.sendBehavioralMetric.secondCall,
772
851
  BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
773
852
  {
774
853
  correlation_id: meeting.correlationId,
@@ -776,6 +855,47 @@ describe('plugin-meetings', () => {
776
855
  reason: addMediaError.message,
777
856
  stack: addMediaError.stack,
778
857
  leaveErrorReason: leaveError.message,
858
+ isRetry: true,
859
+ },
860
+ {
861
+ type: addMediaError.name,
862
+ }
863
+ );
864
+ });
865
+
866
+ it('should not call leave() if addMedia fails the first time and succeeds the second time and should only call join() once', async () => {
867
+ const addMediaError = new Error('fake addMedia error');
868
+ const leaveError = new Error('leave error');
869
+ const leaveStub = sinon.stub(meeting, 'leave').rejects(leaveError);
870
+
871
+ meeting.addMedia = sinon
872
+ .stub()
873
+ .onFirstCall()
874
+ .rejects(addMediaError)
875
+ .onSecondCall()
876
+ .resolves(test4);
877
+
878
+ const result = await meeting.joinWithMedia({
879
+ joinOptions,
880
+ mediaOptions,
881
+ });
882
+
883
+ assert.deepEqual(result, {join: fakeJoinResult, media: test4});
884
+
885
+ assert.calledOnce(meeting.join);
886
+ assert.notCalled(leaveStub);
887
+
888
+ assert.calledOnce(Metrics.sendBehavioralMetric);
889
+ assert.calledWith(
890
+ Metrics.sendBehavioralMetric.firstCall,
891
+ BEHAVIORAL_METRICS.JOIN_WITH_MEDIA_FAILURE,
892
+ {
893
+ correlation_id: meeting.correlationId,
894
+ locus_id: meeting.locusUrl.split('/').pop(),
895
+ reason: addMediaError.message,
896
+ stack: addMediaError.stack,
897
+ leaveErrorReason: undefined,
898
+ isRetry: false,
779
899
  },
780
900
  {
781
901
  type: addMediaError.name,
@@ -786,12 +906,12 @@ describe('plugin-meetings', () => {
786
906
 
787
907
  describe('#isTranscriptionSupported', () => {
788
908
  it('should return false if the feature is not supported for the meeting', () => {
789
- meeting.locusInfo.controls = {transcribe: {transcribing: false}};
909
+ meeting.locusInfo.controls = {transcribe: {caption: false}};
790
910
 
791
911
  assert.equal(meeting.isTranscriptionSupported(), false);
792
912
  });
793
913
  it('should return true if webex assitant is enabled', () => {
794
- meeting.locusInfo.controls = {transcribe: {transcribing: true}};
914
+ meeting.locusInfo.controls = {transcribe: {caption: true}};
795
915
 
796
916
  assert.equal(meeting.isTranscriptionSupported(), true);
797
917
  });
@@ -802,7 +922,7 @@ describe('plugin-meetings', () => {
802
922
  webex.internal.voicea.on = sinon.stub();
803
923
  webex.internal.voicea.off = sinon.stub();
804
924
  webex.internal.voicea.listenToEvents = sinon.stub();
805
- webex.internal.voicea.toggleTranscribing = sinon.stub();
925
+ webex.internal.voicea.turnOnCaptions = sinon.stub();
806
926
  });
807
927
 
808
928
  it('should subscribe to events for the first time and avoid subscribing for future transcription starts', async () => {
@@ -817,17 +937,16 @@ describe('plugin-meetings', () => {
817
937
  assert.equal(webex.internal.voicea.on.callCount, 4);
818
938
  assert.equal(meeting.areVoiceaEventsSetup, true);
819
939
  assert.equal(webex.internal.voicea.listenToEvents.callCount, 1);
820
- assert.calledWith(webex.internal.voicea.toggleTranscribing, true);
940
+ assert.called(webex.internal.voicea.turnOnCaptions);
821
941
 
822
942
  await meeting.startTranscription();
823
943
  assert.equal(webex.internal.voicea.on.callCount, 4);
824
944
  assert.equal(meeting.areVoiceaEventsSetup, true);
825
945
  assert.equal(webex.internal.voicea.listenToEvents.callCount, 1);
826
- assert.calledTwice(webex.internal.voicea.toggleTranscribing);
827
- assert.calledWith(webex.internal.voicea.toggleTranscribing, true);
946
+ assert.calledTwice(webex.internal.voicea.turnOnCaptions);
828
947
  });
829
948
 
830
- it('should listen to events and not toggleTranscribing if the user is not a host', async () => {
949
+ it('should listen to events and not turnOnCaptions if the user is not a host', async () => {
831
950
  meeting.joinedWith = {
832
951
  state: 'JOINED',
833
952
  };
@@ -839,7 +958,7 @@ describe('plugin-meetings', () => {
839
958
  assert.equal(webex.internal.voicea.on.callCount, 4);
840
959
  assert.equal(meeting.areVoiceaEventsSetup, true);
841
960
  assert.equal(webex.internal.voicea.listenToEvents.callCount, 1);
842
- assert.notCalled(webex.internal.voicea.toggleTranscribing);
961
+ assert.notCalled(webex.internal.voicea.turnOnCaptions);
843
962
  });
844
963
 
845
964
  it("should throw error if request doesn't work", async () => {
@@ -858,7 +977,7 @@ describe('plugin-meetings', () => {
858
977
  webex.internal.voicea.on = sinon.stub();
859
978
  webex.internal.voicea.off = sinon.stub();
860
979
  webex.internal.voicea.listenToEvents = sinon.stub();
861
- webex.internal.voicea.toggleTranscribing = sinon.stub();
980
+ webex.internal.voicea.turnOnCaptions = sinon.stub();
862
981
  });
863
982
 
864
983
  it('should stop listening to voicea events and also trigger a stop event', () => {
@@ -1531,7 +1650,7 @@ describe('plugin-meetings', () => {
1531
1650
  };
1532
1651
  meeting.mediaProperties.setMediaDirection = sinon.stub().returns(true);
1533
1652
  meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
1534
- meeting.mediaProperties.getCurrentConnectionType = sinon.stub().resolves('udp');
1653
+ meeting.mediaProperties.getCurrentConnectionInfo = sinon.stub().resolves({connectionType: 'udp', selectedCandidatePairChanges: 2, numTransports: 1});
1535
1654
  meeting.audio = muteStateStub;
1536
1655
  meeting.video = muteStateStub;
1537
1656
  sinon.stub(Media, 'createMediaConnection').returns(fakeMediaConnection);
@@ -1631,11 +1750,14 @@ describe('plugin-meetings', () => {
1631
1750
  turnServerUsed: true,
1632
1751
  retriedWithTurnServer: false,
1633
1752
  isMultistream: false,
1753
+ isJoinWithMediaRetry: false,
1634
1754
  signalingState: 'unknown',
1635
1755
  connectionState: 'unknown',
1636
1756
  iceConnectionState: 'unknown',
1637
1757
  someReachabilityMetric1: 'some value1',
1638
1758
  someReachabilityMetric2: 'some value2',
1759
+ selectedCandidatePairChanges: 2,
1760
+ numTransports: 1,
1639
1761
  }
1640
1762
  );
1641
1763
  });
@@ -1735,11 +1857,14 @@ describe('plugin-meetings', () => {
1735
1857
  turnServerUsed: true,
1736
1858
  retriedWithTurnServer: false,
1737
1859
  isMultistream: false,
1860
+ isJoinWithMediaRetry: false,
1738
1861
  signalingState: 'unknown',
1739
1862
  connectionState: 'unknown',
1740
1863
  iceConnectionState: 'unknown',
1741
1864
  someReachabilityMetric1: 'some value1',
1742
1865
  someReachabilityMetric2: 'some value2',
1866
+ selectedCandidatePairChanges: 2,
1867
+ numTransports: 1,
1743
1868
  }
1744
1869
  );
1745
1870
  });
@@ -2213,9 +2338,12 @@ describe('plugin-meetings', () => {
2213
2338
  turnServerUsed: true,
2214
2339
  retriedWithTurnServer: true,
2215
2340
  isMultistream: false,
2341
+ isJoinWithMediaRetry: false,
2216
2342
  signalingState: 'unknown',
2217
2343
  connectionState: 'unknown',
2218
2344
  iceConnectionState: 'unknown',
2345
+ selectedCandidatePairChanges: 2,
2346
+ numTransports: 1,
2219
2347
  },
2220
2348
  ]);
2221
2349
 
@@ -2394,8 +2522,11 @@ describe('plugin-meetings', () => {
2394
2522
  correlation_id: meeting.correlationId,
2395
2523
  locus_id: meeting.locusUrl.split('/').pop(),
2396
2524
  connectionType: 'udp',
2525
+ selectedCandidatePairChanges: 2,
2526
+ numTransports: 1,
2397
2527
  isMultistream: false,
2398
2528
  retriedWithTurnServer: true,
2529
+ isJoinWithMediaRetry: false,
2399
2530
  },
2400
2531
  ]);
2401
2532
  meeting.roap.doTurnDiscovery;
@@ -2536,8 +2667,11 @@ describe('plugin-meetings', () => {
2536
2667
  correlation_id: meeting.correlationId,
2537
2668
  locus_id: meeting.locusUrl.split('/').pop(),
2538
2669
  connectionType: 'udp',
2670
+ selectedCandidatePairChanges: 2,
2671
+ numTransports: 1,
2539
2672
  isMultistream: false,
2540
2673
  retriedWithTurnServer: false,
2674
+ isJoinWithMediaRetry: false,
2541
2675
  someReachabilityMetric1: 'some value1',
2542
2676
  someReachabilityMetric2: 'some value2',
2543
2677
  }
@@ -2596,9 +2730,12 @@ describe('plugin-meetings', () => {
2596
2730
  turnServerUsed: true,
2597
2731
  retriedWithTurnServer: false,
2598
2732
  isMultistream: false,
2733
+ isJoinWithMediaRetry: false,
2599
2734
  signalingState: 'unknown',
2600
2735
  connectionState: 'unknown',
2601
2736
  iceConnectionState: 'unknown',
2737
+ selectedCandidatePairChanges: 2,
2738
+ numTransports: 1,
2602
2739
  }
2603
2740
  );
2604
2741
 
@@ -3017,7 +3154,7 @@ describe('plugin-meetings', () => {
3017
3154
  meeting.mediaId = 'fake media id';
3018
3155
  meeting.selfUrl = 'selfUrl';
3019
3156
  meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
3020
- meeting.mediaProperties.getCurrentConnectionType = sinon.stub().resolves('udp');
3157
+ meeting.mediaProperties.getCurrentConnectionInfo = sinon.stub().resolves({connectionType: 'udp', selectedCandidatePairChanges: 2, numTransports: 1});
3021
3158
  meeting.setMercuryListener = sinon.stub();
3022
3159
  meeting.locusInfo.onFullLocus = sinon.stub();
3023
3160
  meeting.webex.meetings.geoHintInfo = {regionCode: 'EU', countryCode: 'UK'};
@@ -6029,11 +6166,22 @@ describe('plugin-meetings', () => {
6029
6166
 
6030
6167
  beforeEach(() => {
6031
6168
  sandbox = sinon.createSandbox();
6032
- sandbox.stub(meeting, 'cleanupLocalStreams');
6169
+ meeting.statsAnalyzer = {
6170
+ stopAnalyzer: sinon.stub().returns(Promise.resolve())
6171
+ };
6033
6172
 
6034
- sandbox.stub(meeting.mediaProperties, 'setMediaDirection');
6173
+ meeting.reconnectionManager = {
6174
+ cleanUp: sinon.stub()
6175
+ };
6176
+
6177
+ meeting.cleanupLocalStreams=sinon.stub();
6178
+ meeting.closeRemoteStreams = sinon.stub().returns(Promise.resolve());
6179
+ meeting.closePeerConnections = sinon.stub().returns(Promise.resolve());
6180
+ meeting.unsetRemoteStreams = sinon.stub();
6181
+ meeting.unsetPeerConnections = sinon.stub();
6182
+ meeting.addMedia = sinon.stub().returns(Promise.resolve());
6183
+ meeting.mediaProperties.setMediaDirection = sinon.stub();
6035
6184
 
6036
- sandbox.stub(meeting.reconnectionManager, 'reconnectMedia').returns(Promise.resolve());
6037
6185
  sandbox
6038
6186
  .stub(MeetingUtil, 'joinMeeting')
6039
6187
  .returns(
@@ -6095,9 +6243,11 @@ describe('plugin-meetings', () => {
6095
6243
  });
6096
6244
  });
6097
6245
 
6098
- it('should reconnectMedia after DX joins after moveTo', async () => {
6246
+ it('should cleanup on moveTo & addMedia after', async () => {
6099
6247
  await meeting.moveTo('resourceId');
6100
6248
 
6249
+ assert.equal(meeting.isMoveToInProgress, true);
6250
+
6101
6251
  await meeting.locusInfo.emitScoped(
6102
6252
  {
6103
6253
  file: 'locus-info',
@@ -6105,26 +6255,26 @@ describe('plugin-meetings', () => {
6105
6255
  },
6106
6256
  'SELF_OBSERVING'
6107
6257
  );
6258
+
6108
6259
 
6109
- // beacuse we are calling callback so we need to wait
6110
-
6111
- assert.called(meeting.cleanupLocalStreams);
6112
-
6113
- // give queued Promise callbacks a chance to run
6114
- await Promise.resolve();
6115
-
6116
- assert.called(meeting.mediaProperties.setMediaDirection);
6117
-
6118
- assert.calledWith(meeting.reconnectionManager.reconnectMedia, {
6119
- mediaDirection: {
6120
- sendVideo: false,
6121
- receiveVideo: false,
6122
- sendAudio: false,
6123
- receiveAudio: false,
6124
- sendShare: false,
6125
- receiveShare: true,
6126
- },
6127
- });
6260
+ // Verify that the event handler behaves as expected
6261
+ expect(meeting.statsAnalyzer.stopAnalyzer.calledOnce).to.be.true;
6262
+ expect(meeting.closeRemoteStreams.calledOnce).to.be.true;
6263
+ await testUtils.flushPromises();
6264
+ expect(meeting.closePeerConnections.calledOnce).to.be.true;
6265
+ await testUtils.flushPromises();
6266
+ expect(meeting.cleanupLocalStreams.calledOnce).to.be.true;
6267
+ expect(meeting.unsetRemoteStreams.calledOnce).to.be.true;
6268
+ expect(meeting.unsetPeerConnections.calledOnce).to.be.true;
6269
+ expect(meeting.reconnectionManager.cleanUp.calledOnce).to.be.true;
6270
+ expect(meeting.mediaProperties.setMediaDirection.calledOnce).to.be.true;
6271
+ expect(meeting.addMedia.calledOnceWithExactly({
6272
+ audioEnabled: false,
6273
+ videoEnabled: false,
6274
+ shareVideoEnabled: true
6275
+ })).to.be.true;
6276
+ await testUtils.flushPromises();
6277
+ assert.equal(meeting.isMoveToInProgress, false);
6128
6278
  });
6129
6279
 
6130
6280
  it('should throw an error if moveTo call fails', async () => {
@@ -6132,6 +6282,7 @@ describe('plugin-meetings', () => {
6132
6282
  try {
6133
6283
  await meeting.moveTo('resourceId');
6134
6284
  } catch {
6285
+ assert.equal(meeting.isMoveToInProgress, false);
6135
6286
  assert.calledOnce(Metrics.sendBehavioralMetric);
6136
6287
  assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.MOVE_TO_FAILURE, {
6137
6288
  correlation_id: meeting.correlationId,
@@ -6153,6 +6304,7 @@ describe('plugin-meetings', () => {
6153
6304
  'SELF_OBSERVING'
6154
6305
  );
6155
6306
  } catch {
6307
+ assert.equal(meeting.isMoveToInProgress, false);
6156
6308
  assert.calledOnce(Metrics.sendBehavioralMetric);
6157
6309
  assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.MOVE_TO_FAILURE, {
6158
6310
  correlation_id: meeting.correlationId,
@@ -6778,21 +6930,13 @@ describe('plugin-meetings', () => {
6778
6930
  }),
6779
6931
  };
6780
6932
  meeting.setupMediaConnectionListeners();
6781
- meeting.deferSDPAnswer = {
6782
- resolve: sinon.stub(),
6783
- reject: sinon.stub(),
6784
- };
6785
6933
  meeting.sdpResponseTimer = '1234';
6786
- meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
6934
+ sinon.stub(meeting.mediaProperties, 'waitForMediaConnectionConnected').resolves();
6787
6935
 
6788
- eventListeners[Event.REMOTE_SDP_ANSWER_PROCESSED]();
6789
6936
  meeting.config.reconnection.enabled = true;
6790
6937
  meeting.currentMediaStatus = {audio: true};
6791
6938
  meeting.reconnectionManager = new ReconnectionManager(meeting);
6792
- meeting.reconnectionManager.reconnect = sinon.stub().returns(Promise.resolve());
6793
- meeting.reconnectionManager.reset = sinon.stub().returns(true);
6794
- meeting.reconnectionManager.cleanup = sinon.stub().returns(true);
6795
- meeting.reconnectionManager.setStatus = sinon.stub();
6939
+ sinon.stub(meeting.reconnectionManager, 'reconnect').returns(Promise.resolve());
6796
6940
  });
6797
6941
 
6798
6942
  it('should throw error if media not established before trying reconnect', async () => {
@@ -6812,87 +6956,72 @@ describe('plugin-meetings', () => {
6812
6956
  }
6813
6957
  });
6814
6958
 
6815
- it('should trigger reconnection success and send CA metric', async () => {
6816
- await meeting.reconnect();
6959
+ it('should call the right functions', async () => {
6960
+ const options = {id: 'fake options'};
6961
+ await meeting.reconnect(options);
6962
+
6963
+ sinon.stub(meeting, 'waitForRemoteSDPAnswer').resolves();
6817
6964
 
6818
- assert.calledWith(
6819
- TriggerProxy.trigger,
6820
- sinon.match.instanceOf(Meeting),
6821
- {file: 'meeting/index', function: 'reconnect'},
6822
- 'meeting:reconnectionSuccess'
6823
- );
6824
- assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
6825
- name: 'client.media.recovered',
6826
- payload: {
6827
- recoveredBy: 'new',
6828
- },
6829
- options: {
6830
- meetingId: meeting.id,
6831
- },
6832
- });
6833
6965
  assert.calledOnceWithExactly(
6834
- meeting.reconnectionManager.setStatus,
6835
- RECONNECTION.STATE.COMPLETE
6966
+ meeting.reconnectionManager.reconnect,
6967
+ options,
6968
+ sinon.match.any
6836
6969
  );
6837
- });
6970
+ const callback = meeting.reconnectionManager.reconnect.getCalls()[0].args[1];
6838
6971
 
6839
- it('should reset after reconnection success', async () => {
6840
- await meeting.reconnect();
6841
- assert.calledOnce(meeting.reconnectionManager.reset);
6972
+ // call the completion callback
6973
+ assert.isFunction(callback);
6974
+ await callback();
6975
+
6976
+ // check that the right things were called by the callback
6977
+ assert.calledOnceWithExactly(meeting.waitForRemoteSDPAnswer);
6978
+ assert.calledOnceWithExactly(meeting.mediaProperties.waitForMediaConnectionConnected);
6842
6979
  });
6843
6980
  });
6844
6981
 
6845
6982
  describe('unsuccessful reconnect', () => {
6983
+ let logUploadSpy;
6984
+
6846
6985
  beforeEach(() => {
6847
- meeting.config.reconnection.enabled = true;
6986
+ logUploadSpy = sinon.spy(meeting, 'uploadLogs');
6848
6987
  meeting.currentMediaStatus = {audio: true};
6849
6988
  meeting.reconnectionManager = new ReconnectionManager(meeting);
6850
6989
  meeting.reconnectionManager.reconnect = sinon
6851
6990
  .stub()
6852
6991
  .returns(Promise.reject(new Error()));
6853
- meeting.reconnectionManager.reset = sinon.stub().returns(true);
6854
6992
  });
6855
6993
 
6856
- it('should trigger an unsuccessful reconnection', async () => {
6994
+ it('should upload logs on reconnect failure', async () => {
6857
6995
  await assert.isRejected(meeting.reconnect());
6858
6996
  assert.calledWith(
6859
6997
  TriggerProxy.trigger,
6860
6998
  sinon.match.instanceOf(Meeting),
6861
6999
  {file: 'meeting/index', function: 'reconnect'},
6862
- 'meeting:reconnectionFailure',
6863
- {error: sinon.match.any}
7000
+ EVENTS.REQUEST_UPLOAD_LOGS,
7001
+ sinon.match.instanceOf(Meeting)
6864
7002
  );
6865
7003
  });
6866
7004
 
6867
- it('should send metrics on reconnect failure', async () => {
7005
+ it('should fail without uploading logs if there is no reconnectionManager', async () => {
7006
+ meeting.reconnectionManager = null;
6868
7007
  await assert.isRejected(meeting.reconnect());
6869
- assert(Metrics.sendBehavioralMetric.calledOnce);
6870
- assert.calledWith(
6871
- Metrics.sendBehavioralMetric,
6872
- BEHAVIORAL_METRICS.MEETING_RECONNECT_FAILURE,
6873
- {
6874
- correlation_id: meeting.correlationId,
6875
- locus_id: meeting.locusUrl.split('/').pop(),
6876
- reason: sinon.match.any,
6877
- stack: sinon.match.any,
6878
- }
6879
- );
7008
+ assert.notCalled(logUploadSpy);
6880
7009
  });
6881
7010
 
6882
- it('should upload logs on reconnect failure', async () => {
7011
+ it('should fail without uploading logs if there is no media established', async () => {
7012
+ meeting.currentMediaStatus = null;
6883
7013
  await assert.isRejected(meeting.reconnect());
6884
- assert.calledWith(
6885
- TriggerProxy.trigger,
6886
- sinon.match.instanceOf(Meeting),
6887
- {file: 'meeting/index', function: 'reconnect'},
6888
- EVENTS.REQUEST_UPLOAD_LOGS,
6889
- sinon.match.instanceOf(Meeting)
6890
- );
7014
+ assert.notCalled(logUploadSpy);
6891
7015
  });
6892
7016
 
6893
- it('should reset after an unsuccessful reconnection', async () => {
6894
- await assert.isRejected(meeting.reconnect());
6895
- assert.calledOnce(meeting.reconnectionManager.reset);
7017
+ it('should resolve if the error is ReconnectionNotStartedError', async () => {
7018
+ meeting.reconnectionManager.reconnect.returns(
7019
+ Promise.reject(new ReconnectionNotStartedError())
7020
+ );
7021
+ await meeting.reconnect();
7022
+
7023
+ // logs shouldn't be uploaded
7024
+ assert.notCalled(logUploadSpy);
6896
7025
  });
6897
7026
  });
6898
7027
  });
@@ -7738,6 +7867,7 @@ describe('plugin-meetings', () => {
7738
7867
  describe('#setUpLocusInfoSelfListener', () => {
7739
7868
  it('listens to the self unadmitted guest event', (done) => {
7740
7869
  meeting.startKeepAlive = sinon.stub();
7870
+ meeting.updateLLMConnection = sinon.stub();
7741
7871
  meeting.locusInfo.emit({function: 'test', file: 'test'}, 'SELF_UNADMITTED_GUEST', test1);
7742
7872
  assert.calledOnceWithExactly(meeting.startKeepAlive);
7743
7873
  assert.calledThrice(TriggerProxy.trigger);
@@ -7748,6 +7878,7 @@ describe('plugin-meetings', () => {
7748
7878
  'meeting:self:lobbyWaiting',
7749
7879
  {payload: test1}
7750
7880
  );
7881
+ assert.calledOnce(meeting.updateLLMConnection);
7751
7882
  done();
7752
7883
  });
7753
7884
  it('listens to the self admitted guest event', (done) => {
@@ -8100,6 +8231,21 @@ describe('plugin-meetings', () => {
8100
8231
  EVENT_TRIGGERS.MEETING_INTERPRETATION_UPDATE
8101
8232
  );
8102
8233
  });
8234
+
8235
+ it('listens to the locus manual caption update event', () => {
8236
+ meeting.locusInfo.emit(
8237
+ {function: 'test', file: 'test'},
8238
+ 'CONTROLS_MEETING_MANUAL_CAPTION_UPDATED',
8239
+ {enable: true}
8240
+ );
8241
+
8242
+ assert.calledWith(
8243
+ TriggerProxy.trigger,
8244
+ meeting,
8245
+ {file: 'meeting/index', function: 'setupLocusControlsListener'},
8246
+ EVENT_TRIGGERS.MEETING_MANUAL_CAPTION_UPDATED
8247
+ );
8248
+ });
8103
8249
  });
8104
8250
 
8105
8251
  describe('#setUpLocusUrlListener', () => {