@webex/plugin-meetings 3.0.0-stream-classes.4 → 3.0.0-stream-classes.5

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 (44) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/constants.js +3 -1
  4. package/dist/constants.js.map +1 -1
  5. package/dist/interpretation/index.js +1 -1
  6. package/dist/interpretation/siLanguage.js +1 -1
  7. package/dist/locus-info/index.js +25 -1
  8. package/dist/locus-info/index.js.map +1 -1
  9. package/dist/locus-info/parser.js +5 -0
  10. package/dist/locus-info/parser.js.map +1 -1
  11. package/dist/meeting/index.js +72 -15
  12. package/dist/meeting/index.js.map +1 -1
  13. package/dist/meeting/request.js +1 -1
  14. package/dist/meeting/request.js.map +1 -1
  15. package/dist/metrics/constants.js +3 -1
  16. package/dist/metrics/constants.js.map +1 -1
  17. package/dist/multistream/remoteMediaManager.js +46 -9
  18. package/dist/multistream/remoteMediaManager.js.map +1 -1
  19. package/dist/types/constants.d.ts +1 -0
  20. package/dist/types/meeting/index.d.ts +16 -2
  21. package/dist/types/meeting/locusMediaRequest.d.ts +1 -2
  22. package/dist/types/meeting/request.d.ts +2 -1
  23. package/dist/types/meeting/util.d.ts +9 -1
  24. package/dist/types/metrics/constants.d.ts +3 -0
  25. package/dist/types/multistream/remoteMediaManager.d.ts +9 -1
  26. package/dist/types/reachability/index.d.ts +0 -6
  27. package/dist/types/reachability/request.d.ts +1 -1
  28. package/dist/types/roap/request.d.ts +2 -1
  29. package/package.json +1 -1
  30. package/src/constants.ts +1 -0
  31. package/src/locus-info/index.ts +33 -2
  32. package/src/locus-info/parser.ts +7 -0
  33. package/src/meeting/index.ts +59 -16
  34. package/src/meeting/request.ts +1 -1
  35. package/src/metrics/constants.ts +2 -0
  36. package/src/multistream/remoteMediaManager.ts +41 -4
  37. package/test/integration/spec/converged-space-meetings.js +7 -7
  38. package/test/integration/spec/journey.js +85 -103
  39. package/test/integration/spec/space-meeting.js +9 -9
  40. package/test/unit/spec/locus-info/index.js +118 -1
  41. package/test/unit/spec/meeting/index.js +88 -25
  42. package/test/unit/spec/meetings/index.js +2 -2
  43. package/test/unit/spec/multistream/remoteMediaManager.ts +10 -2
  44. package/test/utils/integrationTestUtils.js +4 -4
