@webex/plugin-meetings 3.0.0-bnr.4 → 3.0.0-stream-classes.1
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/README.md +46 -8
- package/dist/annotation/annotation.types.js +7 -0
- package/dist/annotation/annotation.types.js.map +1 -0
- package/dist/annotation/constants.js +49 -0
- package/dist/annotation/constants.js.map +1 -0
- package/dist/annotation/index.js +342 -0
- package/dist/annotation/index.js.map +1 -0
- package/dist/breakouts/breakout.js +70 -32
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/events.js +45 -0
- package/dist/breakouts/events.js.map +1 -0
- package/dist/breakouts/index.js +422 -217
- package/dist/breakouts/index.js.map +1 -1
- package/dist/breakouts/utils.js +12 -1
- package/dist/breakouts/utils.js.map +1 -1
- package/dist/common/errors/webex-errors.js +3 -2
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/logs/logger-proxy.js +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.d.ts +1 -1
- package/dist/common/queue.js +24 -9
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +1 -7
- package/dist/config.js.map +1 -1
- package/dist/constants.js +118 -24
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js +2 -0
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +19 -14
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/types.js.map +1 -1
- package/dist/controls-options-manager/util.js +80 -11
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/index.js +62 -20
- package/dist/index.js.map +1 -1
- package/dist/interpretation/collection.js +23 -0
- package/dist/interpretation/collection.js.map +1 -0
- package/dist/interpretation/index.js +366 -0
- package/dist/interpretation/index.js.map +1 -0
- package/dist/interpretation/siLanguage.js +25 -0
- package/dist/interpretation/siLanguage.js.map +1 -0
- package/dist/locus-info/controlsUtils.js +71 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +305 -57
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js +7 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js +43 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +219 -63
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js +44 -22
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +57 -104
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +60 -121
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +61 -3
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +2530 -2534
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +292 -0
- package/dist/meeting/locusMediaRequest.js.map +1 -0
- package/dist/meeting/muteState.js +125 -205
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +150 -150
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +568 -438
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/index.js +48 -7
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +94 -38
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +4 -2
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/index.d.ts +0 -2
- package/dist/meetings/index.js +260 -85
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js +7 -0
- package/dist/meetings/meetings.types.js.map +1 -0
- package/dist/meetings/util.js +42 -7
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.d.ts +2 -0
- package/dist/member/index.js +26 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/member.types.d.ts +11 -0
- package/dist/member/member.types.js +18 -0
- package/dist/member/member.types.js.map +1 -0
- package/dist/member/types.js +11 -1
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js +60 -23
- package/dist/member/util.js.map +1 -1
- package/dist/members/index.js +4 -1
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +75 -45
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js +308 -317
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/config.js +1 -3
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/constants.js +1 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.d.ts +1 -1
- package/dist/metrics/index.js +1 -451
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +136 -40
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +4 -4
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +60 -3
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +36 -0
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +233 -0
- package/dist/multistream/sendSlotManager.js.map +1 -0
- package/dist/reachability/index.js +18 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +5 -3
- package/dist/reachability/request.js.map +1 -1
- package/dist/reconnection-manager/index.js +181 -153
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/index.js +21 -2
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js +9 -8
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +25 -32
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +42 -51
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +97 -38
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/rtcMetrics/constants.js +12 -0
- package/dist/rtcMetrics/constants.js.map +1 -0
- package/dist/rtcMetrics/index.js +117 -0
- package/dist/rtcMetrics/index.js.map +1 -0
- package/dist/statsAnalyzer/index.js +0 -1
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/types/annotation/annotation.types.d.ts +43 -0
- package/dist/types/annotation/constants.d.ts +31 -0
- package/dist/types/annotation/index.d.ts +124 -0
- package/dist/types/breakouts/events.d.ts +2 -0
- package/dist/types/breakouts/utils.d.ts +7 -0
- package/dist/types/common/errors/webex-errors.d.ts +1 -1
- package/dist/types/config.d.ts +0 -6
- package/dist/types/constants.d.ts +51 -21
- package/dist/types/controls-options-manager/enums.d.ts +2 -0
- package/dist/types/controls-options-manager/index.d.ts +1 -1
- package/dist/types/controls-options-manager/types.d.ts +7 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/interpretation/collection.d.ts +5 -0
- package/dist/types/interpretation/index.d.ts +5 -0
- package/dist/types/interpretation/siLanguage.d.ts +5 -0
- package/dist/types/locus-info/index.d.ts +39 -1
- package/dist/types/media/index.d.ts +2 -0
- package/dist/types/media/properties.d.ts +16 -38
- package/dist/types/meeting/in-meeting-actions.d.ts +46 -2
- package/dist/types/meeting/index.d.ts +179 -379
- package/dist/types/meeting/locusMediaRequest.d.ts +70 -0
- package/dist/types/meeting/muteState.d.ts +39 -40
- package/dist/types/meeting/request.d.ts +25 -26
- package/dist/types/meeting/util.d.ts +74 -1
- package/dist/types/meeting-info/meeting-info-v2.d.ts +14 -3
- package/dist/types/meetings/index.d.ts +49 -1
- package/dist/types/meetings/meetings.types.d.ts +4 -0
- package/dist/types/member/index.d.ts +2 -0
- package/dist/types/members/request.d.ts +56 -11
- package/dist/types/members/util.d.ts +209 -1
- package/dist/types/metrics/config.d.ts +26 -2
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/types/metrics/index.d.ts +17 -0
- package/dist/types/multistream/mediaRequestManager.d.ts +27 -10
- package/dist/types/multistream/receiveSlot.d.ts +3 -3
- package/dist/types/multistream/remoteMedia.d.ts +2 -2
- package/dist/types/multistream/remoteMediaManager.d.ts +14 -0
- package/dist/types/roap/request.d.ts +6 -8
- package/dist/types/roap/turnDiscovery.d.ts +18 -1
- package/package.json +3 -2
- package/src/annotation/annotation.types.ts +50 -0
- package/src/annotation/constants.ts +36 -0
- package/src/annotation/index.ts +328 -0
- package/src/breakouts/README.md +3 -2
- package/src/breakouts/breakout.ts +62 -27
- package/src/breakouts/events.ts +56 -0
- package/src/breakouts/index.ts +244 -64
- package/src/breakouts/utils.ts +13 -0
- package/src/common/errors/webex-errors.ts +6 -2
- package/src/common/logs/logger-proxy.ts +1 -1
- package/src/common/queue.ts +22 -8
- package/src/config.ts +0 -6
- package/src/constants.ts +111 -19
- package/src/controls-options-manager/enums.ts +2 -0
- package/src/controls-options-manager/index.ts +13 -10
- package/src/controls-options-manager/types.ts +10 -0
- package/src/controls-options-manager/util.ts +82 -11
- package/src/index.ts +18 -11
- package/src/interpretation/README.md +60 -0
- package/src/interpretation/collection.ts +19 -0
- package/src/interpretation/index.ts +332 -0
- package/src/interpretation/siLanguage.ts +18 -0
- package/src/locus-info/controlsUtils.ts +81 -0
- package/src/locus-info/index.ts +318 -57
- package/src/locus-info/infoUtils.ts +10 -2
- package/src/locus-info/mediaSharesUtils.ts +48 -0
- package/src/locus-info/parser.ts +224 -39
- package/src/locus-info/selfUtils.ts +32 -20
- package/src/media/index.ts +94 -108
- package/src/media/properties.ts +69 -109
- package/src/meeting/in-meeting-actions.ts +120 -4
- package/src/meeting/index.ts +1967 -2120
- package/src/meeting/locusMediaRequest.ts +314 -0
- package/src/meeting/muteState.ts +119 -194
- package/src/meeting/request.ts +122 -115
- package/src/meeting/util.ts +549 -413
- package/src/meeting-info/index.ts +54 -8
- package/src/meeting-info/meeting-info-v2.ts +89 -24
- package/src/meeting-info/utilv2.ts +6 -2
- package/src/meetings/index.ts +247 -87
- package/src/meetings/meetings.types.ts +12 -0
- package/src/meetings/util.ts +47 -12
- package/src/member/index.ts +28 -1
- package/src/member/types.ts +14 -0
- package/src/member/util.ts +75 -26
- package/src/members/index.ts +7 -1
- package/src/members/request.ts +61 -21
- package/src/members/util.ts +316 -326
- package/src/metrics/constants.ts +1 -0
- package/src/metrics/index.ts +1 -474
- package/src/multistream/mediaRequestManager.ts +183 -67
- package/src/multistream/receiveSlot.ts +4 -4
- package/src/multistream/receiveSlotManager.ts +4 -4
- package/src/multistream/remoteMedia.ts +2 -2
- package/src/multistream/remoteMediaGroup.ts +59 -0
- package/src/multistream/remoteMediaManager.ts +33 -0
- package/src/multistream/sendSlotManager.ts +170 -0
- package/src/reachability/index.ts +15 -4
- package/src/reachability/request.ts +7 -3
- package/src/reconnection-manager/index.ts +36 -29
- package/src/recording-controller/index.ts +20 -3
- package/src/recording-controller/util.ts +26 -9
- package/src/roap/index.ts +25 -30
- package/src/roap/request.ts +44 -51
- package/src/roap/turnDiscovery.ts +51 -25
- package/src/rtcMetrics/constants.ts +3 -0
- package/src/rtcMetrics/index.ts +100 -0
- package/src/statsAnalyzer/index.ts +0 -1
- package/test/integration/spec/converged-space-meetings.js +60 -3
- package/test/integration/spec/journey.js +336 -259
- package/test/integration/spec/space-meeting.js +76 -3
- package/test/unit/spec/annotation/index.ts +418 -0
- package/test/unit/spec/breakouts/breakout.ts +85 -26
- package/test/unit/spec/breakouts/events.ts +89 -0
- package/test/unit/spec/breakouts/index.ts +636 -98
- package/test/unit/spec/breakouts/utils.js +19 -1
- package/test/unit/spec/common/queue.js +31 -2
- package/test/unit/spec/controls-options-manager/index.js +8 -1
- package/test/unit/spec/controls-options-manager/util.js +576 -397
- package/test/unit/spec/fixture/locus.js +1 -0
- package/test/unit/spec/interpretation/collection.ts +15 -0
- package/test/unit/spec/interpretation/index.ts +589 -0
- package/test/unit/spec/interpretation/siLanguage.ts +28 -0
- package/test/unit/spec/locus-info/controlsUtils.js +195 -1
- package/test/unit/spec/locus-info/index.js +950 -45
- package/test/unit/spec/locus-info/infoUtils.js +37 -15
- package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
- package/test/unit/spec/locus-info/parser.js +62 -22
- package/test/unit/spec/locus-info/selfConstant.js +19 -0
- package/test/unit/spec/locus-info/selfUtils.js +131 -26
- package/test/unit/spec/media/index.ts +82 -79
- package/test/unit/spec/meeting/in-meeting-actions.ts +60 -2
- package/test/unit/spec/meeting/index.js +3208 -1734
- package/test/unit/spec/meeting/locusMediaRequest.ts +443 -0
- package/test/unit/spec/meeting/muteState.js +328 -417
- package/test/unit/spec/meeting/request.js +393 -48
- package/test/unit/spec/meeting/utils.js +552 -76
- package/test/unit/spec/meeting-info/index.js +181 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +258 -20
- package/test/unit/spec/meeting-info/utilv2.js +21 -0
- package/test/unit/spec/meetings/index.js +631 -145
- package/test/unit/spec/meetings/utils.js +164 -9
- package/test/unit/spec/member/index.js +44 -14
- package/test/unit/spec/member/util.js +296 -155
- package/test/unit/spec/members/index.js +23 -3
- package/test/unit/spec/members/request.js +167 -35
- package/test/unit/spec/metrics/index.js +1 -50
- package/test/unit/spec/multistream/mediaRequestManager.ts +366 -8
- package/test/unit/spec/multistream/receiveSlot.ts +1 -1
- package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
- package/test/unit/spec/multistream/remoteMediaManager.ts +123 -0
- package/test/unit/spec/multistream/sendSlotManager.ts +242 -0
- package/test/unit/spec/reachability/index.ts +66 -5
- package/test/unit/spec/reachability/request.js +3 -1
- package/test/unit/spec/reconnection-manager/index.js +55 -5
- package/test/unit/spec/recording-controller/index.js +294 -218
- package/test/unit/spec/recording-controller/util.js +223 -96
- package/test/unit/spec/roap/index.ts +21 -48
- package/test/unit/spec/roap/request.ts +74 -60
- package/test/unit/spec/roap/turnDiscovery.ts +30 -6
- package/test/unit/spec/rtcMetrics/index.ts +68 -0
- package/test/utils/integrationTestUtils.js +46 -0
- package/test/utils/testUtils.js +0 -60
- package/src/metrics/config.ts +0 -487
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable require-jsdoc */
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
StreamRequest,
|
|
4
4
|
Policy,
|
|
5
5
|
ActiveSpeakerInfo,
|
|
6
6
|
ReceiverSelectedInfo,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getRecommendedMaxBitrateForFrameSize,
|
|
10
10
|
RecommendedOpusBitrates,
|
|
11
11
|
} from '@webex/internal-media-core';
|
|
12
|
-
import {
|
|
12
|
+
import {cloneDeepWith, debounce, isEmpty} from 'lodash';
|
|
13
13
|
|
|
14
14
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
15
15
|
|
|
@@ -47,6 +47,7 @@ export interface MediaRequest {
|
|
|
47
47
|
receiveSlots: Array<ReceiveSlot>;
|
|
48
48
|
codecInfo?: CodecInfo;
|
|
49
49
|
preferredMaxFs?: number;
|
|
50
|
+
handleMaxFs?: ({maxFs}: {maxFs: number}) => void;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
export type MediaRequestId = string;
|
|
@@ -65,13 +66,17 @@ type DegradationPreferences = {
|
|
|
65
66
|
maxMacroblocksLimit: number;
|
|
66
67
|
};
|
|
67
68
|
|
|
68
|
-
type SendMediaRequestsCallback = (
|
|
69
|
+
type SendMediaRequestsCallback = (streamRequests: StreamRequest[]) => void;
|
|
69
70
|
type Kind = 'audio' | 'video';
|
|
70
71
|
|
|
71
72
|
type Options = {
|
|
72
73
|
degradationPreferences: DegradationPreferences;
|
|
73
74
|
kind: Kind;
|
|
75
|
+
trimRequestsToNumOfSources: boolean; // if enabled, AS speaker requests will be trimmed based on the calls to setNumCurrentSources()
|
|
74
76
|
};
|
|
77
|
+
|
|
78
|
+
type ClientRequestsMap = {[key: MediaRequestId]: MediaRequest};
|
|
79
|
+
|
|
75
80
|
export class MediaRequestManager {
|
|
76
81
|
private sendMediaRequestsCallback: SendMediaRequestsCallback;
|
|
77
82
|
|
|
@@ -79,7 +84,7 @@ export class MediaRequestManager {
|
|
|
79
84
|
|
|
80
85
|
private counter: number;
|
|
81
86
|
|
|
82
|
-
private clientRequests:
|
|
87
|
+
private clientRequests: ClientRequestsMap;
|
|
83
88
|
|
|
84
89
|
private degradationPreferences: DegradationPreferences;
|
|
85
90
|
|
|
@@ -87,14 +92,21 @@ export class MediaRequestManager {
|
|
|
87
92
|
|
|
88
93
|
private debouncedSourceUpdateListener: () => void;
|
|
89
94
|
|
|
90
|
-
private
|
|
95
|
+
private previousStreamRequests: Array<StreamRequest> = [];
|
|
96
|
+
|
|
97
|
+
private trimRequestsToNumOfSources: boolean;
|
|
98
|
+
private numTotalSources: number;
|
|
99
|
+
private numLiveSources: number;
|
|
91
100
|
|
|
92
101
|
constructor(sendMediaRequestsCallback: SendMediaRequestsCallback, options: Options) {
|
|
93
102
|
this.sendMediaRequestsCallback = sendMediaRequestsCallback;
|
|
94
103
|
this.counter = 0;
|
|
104
|
+
this.numLiveSources = 0;
|
|
105
|
+
this.numTotalSources = 0;
|
|
95
106
|
this.clientRequests = {};
|
|
96
107
|
this.degradationPreferences = options.degradationPreferences;
|
|
97
108
|
this.kind = options.kind;
|
|
109
|
+
this.trimRequestsToNumOfSources = options.trimRequestsToNumOfSources;
|
|
98
110
|
this.sourceUpdateListener = this.commit.bind(this);
|
|
99
111
|
this.debouncedSourceUpdateListener = debounce(
|
|
100
112
|
this.sourceUpdateListener,
|
|
@@ -107,8 +119,7 @@ export class MediaRequestManager {
|
|
|
107
119
|
this.sendRequests(); // re-send requests after preferences are set
|
|
108
120
|
}
|
|
109
121
|
|
|
110
|
-
private getDegradedClientRequests() {
|
|
111
|
-
const clientRequests = cloneDeep(this.clientRequests);
|
|
122
|
+
private getDegradedClientRequests(clientRequests: ClientRequestsMap) {
|
|
112
123
|
const maxFsLimits = [
|
|
113
124
|
getMaxFs('best'),
|
|
114
125
|
getMaxFs('large'),
|
|
@@ -121,7 +132,7 @@ export class MediaRequestManager {
|
|
|
121
132
|
// reduce max-fs until total macroblocks is below limit
|
|
122
133
|
for (let i = 0; i < maxFsLimits.length; i += 1) {
|
|
123
134
|
let totalMacroblocksRequested = 0;
|
|
124
|
-
Object.
|
|
135
|
+
Object.values(clientRequests).forEach((mr) => {
|
|
125
136
|
if (mr.codecInfo) {
|
|
126
137
|
mr.codecInfo.maxFs = Math.min(
|
|
127
138
|
mr.preferredMaxFs || CODEC_DEFAULTS.h264.maxFs,
|
|
@@ -129,9 +140,7 @@ export class MediaRequestManager {
|
|
|
129
140
|
maxFsLimits[i]
|
|
130
141
|
);
|
|
131
142
|
// we only consider sources with "live" state
|
|
132
|
-
const slotsWithLiveSource =
|
|
133
|
-
(rs) => rs.sourceState === 'live'
|
|
134
|
-
);
|
|
143
|
+
const slotsWithLiveSource = mr.receiveSlots.filter((rs) => rs.sourceState === 'live');
|
|
135
144
|
totalMacroblocksRequested += mr.codecInfo.maxFs * slotsWithLiveSource.length;
|
|
136
145
|
}
|
|
137
146
|
});
|
|
@@ -148,37 +157,35 @@ export class MediaRequestManager {
|
|
|
148
157
|
);
|
|
149
158
|
}
|
|
150
159
|
}
|
|
151
|
-
|
|
152
|
-
return clientRequests;
|
|
153
160
|
}
|
|
154
161
|
|
|
155
162
|
/**
|
|
156
|
-
* Returns true if two
|
|
163
|
+
* Returns true if two stream requests are the same, false otherwise.
|
|
157
164
|
*
|
|
158
|
-
* @param {
|
|
159
|
-
* @param {
|
|
165
|
+
* @param {StreamRequest} streamRequestA - Stream request A for comparison.
|
|
166
|
+
* @param {StreamRequest} streamRequestB - Stream request B for comparison.
|
|
160
167
|
* @returns {boolean} - Whether they are equal.
|
|
161
168
|
*/
|
|
162
169
|
// eslint-disable-next-line class-methods-use-this
|
|
163
|
-
public isEqual(
|
|
170
|
+
public isEqual(streamRequestA: StreamRequest, streamRequestB: StreamRequest) {
|
|
164
171
|
return (
|
|
165
|
-
JSON.stringify(
|
|
166
|
-
JSON.stringify(
|
|
172
|
+
JSON.stringify(streamRequestA._toJmpStreamRequest()) ===
|
|
173
|
+
JSON.stringify(streamRequestB._toJmpStreamRequest())
|
|
167
174
|
);
|
|
168
175
|
}
|
|
169
176
|
|
|
170
177
|
/**
|
|
171
|
-
* Compares new
|
|
178
|
+
* Compares new stream requests to previous ones and determines
|
|
172
179
|
* if they are the same.
|
|
173
180
|
*
|
|
174
|
-
* @param {
|
|
181
|
+
* @param {StreamRequest[]} newRequests - Array with new requests.
|
|
175
182
|
* @returns {boolean} - True if they are equal, false otherwise.
|
|
176
183
|
*/
|
|
177
|
-
private checkIsNewRequestsEqualToPrev(newRequests:
|
|
184
|
+
private checkIsNewRequestsEqualToPrev(newRequests: StreamRequest[]) {
|
|
178
185
|
return (
|
|
179
|
-
!isEmpty(this.
|
|
180
|
-
this.
|
|
181
|
-
this.
|
|
186
|
+
!isEmpty(this.previousStreamRequests) &&
|
|
187
|
+
this.previousStreamRequests.length === newRequests.length &&
|
|
188
|
+
this.previousStreamRequests.every((req, idx) => this.isEqual(req, newRequests[idx]))
|
|
182
189
|
);
|
|
183
190
|
}
|
|
184
191
|
|
|
@@ -222,57 +229,151 @@ export class MediaRequestManager {
|
|
|
222
229
|
}
|
|
223
230
|
|
|
224
231
|
/**
|
|
225
|
-
* Clears the previous
|
|
232
|
+
* Clears the previous stream requests.
|
|
226
233
|
*
|
|
227
234
|
* @returns {void}
|
|
228
235
|
*/
|
|
229
236
|
public clearPreviousRequests(): void {
|
|
230
|
-
this.
|
|
237
|
+
this.previousStreamRequests = [];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Modifies the passed in clientRequests and makes sure that in total they don't ask
|
|
241
|
+
* for more streams than there are available.
|
|
242
|
+
*
|
|
243
|
+
* @param {Object} clientRequests
|
|
244
|
+
* @returns {void}
|
|
245
|
+
*/
|
|
246
|
+
private trimRequests(clientRequests: ClientRequestsMap) {
|
|
247
|
+
const preferLiveVideo = this.getPreferLiveVideo();
|
|
248
|
+
|
|
249
|
+
if (!this.trimRequestsToNumOfSources) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// preferLiveVideo being undefined means that there are no active-speaker requests so we don't need to do any trimming
|
|
254
|
+
if (preferLiveVideo === undefined) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
let numStreamsAvailable = preferLiveVideo ? this.numLiveSources : this.numTotalSources;
|
|
259
|
+
|
|
260
|
+
Object.values(clientRequests)
|
|
261
|
+
.sort((a, b) => {
|
|
262
|
+
// we have to count how many streams we're asking for
|
|
263
|
+
// and should not ask for more than numStreamsAvailable in total,
|
|
264
|
+
// so we might need to trim active-speaker requests and first ones to trim should be
|
|
265
|
+
// the ones with lowest priority
|
|
266
|
+
|
|
267
|
+
// receiver-selected requests have priority over active-speakers
|
|
268
|
+
if (a.policyInfo.policy === 'receiver-selected') {
|
|
269
|
+
return -1;
|
|
270
|
+
}
|
|
271
|
+
if (b.policyInfo.policy === 'receiver-selected') {
|
|
272
|
+
return 1;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// and active-speakers are sorted by descending priority
|
|
276
|
+
return b.policyInfo.priority - a.policyInfo.priority;
|
|
277
|
+
})
|
|
278
|
+
.forEach((request) => {
|
|
279
|
+
// we only trim active-speaker requests
|
|
280
|
+
if (request.policyInfo.policy === 'active-speaker') {
|
|
281
|
+
const trimmedCount = Math.min(numStreamsAvailable, request.receiveSlots.length);
|
|
282
|
+
|
|
283
|
+
request.receiveSlots.length = trimmedCount;
|
|
284
|
+
|
|
285
|
+
numStreamsAvailable -= trimmedCount;
|
|
286
|
+
} else {
|
|
287
|
+
numStreamsAvailable -= request.receiveSlots.length;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (numStreamsAvailable < 0) {
|
|
291
|
+
numStreamsAvailable = 0;
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private getPreferLiveVideo(): boolean | undefined {
|
|
297
|
+
let preferLiveVideo;
|
|
298
|
+
|
|
299
|
+
Object.values(this.clientRequests).forEach((mr) => {
|
|
300
|
+
if (mr.policyInfo.policy === 'active-speaker') {
|
|
301
|
+
// take the value from first encountered active speaker request
|
|
302
|
+
if (preferLiveVideo === undefined) {
|
|
303
|
+
preferLiveVideo = mr.policyInfo.preferLiveVideo;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (mr.policyInfo.preferLiveVideo !== preferLiveVideo) {
|
|
307
|
+
throw new Error(
|
|
308
|
+
'a mix of active-speaker groups with different values for preferLiveVideo is not supported'
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
return preferLiveVideo;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private cloneClientRequests(): ClientRequestsMap {
|
|
318
|
+
// we clone the client requests but without cloning the ReceiveSlots that they reference
|
|
319
|
+
return cloneDeepWith(this.clientRequests, (value, key) => {
|
|
320
|
+
if (key === 'receiveSlots') {
|
|
321
|
+
return [...value];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return undefined;
|
|
325
|
+
});
|
|
231
326
|
}
|
|
232
327
|
|
|
233
328
|
private sendRequests() {
|
|
234
|
-
const
|
|
329
|
+
const streamRequests: StreamRequest[] = [];
|
|
330
|
+
|
|
331
|
+
// clone the requests so that any modifications we do to them don't affect the original ones
|
|
332
|
+
const clientRequests = this.cloneClientRequests();
|
|
235
333
|
|
|
236
|
-
|
|
334
|
+
this.trimRequests(clientRequests);
|
|
335
|
+
this.getDegradedClientRequests(clientRequests);
|
|
237
336
|
|
|
238
|
-
// map all the client media requests to wcme
|
|
337
|
+
// map all the client media requests to wcme stream requests
|
|
239
338
|
Object.values(clientRequests).forEach((mr) => {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
339
|
+
if (mr.receiveSlots.length > 0) {
|
|
340
|
+
streamRequests.push(
|
|
341
|
+
new StreamRequest(
|
|
342
|
+
mr.policyInfo.policy === 'active-speaker'
|
|
343
|
+
? Policy.ActiveSpeaker
|
|
344
|
+
: Policy.ReceiverSelected,
|
|
345
|
+
mr.policyInfo.policy === 'active-speaker'
|
|
346
|
+
? new ActiveSpeakerInfo(
|
|
347
|
+
mr.policyInfo.priority,
|
|
348
|
+
mr.policyInfo.crossPriorityDuplication,
|
|
349
|
+
mr.policyInfo.crossPolicyDuplication,
|
|
350
|
+
mr.policyInfo.preferLiveVideo
|
|
351
|
+
)
|
|
352
|
+
: new ReceiverSelectedInfo(mr.policyInfo.csi),
|
|
353
|
+
mr.receiveSlots.map((receiveSlot) => receiveSlot.wcmeReceiveSlot),
|
|
354
|
+
this.getMaxPayloadBitsPerSecond(mr),
|
|
355
|
+
mr.codecInfo && [
|
|
356
|
+
new WcmeCodecInfo(
|
|
357
|
+
0x80,
|
|
358
|
+
new H264Codec(
|
|
359
|
+
mr.codecInfo.maxFs,
|
|
360
|
+
mr.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps,
|
|
361
|
+
this.getH264MaxMbps(mr),
|
|
362
|
+
mr.codecInfo.maxWidth,
|
|
363
|
+
mr.codecInfo.maxHeight
|
|
364
|
+
)
|
|
365
|
+
),
|
|
366
|
+
]
|
|
367
|
+
)
|
|
368
|
+
);
|
|
369
|
+
}
|
|
269
370
|
});
|
|
270
371
|
|
|
271
372
|
//! IMPORTANT: this is only a temporary fix. This will soon be done in the jmp layer (@webex/json-multistream)
|
|
272
373
|
// https://jira-eng-gpk2.cisco.com/jira/browse/WEBEX-326713
|
|
273
|
-
if (!this.checkIsNewRequestsEqualToPrev(
|
|
274
|
-
this.sendMediaRequestsCallback(
|
|
275
|
-
this.
|
|
374
|
+
if (!this.checkIsNewRequestsEqualToPrev(streamRequests)) {
|
|
375
|
+
this.sendMediaRequestsCallback(streamRequests);
|
|
376
|
+
this.previousStreamRequests = streamRequests;
|
|
276
377
|
LoggerProxy.logger.info(`multistream:sendRequests --> media requests sent. `);
|
|
277
378
|
} else {
|
|
278
379
|
LoggerProxy.logger.info(
|
|
@@ -287,12 +388,15 @@ export class MediaRequestManager {
|
|
|
287
388
|
|
|
288
389
|
this.clientRequests[newId] = mediaRequest;
|
|
289
390
|
|
|
391
|
+
const eventHandler = ({maxFs}) => {
|
|
392
|
+
mediaRequest.preferredMaxFs = maxFs;
|
|
393
|
+
this.debouncedSourceUpdateListener();
|
|
394
|
+
};
|
|
395
|
+
mediaRequest.handleMaxFs = eventHandler;
|
|
396
|
+
|
|
290
397
|
mediaRequest.receiveSlots.forEach((rs) => {
|
|
291
398
|
rs.on(ReceiveSlotEvents.SourceUpdate, this.sourceUpdateListener);
|
|
292
|
-
rs.on(ReceiveSlotEvents.MaxFsUpdate,
|
|
293
|
-
mediaRequest.preferredMaxFs = maxFs;
|
|
294
|
-
this.debouncedSourceUpdateListener();
|
|
295
|
-
});
|
|
399
|
+
rs.on(ReceiveSlotEvents.MaxFsUpdate, mediaRequest.handleMaxFs);
|
|
296
400
|
});
|
|
297
401
|
|
|
298
402
|
if (commit) {
|
|
@@ -303,8 +407,11 @@ export class MediaRequestManager {
|
|
|
303
407
|
}
|
|
304
408
|
|
|
305
409
|
public cancelRequest(requestId: MediaRequestId, commit = true) {
|
|
306
|
-
this.clientRequests[requestId]
|
|
410
|
+
const mediaRequest = this.clientRequests[requestId];
|
|
411
|
+
|
|
412
|
+
mediaRequest?.receiveSlots.forEach((rs) => {
|
|
307
413
|
rs.off(ReceiveSlotEvents.SourceUpdate, this.sourceUpdateListener);
|
|
414
|
+
rs.off(ReceiveSlotEvents.MaxFsUpdate, mediaRequest.handleMaxFs);
|
|
308
415
|
});
|
|
309
416
|
|
|
310
417
|
delete this.clientRequests[requestId];
|
|
@@ -320,5 +427,14 @@ export class MediaRequestManager {
|
|
|
320
427
|
|
|
321
428
|
public reset() {
|
|
322
429
|
this.clientRequests = {};
|
|
430
|
+
this.numTotalSources = 0;
|
|
431
|
+
this.numLiveSources = 0;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
public setNumCurrentSources(numTotalSources: number, numLiveSources: number) {
|
|
435
|
+
this.numTotalSources = numTotalSources;
|
|
436
|
+
this.numLiveSources = numLiveSources;
|
|
437
|
+
|
|
438
|
+
this.sendRequests();
|
|
323
439
|
}
|
|
324
440
|
}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
MediaType,
|
|
4
4
|
ReceiveSlot as WcmeReceiveSlot,
|
|
5
5
|
ReceiveSlotEvents as WcmeReceiveSlotEvents,
|
|
6
|
-
|
|
6
|
+
StreamState,
|
|
7
7
|
} from '@webex/internal-media-core';
|
|
8
8
|
|
|
9
9
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
@@ -14,7 +14,7 @@ export const ReceiveSlotEvents = {
|
|
|
14
14
|
MaxFsUpdate: 'maxFsUpdate',
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export type {
|
|
17
|
+
export type {StreamState} from '@webex/internal-media-core';
|
|
18
18
|
export type CSI = number;
|
|
19
19
|
export type MemberId = string;
|
|
20
20
|
export type ReceiveSlotId = string;
|
|
@@ -40,7 +40,7 @@ export class ReceiveSlot extends EventsScope {
|
|
|
40
40
|
|
|
41
41
|
#csi?: CSI;
|
|
42
42
|
|
|
43
|
-
#sourceState:
|
|
43
|
+
#sourceState: StreamState;
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* constructor - don't use it directly, you should always use meeting.receiveSlotManager.allocateSlot()
|
|
@@ -119,7 +119,7 @@ export class ReceiveSlot extends EventsScope {
|
|
|
119
119
|
|
|
120
120
|
this.mcReceiveSlot.on(
|
|
121
121
|
WcmeReceiveSlotEvents.SourceUpdate,
|
|
122
|
-
(state:
|
|
122
|
+
(state: StreamState, csi?: number) => {
|
|
123
123
|
LoggerProxy.logger.log(
|
|
124
124
|
`ReceiveSlot#setupEventListeners --> got source update on receive slot ${this.id}, mediaType=${this.mediaType}, csi=${csi}, state=${state}`
|
|
125
125
|
);
|
|
@@ -59,7 +59,7 @@ export class ReceiveSlotManager {
|
|
|
59
59
|
if (availableSlot) {
|
|
60
60
|
this.allocatedSlots[mediaType].push(availableSlot);
|
|
61
61
|
|
|
62
|
-
LoggerProxy.logger.log(
|
|
62
|
+
LoggerProxy.logger.log(`${mediaType}: receive slot re-used: ${availableSlot.id}`);
|
|
63
63
|
|
|
64
64
|
return availableSlot;
|
|
65
65
|
}
|
|
@@ -70,7 +70,7 @@ export class ReceiveSlotManager {
|
|
|
70
70
|
const receiveSlot = new ReceiveSlot(mediaType, wcmeReceiveSlot, this.findMemberIdByCsiCallback);
|
|
71
71
|
|
|
72
72
|
this.allocatedSlots[mediaType].push(receiveSlot);
|
|
73
|
-
LoggerProxy.logger.log(
|
|
73
|
+
LoggerProxy.logger.log(`${mediaType}: new receive slot allocated: ${receiveSlot.id}`);
|
|
74
74
|
|
|
75
75
|
return receiveSlot;
|
|
76
76
|
}
|
|
@@ -87,10 +87,10 @@ export class ReceiveSlotManager {
|
|
|
87
87
|
if (idx >= 0) {
|
|
88
88
|
this.allocatedSlots[slot.mediaType].splice(idx, 1);
|
|
89
89
|
this.freeSlots[slot.mediaType].push(slot);
|
|
90
|
-
LoggerProxy.logger.log(
|
|
90
|
+
LoggerProxy.logger.log(`${slot.mediaType}: receive slot released: ${slot.id}`);
|
|
91
91
|
} else {
|
|
92
92
|
LoggerProxy.logger.warn(
|
|
93
|
-
|
|
93
|
+
`ReceiveSlotManager#releaseSlot --> trying to release a ${slot.mediaType}} slot that is not managed by this ReceiveSlotManager`
|
|
94
94
|
);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable valid-jsdoc */
|
|
2
|
-
import {MediaType,
|
|
2
|
+
import {MediaType, StreamState} from '@webex/internal-media-core';
|
|
3
3
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
4
4
|
import EventsScope from '../common/events/events-scope';
|
|
5
5
|
|
|
@@ -233,7 +233,7 @@ export class RemoteMedia extends EventsScope {
|
|
|
233
233
|
/**
|
|
234
234
|
* Getter for source state
|
|
235
235
|
*/
|
|
236
|
-
public get sourceState():
|
|
236
|
+
public get sourceState(): StreamState {
|
|
237
237
|
return this.receiveSlot?.sourceState;
|
|
238
238
|
}
|
|
239
239
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable valid-jsdoc */
|
|
2
2
|
/* eslint-disable require-jsdoc */
|
|
3
3
|
/* eslint-disable import/prefer-default-export */
|
|
4
|
+
import {forEach} from 'lodash';
|
|
4
5
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
5
6
|
|
|
6
7
|
import {getMaxFs, RemoteMedia, RemoteVideoResolution} from './remoteMedia';
|
|
@@ -66,6 +67,53 @@ export class RemoteMediaGroup {
|
|
|
66
67
|
return [...this.unpinnedRemoteMedia, ...this.pinnedRemoteMedia];
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Sets CSIs for multiple RemoteMedia instances belonging to this RemoteMediaGroup.
|
|
72
|
+
* For each entry in the remoteMediaCsis array:
|
|
73
|
+
* - if csi is specified, the RemoteMedia instance is pinned to that CSI
|
|
74
|
+
* - if csi is undefined, the RemoteMedia instance is unpinned
|
|
75
|
+
* @internal
|
|
76
|
+
*/
|
|
77
|
+
public setActiveSpeakerCsis(
|
|
78
|
+
remoteMediaCsis: {remoteMedia: RemoteMedia; csi?: number}[],
|
|
79
|
+
commit = true
|
|
80
|
+
): void {
|
|
81
|
+
forEach(remoteMediaCsis, ({csi, remoteMedia}) => {
|
|
82
|
+
if (csi) {
|
|
83
|
+
if (!(this.pinnedRemoteMedia.indexOf(remoteMedia) >= 0)) {
|
|
84
|
+
const unpinId = this.unpinnedRemoteMedia.indexOf(remoteMedia);
|
|
85
|
+
if (unpinId >= 0) {
|
|
86
|
+
this.unpinnedRemoteMedia.splice(unpinId, 1);
|
|
87
|
+
this.pinnedRemoteMedia.push(remoteMedia);
|
|
88
|
+
} else {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`failed to pin a remote media object ${remoteMedia.id}, because it is not found in this remote media group`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
remoteMedia.sendMediaRequest(csi, false);
|
|
95
|
+
} else {
|
|
96
|
+
if (!(this.unpinnedRemoteMedia.indexOf(remoteMedia) >= 0)) {
|
|
97
|
+
const pinId = this.pinnedRemoteMedia.indexOf(remoteMedia);
|
|
98
|
+
if (pinId >= 0) {
|
|
99
|
+
this.pinnedRemoteMedia.splice(pinId, 1);
|
|
100
|
+
this.unpinnedRemoteMedia.push(remoteMedia);
|
|
101
|
+
} else {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`failed to unpin a remote media object ${remoteMedia.id}, because it is not found in this remote media group`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
remoteMedia.cancelMediaRequest(false);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
this.cancelActiveSpeakerMediaRequest(false);
|
|
111
|
+
this.sendActiveSpeakerMediaRequest(false);
|
|
112
|
+
if (commit) {
|
|
113
|
+
this.mediaRequestManager.commit();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
69
117
|
/**
|
|
70
118
|
* Pins a specific remote media instance to a specfic CSI, so the media will
|
|
71
119
|
* no longer come from active speaker, but from that CSI.
|
|
@@ -151,6 +199,17 @@ export class RemoteMediaGroup {
|
|
|
151
199
|
throw new Error(`remote media object ${remoteMedia.id} not found in the group`);
|
|
152
200
|
}
|
|
153
201
|
|
|
202
|
+
/**
|
|
203
|
+
* setPreferLiveVideo - sets preferLiveVideo to true/false
|
|
204
|
+
* @internal
|
|
205
|
+
*/
|
|
206
|
+
public setPreferLiveVideo(preferLiveVideo: boolean, commit: boolean) {
|
|
207
|
+
if (this.options.preferLiveVideo !== preferLiveVideo) {
|
|
208
|
+
this.options.preferLiveVideo = preferLiveVideo;
|
|
209
|
+
this.sendActiveSpeakerMediaRequest(commit);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
154
213
|
private sendActiveSpeakerMediaRequest(commit: boolean) {
|
|
155
214
|
this.cancelActiveSpeakerMediaRequest(false);
|
|
156
215
|
|
|
@@ -96,6 +96,7 @@ const OnePlusFiveLayout: VideoLayout = {
|
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
// A layout with 2 big panes for 2 main active speakers and a strip of 6 small panes for other active speakers:
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
99
100
|
const TwoMainPlusSixSmallLayout: VideoLayout = {
|
|
100
101
|
activeSpeakerVideoPaneGroups: [
|
|
101
102
|
{
|
|
@@ -490,6 +491,38 @@ export class RemoteMediaManager extends EventsScope {
|
|
|
490
491
|
return this.currentLayoutId;
|
|
491
492
|
}
|
|
492
493
|
|
|
494
|
+
/**
|
|
495
|
+
* sets the preferLiveVideo
|
|
496
|
+
*/
|
|
497
|
+
public setPreferLiveVideo(preferLiveVideo: boolean) {
|
|
498
|
+
LoggerProxy.logger.log(
|
|
499
|
+
`RemoteMediaManager#setPreferLiveVideo --> setPreferLiveVideo is called to set preferLiveVideo to ${preferLiveVideo}`
|
|
500
|
+
);
|
|
501
|
+
this.config.video.preferLiveVideo = preferLiveVideo;
|
|
502
|
+
Object.values(this.media.video.activeSpeakerGroups).forEach((activeSpeakerGroup) => {
|
|
503
|
+
activeSpeakerGroup.setPreferLiveVideo(preferLiveVideo, false);
|
|
504
|
+
});
|
|
505
|
+
this.mediaRequestManagers.video.commit();
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Sets CSIs for multiple RemoteMedia instances belonging to RemoteMediaGroup.
|
|
510
|
+
* For each entry in the remoteMediaCsis array:
|
|
511
|
+
* - if csi is specified, the RemoteMedia instance is pinned to that CSI
|
|
512
|
+
* - if csi is undefined, the RemoteMedia instance is unpinned
|
|
513
|
+
*/
|
|
514
|
+
public setActiveSpeakerCsis(remoteMediaCsis: {remoteMedia: RemoteMedia; csi?: number}[]) {
|
|
515
|
+
Object.values(this.media.video.activeSpeakerGroups).forEach((remoteMediaGroup) => {
|
|
516
|
+
const groupRemoteMediaCsis = remoteMediaCsis.filter(({remoteMedia}) =>
|
|
517
|
+
remoteMediaGroup.includes(remoteMedia)
|
|
518
|
+
);
|
|
519
|
+
if (groupRemoteMediaCsis.length > 0) {
|
|
520
|
+
remoteMediaGroup.setActiveSpeakerCsis(groupRemoteMediaCsis, false);
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
this.mediaRequestManagers.video.commit();
|
|
524
|
+
}
|
|
525
|
+
|
|
493
526
|
/**
|
|
494
527
|
* Creates the audio slots
|
|
495
528
|
*/
|