@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.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +25 -1
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +5 -0
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/meeting/index.js +72 -15
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +1 -1
- package/dist/meeting/request.js.map +1 -1
- package/dist/metrics/constants.js +3 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +46 -9
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/meeting/index.d.ts +16 -2
- package/dist/types/meeting/locusMediaRequest.d.ts +1 -2
- package/dist/types/meeting/request.d.ts +2 -1
- package/dist/types/meeting/util.d.ts +9 -1
- package/dist/types/metrics/constants.d.ts +3 -0
- package/dist/types/multistream/remoteMediaManager.d.ts +9 -1
- package/dist/types/reachability/index.d.ts +0 -6
- package/dist/types/reachability/request.d.ts +1 -1
- package/dist/types/roap/request.d.ts +2 -1
- package/package.json +1 -1
- package/src/constants.ts +1 -0
- package/src/locus-info/index.ts +33 -2
- package/src/locus-info/parser.ts +7 -0
- package/src/meeting/index.ts +59 -16
- package/src/meeting/request.ts +1 -1
- package/src/metrics/constants.ts +2 -0
- package/src/multistream/remoteMediaManager.ts +41 -4
- package/test/integration/spec/converged-space-meetings.js +7 -7
- package/test/integration/spec/journey.js +85 -103
- package/test/integration/spec/space-meeting.js +9 -9
- package/test/unit/spec/locus-info/index.js +118 -1
- package/test/unit/spec/meeting/index.js +88 -25
- package/test/unit/spec/meetings/index.js +2 -2
- package/test/unit/spec/multistream/remoteMediaManager.ts +10 -2
- package/test/utils/integrationTestUtils.js +4 -4
package/src/meeting/index.ts
CHANGED
|
@@ -544,7 +544,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
544
544
|
meetingJoinUrl: any;
|
|
545
545
|
meetingNumber: any;
|
|
546
546
|
meetingState: any;
|
|
547
|
-
permissionToken:
|
|
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.
|
|
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
|
-
|
|
3295
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5877
|
-
|
|
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
|
|
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
|
}
|
package/src/meeting/request.ts
CHANGED
package/src/metrics/constants.ts
CHANGED
|
@@ -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
|
|
730
|
+
private logMainVideoReceiveSlots() {
|
|
729
731
|
let logMessage = '';
|
|
730
732
|
forEach(this.receiveSlotAllocations.activeSpeaker, (group, groupName) => {
|
|
731
|
-
logMessage +=
|
|
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#
|
|
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.
|
|
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 {
|
|
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
|
|
157
|
-
localTracks.alice.camera = await
|
|
156
|
+
localTracks.alice.microphone = await createMicrophoneStream();
|
|
157
|
+
localTracks.alice.camera = await createCameraStream();
|
|
158
158
|
|
|
159
|
-
localTracks.bob.microphone = await
|
|
160
|
-
localTracks.bob.camera = await
|
|
159
|
+
localTracks.bob.microphone = await createMicrophoneStream();
|
|
160
|
+
localTracks.bob.camera = await createCameraStream();
|
|
161
161
|
|
|
162
|
-
localTracks.chris.microphone = await
|
|
163
|
-
localTracks.chris.camera = await
|
|
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 () => {
|