@@ -544,7 +544,8 @@ export default class Meeting extends StatelessWebexPlugin {
544
544
  meetingJoinUrl: any;
545
545
  meetingNumber: any;
546
546
  meetingState: any;
547
- permissionToken: any;
547
+ permissionToken: string;
548
+ permissionTokenPayload: any;
548
549
  resourceId: any;
549
550
  resourceUrl: string;
550
551
  selfId: string;
@@ -3024,7 +3025,8 @@ export default class Meeting extends StatelessWebexPlugin {
3024
3025
  webexMeetingInfo?.hostId ||
3025
3026
  this.owner;
3026
3027
  this.permissionToken = webexMeetingInfo?.permissionToken;
3027
- this.setSelfUserPolicies(this.permissionToken);
3028
+ this.setPermissionTokenPayload(webexMeetingInfo?.permissionToken);
3029
+ this.setSelfUserPolicies();
3028
3030
  // Need to populate environment when sending CA event
3029
3031
  this.environment = locusMeetingObject?.info.channel || webexMeetingInfo?.channel;
3030
3032
  }
@@ -3288,11 +3290,20 @@ export default class Meeting extends StatelessWebexPlugin {
3288
3290
 
3289
3291
  /**
3290
3292
  * Sets the self user policies based on the contents of the permission token
3293
+ * @returns {void}
3294
+ */
3295
+ setSelfUserPolicies() {
3296
+ this.selfUserPolicies = this.permissionTokenPayload?.permission?.userPolicies;
3297
+ }
3298
+
3299
+ /**
3300
+ * Sets the permission token payload on the class instance
3301
+ *
3291
3302
  * @param {String} permissionToken
3292
3303
  * @returns {void}
3293
3304
  */
3294
- setSelfUserPolicies(permissionToken: string) {
3295
- this.selfUserPolicies = jwt.decode(permissionToken)?.permission?.userPolicies;
3305
+ public setPermissionTokenPayload(permissionToken: string) {
3306
+ this.permissionTokenPayload = jwt.decode(permissionToken);
3296
3307
  }
3297
3308
 
3298
3309
  /**
@@ -5100,7 +5111,9 @@ export default class Meeting extends StatelessWebexPlugin {
5100
5111
  errors: [
5101
5112
  // @ts-ignore
5102
5113
  this.webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode(
5103
- CALL_DIAGNOSTIC_CONFIG.ICE_FAILURE_CLIENT_CODE
5114
+ {
5115
+ clientErrorCode: CALL_DIAGNOSTIC_CONFIG.ICE_FAILURE_CLIENT_CODE,
5116
+ }
5104
5117
  ),
5105
5118
  ],
5106
5119
  },
@@ -5636,7 +5649,9 @@ export default class Meeting extends StatelessWebexPlugin {
5636
5649
  errors: [
5637
5650
  // @ts-ignore
5638
5651
  this.webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode(
5639
- CALL_DIAGNOSTIC_CONFIG.ICE_FAILURE_CLIENT_CODE
5652
+ {
5653
+ clientErrorCode: CALL_DIAGNOSTIC_CONFIG.ICE_FAILURE_CLIENT_CODE,
5654
+ }
5640
5655
  ),
5641
5656
  ],
5642
5657
  },
@@ -5671,8 +5686,16 @@ export default class Meeting extends StatelessWebexPlugin {
5671
5686
  meetingId: this.id,
5672
5687
  },
5673
5688
  });
5689
+ LoggerProxy.logger.info(
5690
+ `${LOG_HEADER} successfully established media connection, type=${connectionType}`
5691
+ );
5692
+
5693
+ // We can log ReceiveSlot SSRCs only after the SDP exchange, so doing it here:
5694
+ this.remoteMediaManager?.logAllReceiveSlots();
5674
5695
  })
5675
5696
  .catch((error) => {
5697
+ LoggerProxy.logger.error(`${LOG_HEADER} failed to establish media connection: `, error);
5698
+
5676
5699
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
5677
5700
  correlation_id: this.correlationId,
5678
5701
  locus_id: this.locusUrl.split('/').pop(),
@@ -5712,11 +5735,6 @@ export default class Meeting extends StatelessWebexPlugin {
5712
5735
  this.unsetPeerConnections();
5713
5736
  }
5714
5737
 
5715
- LoggerProxy.logger.error(
5716
- `${LOG_HEADER} Error adding media failed to initiate PC and send request, `,
5717
- error
5718
- );
5719
-
5720
5738
  // Upload logs on error while adding media
5721
5739
  Trigger.trigger(
5722
5740
  this,
@@ -5872,12 +5890,15 @@ export default class Meeting extends StatelessWebexPlugin {
5872
5890
  return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.UPDATE_MEDIA, options);
5873
5891
  }
5874
5892
 
5875
- if (
5876
- this.isMultistream &&
5877
- (shareAudioEnabled !== undefined || shareVideoEnabled !== undefined)
5878
- ) {
5893
+ if (this.isMultistream) {
5894
+ if (shareAudioEnabled !== undefined || shareVideoEnabled !== undefined) {
5895
+ throw new Error(
5896
+ 'toggling shareAudioEnabled or shareVideoEnabled in a multistream meeting is not supported, to control receiving screen share call meeting.remoteMediaManager.setLayout() with appropriate layout'
5897
+ );
5898
+ }
5899
+ } else if (shareAudioEnabled !== undefined) {
5879
5900
  throw new Error(
5880
- 'toggling shareAudioEnabled or shareVideoEnabled in a multistream meeting is not supported, to control receiving screen share call meeting.remoteMediaManager.setLayout() with appropriate layout'
5901
+ 'toggling shareAudioEnabled in a transcoded meeting is not supported as of now'
5881
5902
  );
5882
5903
  }
5883
5904
 
@@ -7252,4 +7273,26 @@ export default class Meeting extends StatelessWebexPlugin {
7252
7273
  }
7253
7274
  }
7254
7275
  }
7276
+
7277
+ /**
7278
+ * Gets the time left in seconds till the permission token expires
7279
+ * (from the time the function has been fired)
7280
+ *
7281
+ * @returns {number} time left in seconds
7282
+ */
7283
+ public getPermissionTokenTimeLeftInSec(): number | undefined {
7284
+ if (!this.permissionTokenPayload) {
7285
+ return undefined;
7286
+ }
7287
+
7288
+ const permissionTokenExpValue = Number(this.permissionTokenPayload.exp);
7289
+
7290
+ // using new Date instead of Date.now() to allow for accurate unit testing
7291
+ // https://github.com/sinonjs/fake-timers/issues/321
7292
+ const now = new Date().getTime();
7293
+
7294
+ // substract current time from the permissionTokenExp
7295
+ // (permissionTokenExp is a epoch timestamp, not a time to live duration)
7296
+ return (permissionTokenExpValue - now) / 1000;
7297
+ }
7255
7298
  }
@@ -416,7 +416,7 @@ export default class MeetingRequest extends StatelessWebexPlugin {
416
416
  `Meeting:request#getLocusDTO --> Error getting latest locus, error ${err}`
417
417
  );
418
418
 
419
- return err;
419
+ throw err;
420
420
  });
