@webex/plugin-meetings 3.6.0-next.1 → 3.6.0-next.10

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 (48) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/common/errors/webinar-registration-error.js +50 -0
  4. package/dist/common/errors/webinar-registration-error.js.map +1 -0
  5. package/dist/constants.js +7 -0
  6. package/dist/constants.js.map +1 -1
  7. package/dist/index.js +7 -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/parser.js +5 -1
  12. package/dist/locus-info/parser.js.map +1 -1
  13. package/dist/meeting/index.js +146 -99
  14. package/dist/meeting/index.js.map +1 -1
  15. package/dist/meeting/muteState.js +5 -2
  16. package/dist/meeting/muteState.js.map +1 -1
  17. package/dist/meeting-info/meeting-info-v2.js +68 -17
  18. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  19. package/dist/meetings/index.js +2 -1
  20. package/dist/meetings/index.js.map +1 -1
  21. package/dist/metrics/constants.js +2 -1
  22. package/dist/metrics/constants.js.map +1 -1
  23. package/dist/multistream/remoteMedia.js +4 -0
  24. package/dist/multistream/remoteMedia.js.map +1 -1
  25. package/dist/types/common/errors/webinar-registration-error.d.ts +14 -0
  26. package/dist/types/constants.d.ts +6 -0
  27. package/dist/types/index.d.ts +2 -1
  28. package/dist/types/meeting/muteState.d.ts +2 -1
  29. package/dist/types/meeting-info/meeting-info-v2.d.ts +23 -0
  30. package/dist/types/metrics/constants.d.ts +1 -0
  31. package/dist/types/multistream/remoteMedia.d.ts +1 -0
  32. package/dist/webinar/index.js +1 -1
  33. package/package.json +21 -21
  34. package/src/common/errors/webinar-registration-error.ts +27 -0
  35. package/src/constants.ts +6 -0
  36. package/src/index.ts +2 -0
  37. package/src/locus-info/parser.ts +8 -1
  38. package/src/meeting/index.ts +40 -11
  39. package/src/meeting/muteState.ts +6 -2
  40. package/src/meeting-info/meeting-info-v2.ts +51 -0
  41. package/src/meetings/index.ts +3 -1
  42. package/src/metrics/constants.ts +1 -0
  43. package/src/multistream/remoteMedia.ts +5 -0
  44. package/test/unit/spec/locus-info/index.js +29 -0
  45. package/test/unit/spec/meeting/index.js +60 -1
  46. package/test/unit/spec/meeting/muteState.js +8 -4
  47. package/test/unit/spec/meeting-info/meetinginfov2.js +37 -0
  48. package/test/unit/spec/multistream/remoteMedia.ts +16 -2
@@ -1807,6 +1807,35 @@ describe('plugin-meetings', () => {
1807
1807
  assert.calledWith(locusInfo.applyLocusDeltaData, action, parsedLoci, fakeMeeting);
1808
1808
  });
1809
1809
 
