@webex/plugin-meetings 3.11.0-next.2 → 3.11.0-next.21

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 (64) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/hashTree/hashTree.js +18 -0
  4. package/dist/hashTree/hashTree.js.map +1 -1
  5. package/dist/hashTree/hashTreeParser.js +307 -139
  6. package/dist/hashTree/hashTreeParser.js.map +1 -1
  7. package/dist/hashTree/types.js +2 -1
  8. package/dist/hashTree/types.js.map +1 -1
  9. package/dist/hashTree/utils.js +10 -0
  10. package/dist/hashTree/utils.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 +55 -42
  14. package/dist/locus-info/index.js.map +1 -1
  15. package/dist/media/MediaConnectionAwaiter.js +57 -1
  16. package/dist/media/MediaConnectionAwaiter.js.map +1 -1
  17. package/dist/media/properties.js +4 -2
  18. package/dist/media/properties.js.map +1 -1
  19. package/dist/meeting/index.js +33 -22
  20. package/dist/meeting/index.js.map +1 -1
  21. package/dist/meeting/util.js +108 -2
  22. package/dist/meeting/util.js.map +1 -1
  23. package/dist/meetings/index.js +76 -26
  24. package/dist/meetings/index.js.map +1 -1
  25. package/dist/metrics/constants.js +2 -1
  26. package/dist/metrics/constants.js.map +1 -1
  27. package/dist/multistream/mediaRequestManager.js +1 -1
  28. package/dist/multistream/mediaRequestManager.js.map +1 -1
  29. package/dist/reactions/reactions.type.js.map +1 -1
  30. package/dist/types/hashTree/hashTree.d.ts +7 -0
  31. package/dist/types/hashTree/hashTreeParser.d.ts +47 -12
  32. package/dist/types/hashTree/types.d.ts +1 -0
  33. package/dist/types/hashTree/utils.d.ts +6 -0
  34. package/dist/types/locus-info/index.d.ts +9 -2
  35. package/dist/types/media/MediaConnectionAwaiter.d.ts +10 -1
  36. package/dist/types/media/properties.d.ts +2 -1
  37. package/dist/types/meeting/index.d.ts +8 -5
  38. package/dist/types/meeting/util.d.ts +28 -0
  39. package/dist/types/meetings/index.d.ts +3 -1
  40. package/dist/types/metrics/constants.d.ts +1 -0
  41. package/dist/types/reactions/reactions.type.d.ts +1 -0
  42. package/dist/webinar/index.js +1 -1
  43. package/package.json +22 -22
  44. package/src/hashTree/hashTree.ts +17 -0
  45. package/src/hashTree/hashTreeParser.ts +294 -96
  46. package/src/hashTree/types.ts +1 -0
  47. package/src/hashTree/utils.ts +9 -0
  48. package/src/locus-info/index.ts +83 -35
  49. package/src/media/MediaConnectionAwaiter.ts +41 -1
  50. package/src/media/properties.ts +3 -1
  51. package/src/meeting/index.ts +24 -11
  52. package/src/meeting/util.ts +132 -1
  53. package/src/meetings/index.ts +93 -8
  54. package/src/metrics/constants.ts +1 -0
  55. package/src/multistream/mediaRequestManager.ts +1 -1
  56. package/src/reactions/reactions.type.ts +1 -0
  57. package/test/unit/spec/hashTree/hashTree.ts +66 -0
  58. package/test/unit/spec/hashTree/hashTreeParser.ts +942 -110
  59. package/test/unit/spec/locus-info/index.js +88 -17
  60. package/test/unit/spec/media/MediaConnectionAwaiter.ts +41 -1
  61. package/test/unit/spec/media/properties.ts +12 -3
  62. package/test/unit/spec/meeting/index.js +160 -2
  63. package/test/unit/spec/meeting/utils.js +294 -22
  64. package/test/unit/spec/meetings/index.js +594 -17