421
421
  }
422
422
 
@@ -55,6 +55,8 @@ const BEHAVIORAL_METRICS = {
55
55
  MOVE_FROM_FAILURE: 'js_sdk_move_from_failure',
56
56
  TURN_DISCOVERY_FAILURE: 'js_sdk_turn_discovery_failure',
57
57
  MEETING_INFO_POLICY_ERROR: 'js_sdk_meeting_info_policy_error',
58
+ LOCUS_DELTA_SYNC_FAILED: 'js_sdk_locus_delta_sync_failed',
59
+ LOCUS_DELTA_OUT_OF_ORDER: 'js_sdk_locus_delta_ooo',
58
60
  };
59
61
 
60
62
  export {BEHAVIORAL_METRICS as default};
@@ -473,6 +473,8 @@ export class RemoteMediaManager extends EventsScope {
473
473
  if (!this.started) {
474
474
  throw new Error('setLayout() called before start()');
475
475
  }
476
+ LoggerProxy.logger.log(`RemoteMediaManager#setLayout --> new layout selected: ${layoutId}`);
477
+
476
478
  this.currentLayoutId = layoutId;
477
479
  this.currentLayout = cloneDeep(this.config.video.layouts[this.currentLayoutId]);
478
480
 
@@ -725,10 +727,12 @@ export class RemoteMediaManager extends EventsScope {
725
727
  /**
726
728
  * Logs the state of the receive slots
727
729
  */
728
- private logReceieveSlots() {
730
+ private logMainVideoReceiveSlots() {
729
731
  let logMessage = '';
730
732
  forEach(this.receiveSlotAllocations.activeSpeaker, (group, groupName) => {
731
- logMessage += `group: ${groupName}\n${group.slots.map((slot) => slot.logString).join(' ')}`;
733
+ logMessage += `\ngroup: ${groupName}\n${group.slots
734
+ .map((slot) => slot.logString)
735
+ .join(', ')}`;
732
736
  });
733
737
 
734
738
  logMessage += '\nreceiverSelected:\n';
@@ -737,10 +741,43 @@ export class RemoteMediaManager extends EventsScope {
737
741
  });
738
742
 
739
743
  LoggerProxy.logger.log(
740
- `RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=${this.slots.video.unused.length}, activeSpeaker=${this.slots.video.activeSpeaker.length}, receiverSelected=${this.slots.video.receiverSelected.length}\n${logMessage}`
744
+ `RemoteMediaManager#logMainVideoReceiveSlots --> MAIN VIDEO receive slots: unused=${this.slots.video.unused.length}, activeSpeaker=${this.slots.video.activeSpeaker.length}, receiverSelected=${this.slots.video.receiverSelected.length}${logMessage}`
745
+ );
746
+ }
747
+
748
+ /** logs main audio slots */
749
+ private logMainAudioReceiveSlots() {
750
+ LoggerProxy.logger.log(
751
+ `RemoteMediaManager#logMainAudioReceiveSlots --> MAIN AUDIO receive slots: ${this.slots.audio
752
+ .map((slot) => slot.logString)
753
+ .join(', ')}`
741
754
  );
742
755
  }
743
756
 
757
+ /** logs slides video slots */
758
+ private logSlidesVideoReceiveSlots() {
759
+ LoggerProxy.logger.log(
760
+ `RemoteMediaManager#logSlidesVideoReceiveSlots --> SLIDES VIDEO receive slot: ${this.slots.screenShare.video?.logString}`
761
+ );
762
+ }
763
+
764
+ /** logs slides audio slots */
765
+ private logSlidesAudioReceiveSlots() {
766
+ LoggerProxy.logger.log(
767
+ `RemoteMediaManager#logSlidesAudioReceiveSlots --> SLIDES AUDIO receive slots: ${this.slots.screenShare.audio
768
+ .map((slot) => slot.logString)
769
+ .join(', ')}`
770
+ );
771
+ }
772
+
773
+ /** Logs all current receive slots */
774
+ public logAllReceiveSlots() {
775
+ this.logMainVideoReceiveSlots();
776
+ this.logMainAudioReceiveSlots();
777
+ this.logSlidesVideoReceiveSlots();
778
+ this.logSlidesAudioReceiveSlots();
779
+ }
780
+
744
781
  /**
745
782
  * Makes sure we have the right number of receive slots created for the current layout
746
783
  * and allocates them to the right video panes / pane groups
@@ -765,7 +802,7 @@ export class RemoteMediaManager extends EventsScope {
765
802
  // allocate receiver selected
766
803
  this.allocateSlotsToReceiverSelectedVideoPaneGroups();
767
804
 
768
- this.logReceieveSlots();
805
+ this.logMainVideoReceiveSlots();
769
806
 
770
807
  // If this is the initial layout, there may be some "unused" slots left because of the preallocation
771
808
  // done in this.preallocateVideoReceiveSlots(), so release them now
@@ -3,7 +3,7 @@ import 'jsdom-global/register';
3
3
  import {assert} from '@webex/test-helper-chai';
4
4
  import {skipInNode} from '@webex/test-helper-mocha';
5
5
  import BrowserDetection from '@webex/plugin-meetings/dist/common/browser-detection';
6
- import {createCameraTrack, createMicrophoneTrack} from '@webex/plugin-meetings';
6
+ import {createCameraStream, createMicrophoneStream} from '@webex/plugin-meetings';
7
7
 
8
8
  import {MEDIA_SERVERS} from '../../utils/constants';
9
9
  import testUtils from '../../utils/testUtils';
@@ -153,14 +153,14 @@ skipInNode(describe)('plugin-meetings', () => {
153
153
  });
154
154
 
155
155
  it('users "alice", "bob", and "chris" create local tracks', async () => {
156
- localTracks.alice.microphone = await createMicrophoneTrack();
157
- localTracks.alice.camera = await createCameraTrack();
156
+ localTracks.alice.microphone = await createMicrophoneStream();
157
+ localTracks.alice.camera = await createCameraStream();
158
158
 
159
- localTracks.bob.microphone = await createMicrophoneTrack();
160
- localTracks.bob.camera = await createCameraTrack();
159
+ localTracks.bob.microphone = await createMicrophoneStream();
160
+ localTracks.bob.camera = await createCameraStream();
161
161
 
162
- localTracks.chris.microphone = await createMicrophoneTrack();
163
- localTracks.chris.camera = await createCameraTrack();
162
+ localTracks.chris.microphone = await createMicrophoneStream();
163
+ localTracks.chris.camera = await createCameraStream();
164
164
  });
165
165
 
166
166
  it('users "alice", "bob", and "chris" add media', async () => {