1810
+ it('catches errors thrown by onDeltaAction and is able to process next Locus delta', () => {
1811
+ const fakeLocusDelta = {
1812
+ sequence: {
1813
+ rangeStart: 0,
1814
+ rangeEnd: 0,
1815
+ },
1816
+ };
1817
+ locusInfo.locusParser.workingCopy = {
1818
+ sequence: {
1819
+ rangeStart: 0,
1820
+ rangeEnd: 0,
1821
+ },
1822
+ };
1823
+ const testMeeting = {locusInfo: {onDeltaLocus: sinon.stub()}};
1824
+
1825
+ locusParser.onDeltaAction = sandbox
1826
+ .stub()
1827
+ .onCall(0)
1828
+ .callsFake(() => {
1829
+ throw new Error('fake error');
1830
+ });
1831
+
1832
+ // simulate first locus delta coming - it will trigger an error thrown by onDeltaAction
1833
+ locusInfo.handleLocusDelta(fakeLocusDelta, testMeeting);
1834
+
1835
+ // simulate a second locus delta coming - it should be processed without errors
1836
+ locusInfo.handleLocusDelta(fakeLocusDelta, testMeeting);
1837
+ });
1838
+
1810
1839
  it('applyLocusDeltaData handles USE_INCOMING action correctly', () => {
1811
1840
  const {USE_INCOMING} = LocusDeltaParser.loci;
1812
1841
  const meeting = {
@@ -90,13 +90,15 @@ import WebExMeetingsErrors from '../../../../src/common/errors/webex-meetings-er
90
90
  import ParameterError from '../../../../src/common/errors/parameter';
91
91
  import PasswordError from '../../../../src/common/errors/password-error';
92
92
  import CaptchaError from '../../../../src/common/errors/captcha-error';
93
- import PermissionError from '../../../../src/common/errors/permission';
93
+ import PermissionError from '../../../../src/common/errors/permission';
94
+ import WebinarRegistrationError from '../../../../src/common/errors/webinar-registration-error';
94
95
  import IntentToJoinError from '../../../../src/common/errors/intent-to-join';
95
96
  import testUtils from '../../../utils/testUtils';
96
97
  import {
97
98
  MeetingInfoV2CaptchaError,
98
99
  MeetingInfoV2PasswordError,
99
100
  MeetingInfoV2PolicyError,
101
+ MeetingInfoV2WebinarRegistrationError,
100
102
  } from '../../../../src/meeting-info/meeting-info-v2';
101
103
  import {
102
104
  DTLS_HANDSHAKE_FAILED_CLIENT_CODE,
@@ -3991,6 +3993,7 @@ describe('plugin-meetings', () => {
3991
3993
  assert.notCalled(
3992
3994
  meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream
3993
3995
  );
3996
+ assert.throws(meeting.publishStreams(localStreams), `Attempted to publish microphone stream with ended readyState, correlationId=${meeting.correlationId}`);
3994
3997
  } else {
3995
3998
  assert.calledOnceWithExactly(
3996
3999
  meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
@@ -4003,6 +4006,7 @@ describe('plugin-meetings', () => {
4003
4006
  assert.notCalled(
4004
4007
  meeting.sendSlotManager.getSlot(MediaType.VideoMain).publishStream
4005
4008
  );
4009
+ assert.throws(meeting.publishStreams(localStreams), `Attempted to publish camera stream with ended readyState, correlationId=${meeting.correlationId}`);
4006
4010
  } else {
4007
4011
  assert.calledOnceWithExactly(
4008
4012
  meeting.sendSlotManager.getSlot(MediaType.VideoMain).publishStream,
@@ -4015,6 +4019,7 @@ describe('plugin-meetings', () => {
4015
4019
  assert.notCalled(
4016
4020
  meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream
4017
4021
  );
4022
+ assert.throws(meeting.publishStreams(localStreams), `Attempted to publish screenShare audio stream with ended readyState, correlationId=${meeting.correlationId}`);
4018
4023
  } else {
4019
4024
  assert.calledOnceWithExactly(
4020
4025
  meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream,
@@ -4027,6 +4032,7 @@ describe('plugin-meetings', () => {
4027
4032
  assert.notCalled(
4028
4033
  meeting.sendSlotManager.getSlot(MediaType.VideoSlides).publishStream
4029
4034
  );
4035
+ assert.throws(meeting.publishStreams(localStreams), `Attempted to publish screenShare video stream with ended readyState, correlationId=${meeting.correlationId}`);
4030
4036
  } else {
4031
4037
  assert.calledOnceWithExactly(
4032
4038
  meeting.sendSlotManager.getSlot(MediaType.VideoSlides).publishStream,
@@ -6250,6 +6256,22 @@ describe('plugin-meetings', () => {
6250
6256
 
6251
6257
  assert.equal(meeting.fetchMeetingInfoTimeoutId, undefined);
6252
6258
  });
6259
+
6260
+ it('handles meetingInfoProvider webinar need registration error', async () => {
6261
+ meeting.destination = FAKE_DESTINATION;
6262
+ meeting.destinationType = FAKE_TYPE;
6263
+ meeting.attrs.meetingInfoProvider = {
6264
+ fetchMeetingInfo: sinon
6265
+ .stub()
6266
+ .throws(new MeetingInfoV2WebinarRegistrationError(403021, FAKE_MEETING_INFO, 'a message')),
6267
+ };
6268
+
6269
+ await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), WebinarRegistrationError);
6270
+
6271
+ assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
6272
+ assert.equal(meeting.meetingInfoFailureCode, 403021);
6273
+ assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WEBINAR_REGISTRATION);
6274
+ });
6253
6275
  });
6254
6276
 
6255
6277
  describe('#refreshPermissionToken', () => {
@@ -12178,6 +12200,43 @@ describe('plugin-meetings', () => {
12178
12200
  await testEmit(false);
12179
12201
  });
12180
12202
  });
12203
+
12204
+ describe('LOCAL_UNMUTE_REQUIRED locus event', () => {
12205
+ const testEmit = async (unmuteAllowed) => {
12206
+ meeting.audio = {
12207
+ handleServerLocalUnmuteRequired: sinon.stub(),
12208
+ }
12209
+ await meeting.locusInfo.emitScoped(
12210
+ {},
12211
+ LOCUSINFO.EVENTS.LOCAL_UNMUTE_REQUIRED,
12212
+ {
12213
+ unmuteAllowed,
12214
+ }
12215
+ );
12216
+
12217
+ assert.calledWith(
12218
+ TriggerProxy.trigger,
12219
+ sinon.match.instanceOf(Meeting),
12220
+ {
12221
+ file: 'meeting/index',
12222
+ function: 'setUpLocusInfoSelfListener',
12223
+ },
12224
+ EVENT_TRIGGERS.MEETING_SELF_UNMUTED_BY_OTHERS,
12225
+ {
12226
+ payload: {
12227
+ unmuteAllowed,
12228
+ },
12229
+ }
12230
+ );
12231
+ assert.calledOnceWithExactly(meeting.audio.handleServerLocalUnmuteRequired, meeting, unmuteAllowed)
12232
+ };
12233
+
12234
+ [true, false].forEach((unmuteAllowed) => {
12235
+ it(`emits the expected event and calls handleServerLocalUnmuteRequired() when unmuteAllowed=${unmuteAllowed}`, async () => {
12236
+ await testEmit(unmuteAllowed);
12237
+ });
12238
+ });
12239
+ });
12181
12240
  });
12182
12241
  });
12183
12242
 
@@ -151,7 +151,7 @@ describe('plugin-meetings', () => {
151
151
  meeting.mediaProperties.audioStream.setServerMuted = sinon.stub().callsFake((muted) => {
152
152
  meeting.mediaProperties.audioStream.userMuted = muted;
153
153
  });
154
- audio.handleServerLocalUnmuteRequired(meeting);
154
+ audio.handleServerLocalUnmuteRequired(meeting, true);
155
155
 
156
156
  await testUtils.flushPromises();
157
157
 
@@ -161,6 +161,8 @@ describe('plugin-meetings', () => {
161
161
  false,
162
162
  'localUnmuteRequired'
163
163
  );
164
+ // and unmuteAllowed was updated
165
+ assert.calledWith(meeting.mediaProperties.audioStream.setUnmuteAllowed, true);
164
166
 
165
167
  // and local unmute was sent to server
166
168
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
@@ -184,7 +186,7 @@ describe('plugin-meetings', () => {
184
186
  meeting.mediaProperties.audioStream.setServerMuted = sinon.stub().callsFake((muted) => {
185
187
  meeting.mediaProperties.audioStream.userMuted = muted;
186
188
  });
187
- audio.handleServerLocalUnmuteRequired(meeting);
189
+ audio.handleServerLocalUnmuteRequired(meeting, true);
188
190
 
189
191
  await testUtils.flushPromises();
190
192
 
@@ -215,7 +217,7 @@ describe('plugin-meetings', () => {
215
217
  meeting.mediaProperties.videoStream.setServerMuted = sinon.stub().callsFake((muted) => {
216
218
  meeting.mediaProperties.videoStream.userMuted = muted;
217
219
  });
218
- video.handleServerLocalUnmuteRequired(meeting);
220
+ video.handleServerLocalUnmuteRequired(meeting, true);
219
221
 
220
222
  await testUtils.flushPromises();
221
223
 
@@ -225,6 +227,8 @@ describe('plugin-meetings', () => {
225
227
  false,
226
228
  'localUnmuteRequired'
227
229
  );
230
+ // and unmuteAllowed was updated
231
+ assert.calledWith(meeting.mediaProperties.videoStream.setUnmuteAllowed, true);
228
232
 
229
233
  // and local unmute was sent to server
230
234
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
@@ -248,7 +252,7 @@ describe('plugin-meetings', () => {
248
252
  meeting.mediaProperties.videoStream.setServerMuted = sinon.stub().callsFake((muted) => {
249
253
  meeting.mediaProperties.videoStream.userMuted = muted;
250
254
  });
251
- video.handleServerLocalUnmuteRequired(meeting);
255
+ video.handleServerLocalUnmuteRequired(meeting, true);
252
256
 
253
257
  await testUtils.flushPromises();
254
258
 
@@ -18,6 +18,7 @@ import MeetingInfo, {
18
18
  MeetingInfoV2CaptchaError,
19
19
  MeetingInfoV2AdhocMeetingError,
20
20
  MeetingInfoV2PolicyError,
21
+ MeetingInfoV2WebinarRegistrationError,
21
22
  } from '@webex/plugin-meetings/src/meeting-info/meeting-info-v2';
22
23
  import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
23
24
  import Metrics from '@webex/plugin-meetings/src/metrics';
@@ -888,6 +889,42 @@ describe('plugin-meetings', () => {
888
889
  });
889
890
  }
890
891
  );
892
+
893
+ forEach(
894
+ [
895
+ {errorCode: 403021},
896
+ {errorCode: 403022},
897
+ {errorCode: 403024},
898
+ ],
899
+ ({errorCode}) => {
900
+ it(`should throw a MeetingInfoV2WebinarRegistrationError for error code ${errorCode}`, async () => {
901
+ const message = 'a message';
902
+ const meetingInfoData = {meetingInfo: {registrationUrl: 'registrationUrl'}};
903
+
904
+ webex.request = sinon.stub().rejects({
905
+ statusCode: 403,
906
+ body: {message, code: errorCode, data: {meetingInfo: meetingInfoData}},
907
+ });
908
+ try {
909
+ await meetingInfo.createAdhocSpaceMeeting(conversationUrl, installedOrgID);
910
+ assert.fail('createAdhocSpaceMeeting should have thrown, but has not done that');
911
+ } catch (err) {
912
+ assert.instanceOf(err, MeetingInfoV2WebinarRegistrationError);
913
+ assert.deepEqual(err.message, `${message}, code=${errorCode}`);
914
+ assert.equal(err.wbxAppApiCode, errorCode);
915
+ assert.deepEqual(err.meetingInfo, meetingInfoData);
916
+
917
+ assert(Metrics.sendBehavioralMetric.calledOnce);
918
+ assert.calledWith(
919
+ Metrics.sendBehavioralMetric,
920
+ BEHAVIORAL_METRICS.WEBINAR_REGISTRATION_ERROR,
921
+ {code: errorCode}
922
+ );
923
+
924
+ }
925
+ });
926
+ }
927
+ );
891
928
  });
892
929
  });
893
930
  });
@@ -7,7 +7,7 @@ import {RemoteMedia, RemoteMediaEvents} from '@webex/plugin-meetings/src/multist
7
7
  import {ReceiveSlotEvents} from '@webex/plugin-meetings/src/multistream/receiveSlot';
8
8
  import sinon from 'sinon';
9
9
  import {assert} from '@webex/test-helper-chai';
10
- import { forEach } from 'lodash';
10
+ import {forEach} from 'lodash';
11
11
 
12
12
  describe('RemoteMedia', () => {
13
13
  let remoteMedia;
@@ -227,12 +227,26 @@ describe('RemoteMedia', () => {
227
227
  });
228
228
 
229
229
  describe('setSizeHint()', () => {
230
-
231
230
  it('works if the receive slot is undefined', () => {
232
231
  remoteMedia.receiveSlot = undefined;
233
232
  remoteMedia.setSizeHint(100, 100);
234
233
  });
235
234
 
235
+ forEach(
236
+ [
237
+ {width: 0, height: 0},
238
+ {width: 135, height: 0},
239
+ {width: 0, height: 240},
240
+ ],
241
+ ({width, height}) => {
242
+ it(`skip updating the max fs when applied ${width}:${height}`, () => {
243
+ remoteMedia.setSizeHint(width, height);
244
+
245
+ assert.notCalled(fakeReceiveSlot.setMaxFs);
246
+ });
247
+ }
248
+ );
249
+
236
250
  forEach(
237
251
  [
238
252
  {height: 134, fs: 60},