@@ -425,7 +425,10 @@ describe('plugin-meetings', () => {
425
425
 
426
426
  describe('#_toggleStopIceGatheringAfterFirstRelayCandidate', () => {
427
427
  it('should have _toggleStopIceGatheringAfterFirstRelayCandidate', () => {
428
- assert.equal(typeof webex.meetings._toggleStopIceGatheringAfterFirstRelayCandidate, 'function');
428
+ assert.equal(
429
+ typeof webex.meetings._toggleStopIceGatheringAfterFirstRelayCandidate,
430
+ 'function'
431
+ );
429
432
  });
430
433
 
431
434
  describe('success', () => {
@@ -602,6 +605,196 @@ describe('plugin-meetings', () => {
602
605
 
603
606
  clock.restore();
604
607
  });
608
+
609
+ it('returns the same promise when register is called multiple times concurrently', async () => {
610
+ webex.canAuthorize = true;
611
+ webex.meetings.registered = false;
612
+
613
+ // Make registration take some time
614
+ let resolveRegistration;
615
+ const registrationDelay = new Promise((resolve) => {
616
+ resolveRegistration = resolve;
617
+ });
618
+
619
+ webex.internal.device.register.returns(registrationDelay);
620
+ webex.internal.mercury.connect.returns(Promise.resolve());
621
+
622
+ // Start first registration
623
+ const firstRegisterPromise = webex.meetings.register();
624
+
625
+ // Immediately start second registration while first is in progress
626
+ const secondRegisterPromise = webex.meetings.register();
627
+
628
+ // Start third registration
629
+ const thirdRegisterPromise = webex.meetings.register();
630
+
631
+ // All should return the same promise
632
+ assert.strictEqual(firstRegisterPromise, secondRegisterPromise);
633
+ assert.strictEqual(secondRegisterPromise, thirdRegisterPromise);
634
+
635
+ // Complete the registration
636
+ resolveRegistration();
637
+
638
+ await firstRegisterPromise;
639
+ await secondRegisterPromise;
640
+ await thirdRegisterPromise;
641
+
642
+ // Device registration and mercury connect should only be called once
643
+ assert.calledOnce(webex.internal.device.register);
644
+ assert.calledOnce(webex.internal.mercury.connect);
645
+ assert.isTrue(webex.meetings.registered);
646
+ });
647
+
648
+ it('prevents duplicate registrations when register is called during in-flight registration', async () => {
649
+ webex.canAuthorize = true;
650
+ webex.meetings.registered = false;
651
+
652
+ let deviceRegisterCallCount = 0;
653
+ let mercuryConnectCallCount = 0;
654
+
655
+ // Track actual calls
656
+ webex.internal.device.register = sinon.stub().callsFake(() => {
657
+ deviceRegisterCallCount++;
658
+ return Promise.resolve();
659
+ });
660
+ webex.internal.mercury.connect = sinon.stub().callsFake(() => {
661
+ mercuryConnectCallCount++;
662
+ return Promise.resolve();
663
+ });
664
+
665
+ // Start registration without awaiting
666
+ const promise1 = webex.meetings.register();
667
+
668
+ // Call register again while first is in progress
669
+ const promise2 = webex.meetings.register();
670
+
671
+ // Wait for both
672
+ await Promise.all([promise1, promise2]);
673
+
674
+ // Should only register once
675
+ assert.equal(deviceRegisterCallCount, 1, 'device.register should only be called once');
676
+ assert.equal(mercuryConnectCallCount, 1, 'mercury.connect should only be called once');
677
+ assert.isTrue(webex.meetings.registered);
678
+ });
679
+
680
+ it('handles concurrent register calls when first registration fails', async () => {
681
+ webex.canAuthorize = true;
682
+ webex.meetings.registered = false;
683
+
684
+ const registrationError = new Error('registration failed');
685
+ webex.internal.device.register.rejects(registrationError);
686
+
687
+ // Start first registration
688
+ const firstRegisterPromise = webex.meetings.register();
689
+
690
+ // Start second registration while first is in progress
691
+ const secondRegisterPromise = webex.meetings.register();
692
+
693
+ // Both should reject with the same error
694
+ await assert.isRejected(firstRegisterPromise, 'registration failed');
695
+ await assert.isRejected(secondRegisterPromise, 'registration failed');
696
+
697
+ // Should still only attempt registration once
698
+ assert.calledOnce(webex.internal.device.register);
699
+ assert.isFalse(webex.meetings.registered);
700
+ });
701
+
702
+ it('allows new registration after previous registration completes', async () => {
703
+ webex.canAuthorize = true;
704
+ webex.meetings.registered = false;
705
+
706
+ // First registration
707
+ await webex.meetings.register();
708
+ assert.isTrue(webex.meetings.registered);
709
+
710
+ // Reset for second registration
711
+ webex.meetings.registered = false;
712
+ webex.internal.device.register.resetHistory();
713
+ webex.internal.mercury.connect.resetHistory();
714
+
715
+ // Second registration should work normally
716
+ await webex.meetings.register();
717
+ assert.calledOnce(webex.internal.device.register);
718
+ assert.calledOnce(webex.internal.mercury.connect);
719
+ assert.isTrue(webex.meetings.registered);
720
+ });
721
+
722
+ it('clears registrationPromise after successful registration', async () => {
723
+ webex.canAuthorize = true;
724
+ webex.meetings.registered = false;
725
+
726
+ await webex.meetings.register();
727
+
728
+ assert.isTrue(webex.meetings.registered);
729
+ assert.isNull(webex.meetings.registrationPromise);
730
+ });
731
+
732
+ it('clears registrationPromise after failed registration', async () => {
733
+ webex.canAuthorize = true;
734
+ webex.meetings.registered = false;
735
+
736
+ webex.internal.device.register.rejects(new Error('registration failed'));
737
+
738
+ await assert.isRejected(webex.meetings.register());
739
+
740
+ assert.isFalse(webex.meetings.registered);
741
+ assert.isNull(webex.meetings.registrationPromise);
742
+ });
743
+
744
+ it('waits for unregistration to complete before registering', async () => {
745
+ webex.canAuthorize = true;
746
+
747
+ assert.isFalse(webex.meetings.registered);
748
+
749
+ // First, register successfully
750
+ await webex.meetings.register();
751
+ assert.isTrue(webex.meetings.registered);
752
+
753
+ // Start unregistration (but don't await it)
754
+ const unregisterPromise = webex.meetings.unregister();
755
+ assert.isDefined(webex.meetings.unregistrationPromise);
756
+
757
+ // Immediately try to register while unregister is in progress
758
+ const registerPromise = webex.meetings.register();
759
+
760
+ // Wait for register to complete
761
+ await registerPromise;
762
+
763
+ // Should have completed registration
764
+ assert.isTrue(webex.meetings.registered);
765
+
766
+ // Now await the original unregister promise - this should have already completed
767
+ // and should NOT affect the registered state since register() took over
768
+ await unregisterPromise;
769
+
770
+ // Should STILL be registered because register() took over
771
+ assert.isTrue(webex.meetings.registered);
772
+ });
773
+
774
+ it('handles multiple register calls during unregistration', async () => {
775
+ webex.canAuthorize = true;
776
+
777
+ // First, register successfully
778
+ await webex.meetings.register();
779
+ assert.isTrue(webex.meetings.registered);
780
+
781
+ // Start unregistration
782
+ const unregistrationPromise = webex.meetings.unregister();
783
+
784
+ // Try to register once while unregister is in progress
785
+ await webex.meetings.register();
786
+
787
+ // Should be registered again
788
+ assert.isTrue(
789
+ webex.meetings.registered,
790
+ 'Expected meetings to be registered after unregister and register cycle'
791
+ );
792
+
793
+ await unregistrationPromise;
794
+
795
+ // Should STILL be registered because register() took over
796
+ assert.isTrue(webex.meetings.registered);
797
+ });
605
798
  });
606
799
 
607
800
  describe('#unregister', () => {
@@ -622,6 +815,18 @@ describe('plugin-meetings', () => {
622
815
  });
623
816
  });
624
817
 
818
+ it('calls mercury.disconnect with code 3050 and reason to prevent auto-reconnect', (done) => {
819
+ webex.meetings.registered = true;
820
+ webex.meetings.unregister().then(() => {
821
+ assert.calledOnce(webex.internal.mercury.disconnect);
822
+ assert.calledWith(webex.internal.mercury.disconnect, {
823
+ code: 3050,
824
+ reason: 'meetings unregister',
825
+ });
826
+ done();
827
+ });
828
+ });
829
+
625
830
  it('rejects when device.unregister fails', async () => {
626
831
  webex.meetings.registered = true;
627
832
  webex.internal.device.unregister = sinon.stub().returns(Promise.reject());
@@ -670,6 +875,335 @@ describe('plugin-meetings', () => {
670
875
  done();
671
876
  });
672
877
  });
878
+
879
+ it('waits for registration to complete before unregistering when called during registration', async () => {
880
+ webex.canAuthorize = true;
881
+ webex.meetings.registered = false;
882
+
883
+ let resolveRegistration;
884
+ const registrationDelay = new Promise((resolve) => {
885
+ resolveRegistration = resolve;
886
+ });
887
+
888
+ webex.internal.device.register.returns(registrationDelay);
889
+ webex.internal.mercury.connect.returns(Promise.resolve());
890
+
891
+ // Start registration (don't await)
892
+ const registerPromise = webex.meetings.register();
893
+
894
+ // Verify registration is in progress
895
+ assert.exists(webex.meetings.registrationPromise);
896
+ assert.isFalse(webex.meetings.registered);
897
+
898
+ // Call unregister while registration is in progress
899
+ const unregisterPromise = webex.meetings.unregister();
900
+
901
+ // Registration should still be in progress
902
+ assert.exists(webex.meetings.registrationPromise);
903
+
904
+ // Complete the registration
905
+ resolveRegistration();
906
+ await registerPromise;
907
+
908
+ // Now unregister should proceed
909
+ await unregisterPromise;
910
+
911
+ // Verify final state
912
+ assert.isFalse(webex.meetings.registered);
913
+ assert.isNull(webex.meetings.registrationPromise);
914
+ assert.calledOnce(webex.internal.device.unregister);
915
+ assert.calledOnce(webex.internal.mercury.disconnect);
916
+ });
917
+
918
+ it('handles unregister called during registration that fails', async () => {
919
+ webex.canAuthorize = true;
920
+ webex.meetings.registered = false;
921
+
922
+ const registrationError = new Error('registration failed');
923
+ let rejectRegistration;
924
+ const registrationDelay = new Promise((resolve, reject) => {
925
+ rejectRegistration = reject;
926
+ });
927
+
928
+ webex.internal.device.register.returns(registrationDelay);
929
+
930
+ // Start registration (don't await)
931
+ const registerPromise = webex.meetings.register();
932
+
933
+ // Call unregister while registration is in progress
934
+ const unregisterPromise = webex.meetings.unregister();
935
+
936
+ // Fail the registration
937
+ rejectRegistration(registrationError);
938
+
939
+ // Registration should fail
940
+ await assert.isRejected(registerPromise, 'registration failed');
941
+
942
+ // // Unregister should resolve immediately since registration failed
943
+ await unregisterPromise;
944
+
945
+ // Verify final state - not registered
946
+ assert.isFalse(webex.meetings.registered);
947
+ assert.isNull(webex.meetings.registrationPromise);
948
+ // Device unregister should not be called because registration never completed
949
+ assert.notCalled(webex.internal.device.unregister);
950
+ });
951
+
952
+ it('handles multiple unregister calls during registration', async () => {
953
+ webex.canAuthorize = true;
954
+ webex.meetings.registered = false;
955
+
956
+ let resolveRegistration;
957
+ const registrationDelay = new Promise((resolve) => {
958
+ resolveRegistration = resolve;
959
+ });
960
+
961
+ webex.internal.device.register.returns(registrationDelay);
962
+ webex.internal.mercury.connect.returns(Promise.resolve());
963
+
964
+ // Start registration
965
+ const registerPromise = webex.meetings.register();
966
+
967
+ // Call unregister multiple times while registration is in progress
968
+ const unregisterPromise1 = webex.meetings.unregister();
969
+ const unregisterPromise2 = webex.meetings.unregister();
970
+ const unregisterPromise3 = webex.meetings.unregister();
971
+
972
+ // Complete registration
973
+ resolveRegistration();
974
+ await registerPromise;
975
+
976
+ // All unregister calls should complete
977
+ await Promise.all([unregisterPromise1, unregisterPromise2, unregisterPromise3]);
978
+
979
+ // Verify final state
980
+ assert.isFalse(webex.meetings.registered);
981
+ // Disconnect and unregister should be called, but not multiple times
982
+ assert.calledOnce(webex.internal.mercury.disconnect);
983
+ assert.calledOnce(webex.internal.device.unregister);
984
+ });
985
+
986
+ it('completes unregister correctly after waiting for registration', async () => {
987
+ webex.canAuthorize = true;
988
+ webex.meetings.registered = false;
989
+
990
+ const stopListeningForEventsSpy = sinon.spy(webex.meetings, 'stopListeningForEvents');
991
+
992
+ let resolveRegistration;
993
+ const registrationDelay = new Promise((resolve) => {
994
+ resolveRegistration = resolve;
995
+ });
996
+
997
+ webex.internal.device.register.returns(registrationDelay);
998
+ webex.internal.mercury.connect.returns(Promise.resolve());
999
+
1000
+ // Start registration
1001
+ const registerPromise = webex.meetings.register();
1002
+
1003
+ // Call unregister during registration
1004
+ const unregisterPromise = webex.meetings.unregister();
1005
+
1006
+ // stopListeningForEvents should not be called yet
1007
+ assert.notCalled(stopListeningForEventsSpy);
1008
+
1009
+ // Complete registration
1010
+ resolveRegistration();
1011
+ await registerPromise;
1012
+
1013
+ // After registration completes, the meetings plugin should be registered
1014
+ assert.isTrue(webex.meetings.registered);
1015
+
1016
+ // Now unregister should proceed
1017
+ await unregisterPromise;
1018
+
1019
+ // Verify unregister completed properly
1020
+ assert.calledOnce(stopListeningForEventsSpy);
1021
+ assert.calledOnce(webex.internal.mercury.disconnect);
1022
+ assert.calledOnce(webex.internal.device.unregister);
1023
+ assert.isFalse(webex.meetings.registered);
1024
+ assert.deepEqual(webex.meetings.registrationStatus, INITIAL_REGISTRATION_STATUS);
1025
+ });
1026
+
1027
+ it('logs appropriate message when unregister is called during registration', async () => {
1028
+ webex.canAuthorize = true;
1029
+ webex.meetings.registered = false;
1030
+
1031
+ const loggerSpy = sinon.spy(LoggerProxy.logger, 'info');
1032
+
1033
+ let resolveRegistration;
1034
+ const registrationDelay = new Promise((resolve) => {
1035
+ resolveRegistration = resolve;
1036
+ });
1037
+
1038
+ webex.internal.device.register.returns(registrationDelay);
1039
+ webex.internal.mercury.connect.returns(Promise.resolve());
1040
+
1041
+ // Start registration
1042
+ const registerPromise = webex.meetings.register();
1043
+
1044
+ // Call unregister during registration
1045
+ const unregisterPromise = webex.meetings.unregister();
1046
+
1047
+ // Should log that it's waiting
1048
+ assert.calledWith(
1049
+ loggerSpy,
1050
+ 'Meetings:index#unregister --> INFO, Meetings plugin registration in progress, waiting to unregister'
1051
+ );
1052
+
1053
+ // Complete registration and unregistration
1054
+ resolveRegistration();
1055
+ await registerPromise;
1056
+ await unregisterPromise;
1057
+
1058
+ loggerSpy.restore();
1059
+ });
1060
+
1061
+ it('returns the same promise when unregister is called multiple times concurrently', async () => {
1062
+ webex.meetings.registered = true;
1063
+
1064
+ // Make unregistration take some time
1065
+ let resolveUnregistration;
1066
+ const unregistrationDelay = new Promise((resolve) => {
1067
+ resolveUnregistration = resolve;
1068
+ });
1069
+
1070
+ webex.internal.mercury.disconnect.returns(unregistrationDelay);
1071
+ webex.internal.device.unregister.returns(Promise.resolve());
1072
+
1073
+ // Start first unregistration
1074
+ const firstUnregisterPromise = webex.meetings.unregister();
1075
+
1076
+ // Immediately start second unregistration while first is in progress
1077
+ const secondUnregisterPromise = webex.meetings.unregister();
1078
+
1079
+ // Start third unregistration
1080
+ const thirdUnregisterPromise = webex.meetings.unregister();
1081
+
1082
+ // All should return the same promise
1083
+ assert.strictEqual(firstUnregisterPromise, secondUnregisterPromise);
1084
+ assert.strictEqual(secondUnregisterPromise, thirdUnregisterPromise);
1085
+
1086
+ // Complete the unregistration
1087
+ resolveUnregistration();
1088
+
1089
+ await firstUnregisterPromise;
1090
+ await secondUnregisterPromise;
1091
+ await thirdUnregisterPromise;
1092
+
1093
+ // Mercury disconnect and device unregister should only be called once
1094
+ assert.calledOnce(webex.internal.mercury.disconnect);
1095
+ assert.calledOnce(webex.internal.device.unregister);
1096
+ assert.isFalse(webex.meetings.registered);
1097
+ });
1098
+
1099
+ it('clears unregistrationPromise after successful unregistration', async () => {
1100
+ webex.meetings.registered = true;
1101
+
1102
+ await webex.meetings.unregister();
1103
+
1104
+ assert.isFalse(webex.meetings.registered);
1105
+ assert.isNull(webex.meetings.unregistrationPromise);
1106
+ });
1107
+
1108
+ it('clears unregistrationPromise after failed unregistration', async () => {
1109
+ webex.meetings.registered = true;
1110
+
1111
+ webex.internal.mercury.disconnect.rejects(new Error('disconnect failed'));
1112
+
1113
+ await assert.isRejected(webex.meetings.unregister());
1114
+
1115
+ assert.isTrue(webex.meetings.registered);
1116
+ assert.isNull(webex.meetings.unregistrationPromise);
1117
+ });
1118
+
1119
+ it('allows new unregistration after previous unregistration completes', async () => {
1120
+ webex.meetings.registered = true;
1121
+
1122
+ // First unregistration
1123
+ await webex.meetings.unregister();
1124
+ assert.isFalse(webex.meetings.registered);
1125
+
1126
+ // Register again
1127
+ webex.canAuthorize = true;
1128
+ await webex.meetings.register();
1129
+ assert.isTrue(webex.meetings.registered);
1130
+
1131
+ // Reset history
1132
+ webex.internal.mercury.disconnect.resetHistory();
1133
+ webex.internal.device.unregister.resetHistory();
1134
+
1135
+ // Second unregistration should work normally
1136
+ await webex.meetings.unregister();
1137
+ assert.calledOnce(webex.internal.mercury.disconnect);
1138
+ assert.calledOnce(webex.internal.device.unregister);
1139
+ assert.isFalse(webex.meetings.registered);
1140
+ });
1141
+
1142
+ it('handles register called during unregistration that fails', async () => {
1143
+ webex.canAuthorize = true;
1144
+ webex.meetings.registered = true;
1145
+
1146
+ const unregistrationError = new Error('unregistration failed');
1147
+ let rejectUnregistration;
1148
+ const unregistrationDelay = new Promise((resolve, reject) => {
1149
+ rejectUnregistration = reject;
1150
+ });
1151
+
1152
+ webex.internal.mercury.disconnect.returns(unregistrationDelay);
1153
+
1154
+ // Start unregistration (don't await)
1155
+ const unregisterPromise = webex.meetings.unregister();
1156
+
1157
+ // Call register while unregistration is in progress
1158
+ const registerPromise = webex.meetings.register();
1159
+
1160
+ // Fail the unregistration
1161
+ rejectUnregistration(unregistrationError);
1162
+
1163
+ // Unregistration should fail
1164
+ await assert.isRejected(unregisterPromise, 'unregistration failed');
1165
+
1166
+ // Register should still succeed (retry after unregister failure)
1167
+ await registerPromise;
1168
+
1169
+ // Verify final state - should be registered
1170
+ assert.isTrue(webex.meetings.registered);
1171
+ assert.isNull(webex.meetings.unregistrationPromise);
1172
+ });
1173
+
1174
+ it('logs appropriate message when register is called during unregistration', async () => {
1175
+ webex.canAuthorize = true;
1176
+ webex.meetings.registered = true;
1177
+
1178
+ const loggerSpy = sinon.spy(LoggerProxy.logger, 'info');
1179
+
1180
+ let resolveUnregistration;
1181
+ const unregistrationDelay = new Promise((resolve) => {
1182
+ resolveUnregistration = resolve;
1183
+ });
1184
+
1185
+ webex.internal.mercury.disconnect.returns(unregistrationDelay);
1186
+ webex.internal.device.unregister.returns(Promise.resolve());
1187
+
1188
+ // Start unregistration
1189
+ const unregisterPromise = webex.meetings.unregister();
1190
+
1191
+ // Call register during unregistration
1192
+ const registerPromise = webex.meetings.register();
1193
+
1194
+ // Should log that it's waiting
1195
+ assert.calledWith(
1196
+ loggerSpy,
1197
+ 'Meetings:index#register --> INFO, Meetings plugin unregistration in progress, waiting to register'
1198
+ );
1199
+
1200
+ // Complete unregistration and registration
1201
+ resolveUnregistration();
1202
+ await unregisterPromise;
1203
+ await registerPromise;
1204
+
1205
+ loggerSpy.restore();
1206
+ });
673
1207
  });
674
1208
 
675
1209
  describe('virtual background effect', () => {
@@ -732,7 +1266,7 @@ describe('plugin-meetings', () => {
732
1266
  };
733
1267
  });
734
1268
 
735
- it('creates noise reduction effect', async () => {
1269
+ it('creates noise reduction effect with BNR model', async () => {
736
1270
  const result = await webex.meetings.createNoiseReductionEffect({audioContext: {}});
737
1271
 
738
1272
  assert.exists(result);
@@ -744,30 +1278,51 @@ describe('plugin-meetings', () => {
744
1278
  authToken: 'fake_token',
745
1279
  mode: 'WORKLET',
746
1280
  avoidSimd: false,
1281
+ model: 'bnr',
747
1282
  });
748
1283
  assert.exists(result.enable);
749
1284
  assert.exists(result.disable);
750
1285
  assert.exists(result.dispose);
751
1286
  });
752
1287
 
753
- it('creates noise reduction effect with custom options passed', async () => {
754
- const effectOptions = {
1288
+ it('creates noise reduction effect with ST model', async () => {
1289
+ const result = await webex.meetings.createNoiseReductionEffect({
755
1290
  audioContext: {},
756
- mode: 'LEGACY',
757
- env: 'int',
758
- avoidSimd: true,
759
- };
760
-
761
- const result = await webex.meetings.createNoiseReductionEffect(effectOptions);
1291
+ model: 'st',
1292
+ });
762
1293
 
763
1294
  assert.exists(result);
764
1295
  assert.instanceOf(result, NoiseReductionEffect);
765
1296
  assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
766
- assert.deepEqual(result.options, {...effectOptions, authToken: 'fake_token'});
1297
+ assert.equal(result.options.authToken, 'fake_token');
1298
+ assert.deepEqual(result.options, {
1299
+ audioContext: {},
1300
+ authToken: 'fake_token',
1301
+ mode: 'WORKLET',
1302
+ avoidSimd: false,
1303
+ model: 'st',
1304
+ });
767
1305
  assert.exists(result.enable);
768
1306
  assert.exists(result.disable);
769
1307
  assert.exists(result.dispose);
770
1308
  });
1309
+
1310
+ it('passes custom options to noise reduction effect', async () => {
1311
+ const result = await webex.meetings.createNoiseReductionEffect({
1312
+ audioContext: {},
1313
+ mode: 'LEGACY',
1314
+ env: 'int',
1315
+ avoidSimd: true,
1316
+ });
1317
+
1318
+ assert.exists(result);
1319
+ assert.instanceOf(result, NoiseReductionEffect);
1320
+ assert.equal(result.options.mode, 'LEGACY');
1321
+ assert.equal(result.options.env, 'int');
1322
+ assert.equal(result.options.avoidSimd, true);
1323
+ assert.equal(result.options.authToken, 'fake_token');
1324
+ assert.equal(result.options.model, 'bnr');
1325
+ });
771
1326
  });
772
1327
 
773
1328
  describe('gets', () => {
@@ -918,7 +1473,7 @@ describe('plugin-meetings', () => {
918
1473
  locus: {
919
1474
  url: url1,
920
1475
  },
921
- hashTreeMessage: undefined
1476
+ hashTreeMessage: undefined,
922
1477
  });
923
1478
  });
924
1479
  });
@@ -1203,8 +1758,30 @@ describe('plugin-meetings', () => {
1203
1758
 
1204
1759
  it('calls createMeeting with classificationId and returns its promise', async () => {
1205
1760
  await checkCallCreateMeeting(
1206
- [test1, test2, FAKE_USE_RANDOM_DELAY, {}, undefined, true, callStateForMetrics, undefined, undefined, undefined, classificationId],
1207
- [test1, test2, FAKE_USE_RANDOM_DELAY, {}, callStateForMetrics, true, undefined, undefined, classificationId],
1761
+ [
1762
+ test1,
1763
+ test2,
1764
+ FAKE_USE_RANDOM_DELAY,
1765
+ {},
1766
+ undefined,
1767
+ true,
1768
+ callStateForMetrics,
1769
+ undefined,
1770
+ undefined,
1771
+ undefined,
1772
+ classificationId,
1773
+ ],
1774
+ [
1775
+ test1,
1776
+ test2,
1777
+ FAKE_USE_RANDOM_DELAY,
1778
+ {},
1779
+ callStateForMetrics,
1780
+ true,
1781
+ undefined,
1782
+ undefined,
1783
+ classificationId,
1784
+ ]
1208
1785
  );
1209
1786
  });
1210
1787
 
@@ -1437,7 +2014,7 @@ describe('plugin-meetings', () => {
1437
2014
  webExMeetingId,
1438
2015
  },
1439
2016
  },
1440
- hashTreeMessage: undefined
2017
+ hashTreeMessage: undefined,
1441
2018
  });
1442
2019
  });
1443
2020
  it('should setup the meeting from a hash tree event', async () => {
@@ -1507,7 +2084,7 @@ describe('plugin-meetings', () => {
1507
2084
  webExMeetingId,
1508
2085
  },
1509
2086
  },
1510
- hashTreeMessage: undefined
2087
+ hashTreeMessage: undefined,
1511
2088
  });
1512
2089
  });
1513
2090
 
@@ -1583,7 +2160,7 @@ describe('plugin-meetings', () => {
1583
2160
  webExMeetingId,
1584
2161
  },
1585
2162
  },
1586
- hashTreeMessage: undefined
2163
+ hashTreeMessage: undefined,
1587
2164
  });
1588
2165
  });
1589
2166