@webex/plugin-meetings 3.0.0-beta.76 → 3.0.0-beta.78
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/locus-info/selfUtils.js +1 -1
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/meeting/index.js +20 -10
- package/dist/meeting/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +51 -9
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/types/multistream/mediaRequestManager.d.ts +28 -1
- package/package.json +19 -19
- package/src/locus-info/selfUtils.ts +1 -0
- package/src/meeting/index.ts +46 -22
- package/src/multistream/mediaRequestManager.ts +53 -8
- package/test/unit/spec/meeting/utils.js +1 -1
- package/test/unit/spec/multistream/mediaRequestManager.ts +326 -107
|
@@ -31,9 +31,10 @@ var CODEC_DEFAULTS = {
|
|
|
31
31
|
};
|
|
32
32
|
var DEBOUNCED_SOURCE_UPDATE_TIME = 1000;
|
|
33
33
|
var MediaRequestManager = /*#__PURE__*/function () {
|
|
34
|
-
function MediaRequestManager(
|
|
34
|
+
function MediaRequestManager(sendMediaRequestsCallback, options) {
|
|
35
35
|
(0, _classCallCheck2.default)(this, MediaRequestManager);
|
|
36
36
|
(0, _defineProperty2.default)(this, "sendMediaRequestsCallback", void 0);
|
|
37
|
+
(0, _defineProperty2.default)(this, "kind", void 0);
|
|
37
38
|
(0, _defineProperty2.default)(this, "counter", void 0);
|
|
38
39
|
(0, _defineProperty2.default)(this, "clientRequests", void 0);
|
|
39
40
|
(0, _defineProperty2.default)(this, "degradationPreferences", void 0);
|
|
@@ -43,7 +44,8 @@ var MediaRequestManager = /*#__PURE__*/function () {
|
|
|
43
44
|
this.sendMediaRequestsCallback = sendMediaRequestsCallback;
|
|
44
45
|
this.counter = 0;
|
|
45
46
|
this.clientRequests = {};
|
|
46
|
-
this.degradationPreferences = degradationPreferences;
|
|
47
|
+
this.degradationPreferences = options.degradationPreferences;
|
|
48
|
+
this.kind = options.kind;
|
|
47
49
|
this.sourceUpdateListener = this.commit.bind(this);
|
|
48
50
|
this.debouncedSourceUpdateListener = (0, _debounce2.default)(this.sourceUpdateListener, DEBOUNCED_SOURCE_UPDATE_TIME);
|
|
49
51
|
}
|
|
@@ -122,6 +124,46 @@ var MediaRequestManager = /*#__PURE__*/function () {
|
|
|
122
124
|
});
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Returns the maxPayloadBitsPerSecond per Stream
|
|
129
|
+
*
|
|
130
|
+
* If MediaRequestManager kind is "audio", a constant bitrate will be returned.
|
|
131
|
+
* If MediaRequestManager kind is "video", the bitrate will be calculated based
|
|
132
|
+
* on maxFs (default h264 maxFs as fallback if maxFs is not defined)
|
|
133
|
+
*
|
|
134
|
+
* @param {MediaRequest} mediaRequest - mediaRequest to take data from
|
|
135
|
+
* @returns {number} maxPayloadBitsPerSecond
|
|
136
|
+
*/
|
|
137
|
+
}, {
|
|
138
|
+
key: "getMaxPayloadBitsPerSecond",
|
|
139
|
+
value: function getMaxPayloadBitsPerSecond(mediaRequest) {
|
|
140
|
+
if (this.kind === 'audio') {
|
|
141
|
+
// return mono_music bitrate default if the kind of mediarequest manager is audio:
|
|
142
|
+
return _internalMediaCore.RecommendedOpusBitrates.FB_MONO_MUSIC;
|
|
143
|
+
}
|
|
144
|
+
return (0, _internalMediaCore.getRecommendedMaxBitrateForFrameSize)(mediaRequest.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Returns the max Macro Blocks per second (maxMbps) per H264 Stream
|
|
149
|
+
*
|
|
150
|
+
* The maxMbps will be calculated based on maxFs and maxFps
|
|
151
|
+
* (default h264 maxFps as fallback if maxFps is not defined)
|
|
152
|
+
*
|
|
153
|
+
* @param {MediaRequest} mediaRequest - mediaRequest to take data from
|
|
154
|
+
* @returns {number} maxMbps
|
|
155
|
+
*/
|
|
156
|
+
// eslint-disable-next-line class-methods-use-this
|
|
157
|
+
}, {
|
|
158
|
+
key: "getH264MaxMbps",
|
|
159
|
+
value: function getH264MaxMbps(mediaRequest) {
|
|
160
|
+
// fallback for maxFps (not needed for maxFs, since there is a fallback already in getDegradedClientRequests)
|
|
161
|
+
var maxFps = mediaRequest.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps;
|
|
162
|
+
|
|
163
|
+
// divided by 100 since maxFps is 3000 (for 30 frames per seconds)
|
|
164
|
+
return mediaRequest.codecInfo.maxFs * maxFps / 100;
|
|
165
|
+
}
|
|
166
|
+
|
|
125
167
|
/**
|
|
126
168
|
* Clears the previous media requests.
|
|
127
169
|
*
|
|
@@ -135,15 +177,15 @@ var MediaRequestManager = /*#__PURE__*/function () {
|
|
|
135
177
|
}, {
|
|
136
178
|
key: "sendRequests",
|
|
137
179
|
value: function sendRequests() {
|
|
180
|
+
var _this3 = this;
|
|
138
181
|
var wcmeMediaRequests = [];
|
|
139
182
|
var clientRequests = this.getDegradedClientRequests();
|
|
140
|
-
var maxPayloadBitsPerSecond = 10 * 1000 * 1000;
|
|
141
183
|
|
|
142
184
|
// map all the client media requests to wcme media requests
|
|
143
185
|
(0, _values.default)(clientRequests).forEach(function (mr) {
|
|
144
186
|
wcmeMediaRequests.push(new _internalMediaCore.MediaRequest(mr.policyInfo.policy === 'active-speaker' ? _internalMediaCore.Policy.ActiveSpeaker : _internalMediaCore.Policy.ReceiverSelected, mr.policyInfo.policy === 'active-speaker' ? new _internalMediaCore.ActiveSpeakerInfo(mr.policyInfo.priority, mr.policyInfo.crossPriorityDuplication, mr.policyInfo.crossPolicyDuplication, mr.policyInfo.preferLiveVideo) : new _internalMediaCore.ReceiverSelectedInfo(mr.policyInfo.csi), mr.receiveSlots.map(function (receiveSlot) {
|
|
145
187
|
return receiveSlot.wcmeReceiveSlot;
|
|
146
|
-
}),
|
|
188
|
+
}), _this3.getMaxPayloadBitsPerSecond(mr), mr.codecInfo && [new _internalMediaCore.CodecInfo(0x80, new _internalMediaCore.H264Codec(mr.codecInfo.maxFs, mr.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps, _this3.getH264MaxMbps(mr), mr.codecInfo.maxWidth, mr.codecInfo.maxHeight))]));
|
|
147
189
|
});
|
|
148
190
|
|
|
149
191
|
//! IMPORTANT: this is only a temporary fix. This will soon be done in the jmp layer (@webex/json-multistream)
|
|
@@ -159,17 +201,17 @@ var MediaRequestManager = /*#__PURE__*/function () {
|
|
|
159
201
|
}, {
|
|
160
202
|
key: "addRequest",
|
|
161
203
|
value: function addRequest(mediaRequest) {
|
|
162
|
-
var
|
|
204
|
+
var _this4 = this;
|
|
163
205
|
var commit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
164
206
|
// eslint-disable-next-line no-plusplus
|
|
165
207
|
var newId = "".concat(this.counter++);
|
|
166
208
|
this.clientRequests[newId] = mediaRequest;
|
|
167
209
|
mediaRequest.receiveSlots.forEach(function (rs) {
|
|
168
|
-
rs.on(_receiveSlot.ReceiveSlotEvents.SourceUpdate,
|
|
210
|
+
rs.on(_receiveSlot.ReceiveSlotEvents.SourceUpdate, _this4.sourceUpdateListener);
|
|
169
211
|
rs.on(_receiveSlot.ReceiveSlotEvents.MaxFsUpdate, function (_ref3) {
|
|
170
212
|
var maxFs = _ref3.maxFs;
|
|
171
213
|
mediaRequest.preferredMaxFs = maxFs;
|
|
172
|
-
|
|
214
|
+
_this4.debouncedSourceUpdateListener();
|
|
173
215
|
});
|
|
174
216
|
});
|
|
175
217
|
if (commit) {
|
|
@@ -181,10 +223,10 @@ var MediaRequestManager = /*#__PURE__*/function () {
|
|
|
181
223
|
key: "cancelRequest",
|
|
182
224
|
value: function cancelRequest(requestId) {
|
|
183
225
|
var _this$clientRequests$,
|
|
184
|
-
|
|
226
|
+
_this5 = this;
|
|
185
227
|
var commit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
186
228
|
(_this$clientRequests$ = this.clientRequests[requestId]) === null || _this$clientRequests$ === void 0 ? void 0 : _this$clientRequests$.receiveSlots.forEach(function (rs) {
|
|
187
|
-
rs.off(_receiveSlot.ReceiveSlotEvents.SourceUpdate,
|
|
229
|
+
rs.off(_receiveSlot.ReceiveSlotEvents.SourceUpdate, _this5.sourceUpdateListener);
|
|
188
230
|
});
|
|
189
231
|
delete this.clientRequests[requestId];
|
|
190
232
|
if (commit) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["CODEC_DEFAULTS","h264","maxFs","maxFps","maxMbps","DEBOUNCED_SOURCE_UPDATE_TIME","MediaRequestManager","degradationPreferences","sendMediaRequestsCallback","counter","clientRequests","sourceUpdateListener","commit","bind","debouncedSourceUpdateListener","sendRequests","maxFsLimits","getMaxFs","totalMacroblocksRequested","forEach","id","mr","codecInfo","Math","min","preferredMaxFs","i","slotsWithLiveSource","receiveSlots","filter","rs","sourceState","length","maxMacroblocksLimit","LoggerProxy","logger","warn","mediaRequestA","mediaRequestB","_toJmpScrRequest","newRequests","previousWCMEMediaRequests","every","req","idx","isEqual","wcmeMediaRequests","getDegradedClientRequests","maxPayloadBitsPerSecond","push","WcmeMediaRequest","policyInfo","policy","Policy","ActiveSpeaker","ReceiverSelected","ActiveSpeakerInfo","priority","crossPriorityDuplication","crossPolicyDuplication","preferLiveVideo","ReceiverSelectedInfo","csi","map","receiveSlot","wcmeReceiveSlot","WcmeCodecInfo","H264Codec","maxWidth","maxHeight","checkIsNewRequestsEqualToPrev","info","mediaRequest","newId","on","ReceiveSlotEvents","SourceUpdate","MaxFsUpdate","requestId","off"],"sources":["mediaRequestManager.ts"],"sourcesContent":["/* eslint-disable require-jsdoc */\nimport {\n MediaRequest as WcmeMediaRequest,\n Policy,\n ActiveSpeakerInfo,\n ReceiverSelectedInfo,\n CodecInfo as WcmeCodecInfo,\n H264Codec,\n} from '@webex/internal-media-core';\nimport {cloneDeep, debounce, isEmpty} from 'lodash';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\n\nimport {ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';\nimport {getMaxFs} from './remoteMedia';\n\nexport interface ActiveSpeakerPolicyInfo {\n policy: 'active-speaker';\n priority: number;\n crossPriorityDuplication: boolean;\n crossPolicyDuplication: boolean;\n preferLiveVideo: boolean;\n}\n\nexport interface ReceiverSelectedPolicyInfo {\n policy: 'receiver-selected';\n csi: number;\n}\n\nexport type PolicyInfo = ActiveSpeakerPolicyInfo | ReceiverSelectedPolicyInfo;\n\nexport interface H264CodecInfo {\n codec: 'h264';\n maxFs?: number;\n maxFps?: number;\n maxMbps?: number;\n maxWidth?: number;\n maxHeight?: number;\n}\n\nexport type CodecInfo = H264CodecInfo; // we'll add AV1 here in the future when it's available\n\nexport interface MediaRequest {\n policyInfo: PolicyInfo;\n receiveSlots: Array<ReceiveSlot>;\n codecInfo?: CodecInfo;\n preferredMaxFs?: number;\n}\n\nexport type MediaRequestId = string;\n\nconst CODEC_DEFAULTS = {\n h264: {\n maxFs: 8192,\n maxFps: 3000,\n maxMbps: 245760,\n },\n};\n\nconst DEBOUNCED_SOURCE_UPDATE_TIME = 1000;\n\ntype DegradationPreferences = {\n maxMacroblocksLimit: number;\n};\n\ntype SendMediaRequestsCallback = (mediaRequests: WcmeMediaRequest[]) => void;\n\nexport class MediaRequestManager {\n private sendMediaRequestsCallback: SendMediaRequestsCallback;\n\n private counter: number;\n\n private clientRequests: {[key: MediaRequestId]: MediaRequest};\n\n private degradationPreferences: DegradationPreferences;\n\n private sourceUpdateListener: () => void;\n\n private debouncedSourceUpdateListener: () => void;\n\n private previousWCMEMediaRequests: Array<WcmeMediaRequest> = [];\n\n constructor(\n degradationPreferences: DegradationPreferences,\n sendMediaRequestsCallback: SendMediaRequestsCallback\n ) {\n this.sendMediaRequestsCallback = sendMediaRequestsCallback;\n this.counter = 0;\n this.clientRequests = {};\n this.degradationPreferences = degradationPreferences;\n this.sourceUpdateListener = this.commit.bind(this);\n this.debouncedSourceUpdateListener = debounce(\n this.sourceUpdateListener,\n DEBOUNCED_SOURCE_UPDATE_TIME\n );\n }\n\n public setDegradationPreferences(degradationPreferences: DegradationPreferences) {\n this.degradationPreferences = degradationPreferences;\n this.sendRequests(); // re-send requests after preferences are set\n }\n\n private getDegradedClientRequests() {\n const clientRequests = cloneDeep(this.clientRequests);\n const maxFsLimits = [\n getMaxFs('best'),\n getMaxFs('large'),\n getMaxFs('medium'),\n getMaxFs('small'),\n getMaxFs('very small'),\n getMaxFs('thumbnail'),\n ];\n\n // reduce max-fs until total macroblocks is below limit\n for (let i = 0; i < maxFsLimits.length; i += 1) {\n let totalMacroblocksRequested = 0;\n Object.entries(clientRequests).forEach(([id, mr]) => {\n if (mr.codecInfo) {\n mr.codecInfo.maxFs = Math.min(\n mr.preferredMaxFs || CODEC_DEFAULTS.h264.maxFs,\n mr.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs,\n maxFsLimits[i]\n );\n // we only consider sources with \"live\" state\n const slotsWithLiveSource = this.clientRequests[id].receiveSlots.filter(\n (rs) => rs.sourceState === 'live'\n );\n totalMacroblocksRequested += mr.codecInfo.maxFs * slotsWithLiveSource.length;\n }\n });\n if (totalMacroblocksRequested <= this.degradationPreferences.maxMacroblocksLimit) {\n if (i !== 0) {\n LoggerProxy.logger.warn(\n `multistream:mediaRequestManager --> too many streams with high max-fs, frame size will be limited to ${maxFsLimits[i]}`\n );\n }\n break;\n } else if (i === maxFsLimits.length - 1) {\n LoggerProxy.logger.warn(\n `multistream:mediaRequestManager --> even with frame size limited to ${maxFsLimits[i]} you are still requesting too many streams, consider reducing the number of requests`\n );\n }\n }\n\n return clientRequests;\n }\n\n /**\n * Returns true if two media requests are the same, false otherwise.\n *\n * @param {WcmeMediaRequest} mediaRequestA - Media request A for comparison.\n * @param {WcmeMediaRequest} mediaRequestB - Media request B for comparison.\n * @returns {boolean} - Whether they are equal.\n */\n // eslint-disable-next-line class-methods-use-this\n public isEqual(mediaRequestA: WcmeMediaRequest, mediaRequestB: WcmeMediaRequest) {\n return (\n JSON.stringify(mediaRequestA._toJmpScrRequest()) ===\n JSON.stringify(mediaRequestB._toJmpScrRequest())\n );\n }\n\n /**\n * Compares new media requests to previous ones and determines\n * if they are the same.\n *\n * @param {WcmeMediaRequest[]} newRequests - Array with new requests.\n * @returns {boolean} - True if they are equal, false otherwise.\n */\n private checkIsNewRequestsEqualToPrev(newRequests: WcmeMediaRequest[]) {\n return (\n !isEmpty(this.previousWCMEMediaRequests) &&\n this.previousWCMEMediaRequests.length === newRequests.length &&\n this.previousWCMEMediaRequests.every((req, idx) => this.isEqual(req, newRequests[idx]))\n );\n }\n\n /**\n * Clears the previous media requests.\n *\n * @returns {void}\n */\n public clearPreviousRequests(): void {\n this.previousWCMEMediaRequests = [];\n }\n\n private sendRequests() {\n const wcmeMediaRequests: WcmeMediaRequest[] = [];\n\n const clientRequests = this.getDegradedClientRequests();\n const maxPayloadBitsPerSecond = 10 * 1000 * 1000;\n\n // map all the client media requests to wcme media requests\n Object.values(clientRequests).forEach((mr) => {\n wcmeMediaRequests.push(\n new WcmeMediaRequest(\n mr.policyInfo.policy === 'active-speaker'\n ? Policy.ActiveSpeaker\n : Policy.ReceiverSelected,\n mr.policyInfo.policy === 'active-speaker'\n ? new ActiveSpeakerInfo(\n mr.policyInfo.priority,\n mr.policyInfo.crossPriorityDuplication,\n mr.policyInfo.crossPolicyDuplication,\n mr.policyInfo.preferLiveVideo\n )\n : new ReceiverSelectedInfo(mr.policyInfo.csi),\n mr.receiveSlots.map((receiveSlot) => receiveSlot.wcmeReceiveSlot),\n maxPayloadBitsPerSecond,\n mr.codecInfo && [\n new WcmeCodecInfo(\n 0x80,\n new H264Codec(\n mr.codecInfo.maxFs,\n mr.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps,\n mr.codecInfo.maxMbps || CODEC_DEFAULTS.h264.maxMbps,\n mr.codecInfo.maxWidth,\n mr.codecInfo.maxHeight\n )\n ),\n ]\n )\n );\n });\n\n //! IMPORTANT: this is only a temporary fix. This will soon be done in the jmp layer (@webex/json-multistream)\n // https://jira-eng-gpk2.cisco.com/jira/browse/WEBEX-326713\n if (!this.checkIsNewRequestsEqualToPrev(wcmeMediaRequests)) {\n this.sendMediaRequestsCallback(wcmeMediaRequests);\n this.previousWCMEMediaRequests = wcmeMediaRequests;\n LoggerProxy.logger.info(`multistream:sendRequests --> media requests sent. `);\n } else {\n LoggerProxy.logger.info(\n `multistream:sendRequests --> detected duplicate WCME requests, skipping them... `\n );\n }\n }\n\n public addRequest(mediaRequest: MediaRequest, commit = true): MediaRequestId {\n // eslint-disable-next-line no-plusplus\n const newId = `${this.counter++}`;\n\n this.clientRequests[newId] = mediaRequest;\n\n mediaRequest.receiveSlots.forEach((rs) => {\n rs.on(ReceiveSlotEvents.SourceUpdate, this.sourceUpdateListener);\n rs.on(ReceiveSlotEvents.MaxFsUpdate, ({maxFs}) => {\n mediaRequest.preferredMaxFs = maxFs;\n this.debouncedSourceUpdateListener();\n });\n });\n\n if (commit) {\n this.commit();\n }\n\n return newId;\n }\n\n public cancelRequest(requestId: MediaRequestId, commit = true) {\n this.clientRequests[requestId]?.receiveSlots.forEach((rs) => {\n rs.off(ReceiveSlotEvents.SourceUpdate, this.sourceUpdateListener);\n });\n\n delete this.clientRequests[requestId];\n\n if (commit) {\n this.commit();\n }\n }\n\n public commit() {\n return this.sendRequests();\n }\n\n public reset() {\n this.clientRequests = {};\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["CODEC_DEFAULTS","h264","maxFs","maxFps","maxMbps","DEBOUNCED_SOURCE_UPDATE_TIME","MediaRequestManager","sendMediaRequestsCallback","options","counter","clientRequests","degradationPreferences","kind","sourceUpdateListener","commit","bind","debouncedSourceUpdateListener","sendRequests","maxFsLimits","getMaxFs","totalMacroblocksRequested","forEach","id","mr","codecInfo","Math","min","preferredMaxFs","i","slotsWithLiveSource","receiveSlots","filter","rs","sourceState","length","maxMacroblocksLimit","LoggerProxy","logger","warn","mediaRequestA","mediaRequestB","_toJmpScrRequest","newRequests","previousWCMEMediaRequests","every","req","idx","isEqual","mediaRequest","RecommendedOpusBitrates","FB_MONO_MUSIC","getRecommendedMaxBitrateForFrameSize","wcmeMediaRequests","getDegradedClientRequests","push","WcmeMediaRequest","policyInfo","policy","Policy","ActiveSpeaker","ReceiverSelected","ActiveSpeakerInfo","priority","crossPriorityDuplication","crossPolicyDuplication","preferLiveVideo","ReceiverSelectedInfo","csi","map","receiveSlot","wcmeReceiveSlot","getMaxPayloadBitsPerSecond","WcmeCodecInfo","H264Codec","getH264MaxMbps","maxWidth","maxHeight","checkIsNewRequestsEqualToPrev","info","newId","on","ReceiveSlotEvents","SourceUpdate","MaxFsUpdate","requestId","off"],"sources":["mediaRequestManager.ts"],"sourcesContent":["/* eslint-disable require-jsdoc */\nimport {\n MediaRequest as WcmeMediaRequest,\n Policy,\n ActiveSpeakerInfo,\n ReceiverSelectedInfo,\n CodecInfo as WcmeCodecInfo,\n H264Codec,\n getRecommendedMaxBitrateForFrameSize,\n RecommendedOpusBitrates,\n} from '@webex/internal-media-core';\nimport {cloneDeep, debounce, isEmpty} from 'lodash';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\n\nimport {ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';\nimport {getMaxFs} from './remoteMedia';\n\nexport interface ActiveSpeakerPolicyInfo {\n policy: 'active-speaker';\n priority: number;\n crossPriorityDuplication: boolean;\n crossPolicyDuplication: boolean;\n preferLiveVideo: boolean;\n}\n\nexport interface ReceiverSelectedPolicyInfo {\n policy: 'receiver-selected';\n csi: number;\n}\n\nexport type PolicyInfo = ActiveSpeakerPolicyInfo | ReceiverSelectedPolicyInfo;\n\nexport interface H264CodecInfo {\n codec: 'h264';\n maxFs?: number;\n maxFps?: number;\n maxMbps?: number;\n maxWidth?: number;\n maxHeight?: number;\n}\n\nexport type CodecInfo = H264CodecInfo; // we'll add AV1 here in the future when it's available\n\nexport interface MediaRequest {\n policyInfo: PolicyInfo;\n receiveSlots: Array<ReceiveSlot>;\n codecInfo?: CodecInfo;\n preferredMaxFs?: number;\n}\n\nexport type MediaRequestId = string;\n\nconst CODEC_DEFAULTS = {\n h264: {\n maxFs: 8192,\n maxFps: 3000,\n maxMbps: 245760,\n },\n};\n\nconst DEBOUNCED_SOURCE_UPDATE_TIME = 1000;\n\ntype DegradationPreferences = {\n maxMacroblocksLimit: number;\n};\n\ntype SendMediaRequestsCallback = (mediaRequests: WcmeMediaRequest[]) => void;\ntype Kind = 'audio' | 'video';\n\ntype Options = {\n degradationPreferences: DegradationPreferences;\n kind: Kind;\n};\nexport class MediaRequestManager {\n private sendMediaRequestsCallback: SendMediaRequestsCallback;\n\n private kind: Kind;\n\n private counter: number;\n\n private clientRequests: {[key: MediaRequestId]: MediaRequest};\n\n private degradationPreferences: DegradationPreferences;\n\n private sourceUpdateListener: () => void;\n\n private debouncedSourceUpdateListener: () => void;\n\n private previousWCMEMediaRequests: Array<WcmeMediaRequest> = [];\n\n constructor(sendMediaRequestsCallback: SendMediaRequestsCallback, options: Options) {\n this.sendMediaRequestsCallback = sendMediaRequestsCallback;\n this.counter = 0;\n this.clientRequests = {};\n this.degradationPreferences = options.degradationPreferences;\n this.kind = options.kind;\n this.sourceUpdateListener = this.commit.bind(this);\n this.debouncedSourceUpdateListener = debounce(\n this.sourceUpdateListener,\n DEBOUNCED_SOURCE_UPDATE_TIME\n );\n }\n\n public setDegradationPreferences(degradationPreferences: DegradationPreferences) {\n this.degradationPreferences = degradationPreferences;\n this.sendRequests(); // re-send requests after preferences are set\n }\n\n private getDegradedClientRequests() {\n const clientRequests = cloneDeep(this.clientRequests);\n const maxFsLimits = [\n getMaxFs('best'),\n getMaxFs('large'),\n getMaxFs('medium'),\n getMaxFs('small'),\n getMaxFs('very small'),\n getMaxFs('thumbnail'),\n ];\n\n // reduce max-fs until total macroblocks is below limit\n for (let i = 0; i < maxFsLimits.length; i += 1) {\n let totalMacroblocksRequested = 0;\n Object.entries(clientRequests).forEach(([id, mr]) => {\n if (mr.codecInfo) {\n mr.codecInfo.maxFs = Math.min(\n mr.preferredMaxFs || CODEC_DEFAULTS.h264.maxFs,\n mr.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs,\n maxFsLimits[i]\n );\n // we only consider sources with \"live\" state\n const slotsWithLiveSource = this.clientRequests[id].receiveSlots.filter(\n (rs) => rs.sourceState === 'live'\n );\n totalMacroblocksRequested += mr.codecInfo.maxFs * slotsWithLiveSource.length;\n }\n });\n if (totalMacroblocksRequested <= this.degradationPreferences.maxMacroblocksLimit) {\n if (i !== 0) {\n LoggerProxy.logger.warn(\n `multistream:mediaRequestManager --> too many streams with high max-fs, frame size will be limited to ${maxFsLimits[i]}`\n );\n }\n break;\n } else if (i === maxFsLimits.length - 1) {\n LoggerProxy.logger.warn(\n `multistream:mediaRequestManager --> even with frame size limited to ${maxFsLimits[i]} you are still requesting too many streams, consider reducing the number of requests`\n );\n }\n }\n\n return clientRequests;\n }\n\n /**\n * Returns true if two media requests are the same, false otherwise.\n *\n * @param {WcmeMediaRequest} mediaRequestA - Media request A for comparison.\n * @param {WcmeMediaRequest} mediaRequestB - Media request B for comparison.\n * @returns {boolean} - Whether they are equal.\n */\n // eslint-disable-next-line class-methods-use-this\n public isEqual(mediaRequestA: WcmeMediaRequest, mediaRequestB: WcmeMediaRequest) {\n return (\n JSON.stringify(mediaRequestA._toJmpScrRequest()) ===\n JSON.stringify(mediaRequestB._toJmpScrRequest())\n );\n }\n\n /**\n * Compares new media requests to previous ones and determines\n * if they are the same.\n *\n * @param {WcmeMediaRequest[]} newRequests - Array with new requests.\n * @returns {boolean} - True if they are equal, false otherwise.\n */\n private checkIsNewRequestsEqualToPrev(newRequests: WcmeMediaRequest[]) {\n return (\n !isEmpty(this.previousWCMEMediaRequests) &&\n this.previousWCMEMediaRequests.length === newRequests.length &&\n this.previousWCMEMediaRequests.every((req, idx) => this.isEqual(req, newRequests[idx]))\n );\n }\n\n /**\n * Returns the maxPayloadBitsPerSecond per Stream\n *\n * If MediaRequestManager kind is \"audio\", a constant bitrate will be returned.\n * If MediaRequestManager kind is \"video\", the bitrate will be calculated based\n * on maxFs (default h264 maxFs as fallback if maxFs is not defined)\n *\n * @param {MediaRequest} mediaRequest - mediaRequest to take data from\n * @returns {number} maxPayloadBitsPerSecond\n */\n private getMaxPayloadBitsPerSecond(mediaRequest: MediaRequest): number {\n if (this.kind === 'audio') {\n // return mono_music bitrate default if the kind of mediarequest manager is audio:\n return RecommendedOpusBitrates.FB_MONO_MUSIC;\n }\n\n return getRecommendedMaxBitrateForFrameSize(\n mediaRequest.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs\n );\n }\n\n /**\n * Returns the max Macro Blocks per second (maxMbps) per H264 Stream\n *\n * The maxMbps will be calculated based on maxFs and maxFps\n * (default h264 maxFps as fallback if maxFps is not defined)\n *\n * @param {MediaRequest} mediaRequest - mediaRequest to take data from\n * @returns {number} maxMbps\n */\n // eslint-disable-next-line class-methods-use-this\n private getH264MaxMbps(mediaRequest: MediaRequest): number {\n // fallback for maxFps (not needed for maxFs, since there is a fallback already in getDegradedClientRequests)\n const maxFps = mediaRequest.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps;\n\n // divided by 100 since maxFps is 3000 (for 30 frames per seconds)\n return (mediaRequest.codecInfo.maxFs * maxFps) / 100;\n }\n\n /**\n * Clears the previous media requests.\n *\n * @returns {void}\n */\n public clearPreviousRequests(): void {\n this.previousWCMEMediaRequests = [];\n }\n\n private sendRequests() {\n const wcmeMediaRequests: WcmeMediaRequest[] = [];\n\n const clientRequests = this.getDegradedClientRequests();\n\n // map all the client media requests to wcme media requests\n Object.values(clientRequests).forEach((mr) => {\n wcmeMediaRequests.push(\n new WcmeMediaRequest(\n mr.policyInfo.policy === 'active-speaker'\n ? Policy.ActiveSpeaker\n : Policy.ReceiverSelected,\n mr.policyInfo.policy === 'active-speaker'\n ? new ActiveSpeakerInfo(\n mr.policyInfo.priority,\n mr.policyInfo.crossPriorityDuplication,\n mr.policyInfo.crossPolicyDuplication,\n mr.policyInfo.preferLiveVideo\n )\n : new ReceiverSelectedInfo(mr.policyInfo.csi),\n mr.receiveSlots.map((receiveSlot) => receiveSlot.wcmeReceiveSlot),\n this.getMaxPayloadBitsPerSecond(mr),\n mr.codecInfo && [\n new WcmeCodecInfo(\n 0x80,\n new H264Codec(\n mr.codecInfo.maxFs,\n mr.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps,\n this.getH264MaxMbps(mr),\n mr.codecInfo.maxWidth,\n mr.codecInfo.maxHeight\n )\n ),\n ]\n )\n );\n });\n\n //! IMPORTANT: this is only a temporary fix. This will soon be done in the jmp layer (@webex/json-multistream)\n // https://jira-eng-gpk2.cisco.com/jira/browse/WEBEX-326713\n if (!this.checkIsNewRequestsEqualToPrev(wcmeMediaRequests)) {\n this.sendMediaRequestsCallback(wcmeMediaRequests);\n this.previousWCMEMediaRequests = wcmeMediaRequests;\n LoggerProxy.logger.info(`multistream:sendRequests --> media requests sent. `);\n } else {\n LoggerProxy.logger.info(\n `multistream:sendRequests --> detected duplicate WCME requests, skipping them... `\n );\n }\n }\n\n public addRequest(mediaRequest: MediaRequest, commit = true): MediaRequestId {\n // eslint-disable-next-line no-plusplus\n const newId = `${this.counter++}`;\n\n this.clientRequests[newId] = mediaRequest;\n\n mediaRequest.receiveSlots.forEach((rs) => {\n rs.on(ReceiveSlotEvents.SourceUpdate, this.sourceUpdateListener);\n rs.on(ReceiveSlotEvents.MaxFsUpdate, ({maxFs}) => {\n mediaRequest.preferredMaxFs = maxFs;\n this.debouncedSourceUpdateListener();\n });\n });\n\n if (commit) {\n this.commit();\n }\n\n return newId;\n }\n\n public cancelRequest(requestId: MediaRequestId, commit = true) {\n this.clientRequests[requestId]?.receiveSlots.forEach((rs) => {\n rs.off(ReceiveSlotEvents.SourceUpdate, this.sourceUpdateListener);\n });\n\n delete this.clientRequests[requestId];\n\n if (commit) {\n this.commit();\n }\n }\n\n public commit() {\n return this.sendRequests();\n }\n\n public reset() {\n this.clientRequests = {};\n }\n}\n"],"mappings":"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"}
|
|
@@ -32,15 +32,21 @@ type DegradationPreferences = {
|
|
|
32
32
|
maxMacroblocksLimit: number;
|
|
33
33
|
};
|
|
34
34
|
type SendMediaRequestsCallback = (mediaRequests: WcmeMediaRequest[]) => void;
|
|
35
|
+
type Kind = 'audio' | 'video';
|
|
36
|
+
type Options = {
|
|
37
|
+
degradationPreferences: DegradationPreferences;
|
|
38
|
+
kind: Kind;
|
|
39
|
+
};
|
|
35
40
|
export declare class MediaRequestManager {
|
|
36
41
|
private sendMediaRequestsCallback;
|
|
42
|
+
private kind;
|
|
37
43
|
private counter;
|
|
38
44
|
private clientRequests;
|
|
39
45
|
private degradationPreferences;
|
|
40
46
|
private sourceUpdateListener;
|
|
41
47
|
private debouncedSourceUpdateListener;
|
|
42
48
|
private previousWCMEMediaRequests;
|
|
43
|
-
constructor(
|
|
49
|
+
constructor(sendMediaRequestsCallback: SendMediaRequestsCallback, options: Options);
|
|
44
50
|
setDegradationPreferences(degradationPreferences: DegradationPreferences): void;
|
|
45
51
|
private getDegradedClientRequests;
|
|
46
52
|
/**
|
|
@@ -59,6 +65,27 @@ export declare class MediaRequestManager {
|
|
|
59
65
|
* @returns {boolean} - True if they are equal, false otherwise.
|
|
60
66
|
*/
|
|
61
67
|
private checkIsNewRequestsEqualToPrev;
|
|
68
|
+
/**
|
|
69
|
+
* Returns the maxPayloadBitsPerSecond per Stream
|
|
70
|
+
*
|
|
71
|
+
* If MediaRequestManager kind is "audio", a constant bitrate will be returned.
|
|
72
|
+
* If MediaRequestManager kind is "video", the bitrate will be calculated based
|
|
73
|
+
* on maxFs (default h264 maxFs as fallback if maxFs is not defined)
|
|
74
|
+
*
|
|
75
|
+
* @param {MediaRequest} mediaRequest - mediaRequest to take data from
|
|
76
|
+
* @returns {number} maxPayloadBitsPerSecond
|
|
77
|
+
*/
|
|
78
|
+
private getMaxPayloadBitsPerSecond;
|
|
79
|
+
/**
|
|
80
|
+
* Returns the max Macro Blocks per second (maxMbps) per H264 Stream
|
|
81
|
+
*
|
|
82
|
+
* The maxMbps will be calculated based on maxFs and maxFps
|
|
83
|
+
* (default h264 maxFps as fallback if maxFps is not defined)
|
|
84
|
+
*
|
|
85
|
+
* @param {MediaRequest} mediaRequest - mediaRequest to take data from
|
|
86
|
+
* @returns {number} maxMbps
|
|
87
|
+
*/
|
|
88
|
+
private getH264MaxMbps;
|
|
62
89
|
/**
|
|
63
90
|
* Clears the previous media requests.
|
|
64
91
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/plugin-meetings",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.78",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
|
|
6
6
|
"contributors": [
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"build": "yarn run -T tsc --declaration true --declarationDir ./dist/types"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@webex/plugin-meetings": "3.0.0-beta.
|
|
36
|
-
"@webex/test-helper-chai": "3.0.0-beta.
|
|
37
|
-
"@webex/test-helper-mocha": "3.0.0-beta.
|
|
38
|
-
"@webex/test-helper-mock-webex": "3.0.0-beta.
|
|
39
|
-
"@webex/test-helper-retry": "3.0.0-beta.
|
|
40
|
-
"@webex/test-helper-test-users": "3.0.0-beta.
|
|
35
|
+
"@webex/plugin-meetings": "3.0.0-beta.78",
|
|
36
|
+
"@webex/test-helper-chai": "3.0.0-beta.78",
|
|
37
|
+
"@webex/test-helper-mocha": "3.0.0-beta.78",
|
|
38
|
+
"@webex/test-helper-mock-webex": "3.0.0-beta.78",
|
|
39
|
+
"@webex/test-helper-retry": "3.0.0-beta.78",
|
|
40
|
+
"@webex/test-helper-test-users": "3.0.0-beta.78",
|
|
41
41
|
"chai": "^4.3.4",
|
|
42
42
|
"chai-as-promised": "^7.1.1",
|
|
43
43
|
"jsdom-global": "3.0.2",
|
|
@@ -46,18 +46,18 @@
|
|
|
46
46
|
"typescript": "^4.7.4"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@webex/common": "3.0.0-beta.
|
|
50
|
-
"@webex/internal-media-core": "1.
|
|
51
|
-
"@webex/internal-plugin-conversation": "3.0.0-beta.
|
|
52
|
-
"@webex/internal-plugin-device": "3.0.0-beta.
|
|
53
|
-
"@webex/internal-plugin-llm": "3.0.0-beta.
|
|
54
|
-
"@webex/internal-plugin-mercury": "3.0.0-beta.
|
|
55
|
-
"@webex/internal-plugin-metrics": "3.0.0-beta.
|
|
56
|
-
"@webex/internal-plugin-support": "3.0.0-beta.
|
|
57
|
-
"@webex/internal-plugin-user": "3.0.0-beta.
|
|
58
|
-
"@webex/plugin-people": "3.0.0-beta.
|
|
59
|
-
"@webex/plugin-rooms": "3.0.0-beta.
|
|
60
|
-
"@webex/webex-core": "3.0.0-beta.
|
|
49
|
+
"@webex/common": "3.0.0-beta.78",
|
|
50
|
+
"@webex/internal-media-core": "1.36.0",
|
|
51
|
+
"@webex/internal-plugin-conversation": "3.0.0-beta.78",
|
|
52
|
+
"@webex/internal-plugin-device": "3.0.0-beta.78",
|
|
53
|
+
"@webex/internal-plugin-llm": "3.0.0-beta.78",
|
|
54
|
+
"@webex/internal-plugin-mercury": "3.0.0-beta.78",
|
|
55
|
+
"@webex/internal-plugin-metrics": "3.0.0-beta.78",
|
|
56
|
+
"@webex/internal-plugin-support": "3.0.0-beta.78",
|
|
57
|
+
"@webex/internal-plugin-user": "3.0.0-beta.78",
|
|
58
|
+
"@webex/plugin-people": "3.0.0-beta.78",
|
|
59
|
+
"@webex/plugin-rooms": "3.0.0-beta.78",
|
|
60
|
+
"@webex/webex-core": "3.0.0-beta.78",
|
|
61
61
|
"ampersand-collection": "^2.0.2",
|
|
62
62
|
"bowser": "^2.11.0",
|
|
63
63
|
"btoa": "^1.2.1",
|
|
@@ -294,6 +294,7 @@ SelfUtils.getStatus = (status) => ({
|
|
|
294
294
|
SelfUtils.wasMediaInactiveOrReleased = (oldSelf: any = {}, changedSelf: any) =>
|
|
295
295
|
oldSelf.joinedWith &&
|
|
296
296
|
oldSelf.joinedWith.state === _JOINED_ &&
|
|
297
|
+
changedSelf.joinedWith &&
|
|
297
298
|
changedSelf.joinedWith.state === _LEFT_ &&
|
|
298
299
|
(changedSelf.joinedWith.reason === MEETING_END_REASON.INACTIVE ||
|
|
299
300
|
changedSelf.joinedWith.reason === MEETING_END_REASON.MEDIA_RELEASED);
|
package/src/meeting/index.ts
CHANGED
|
@@ -632,31 +632,47 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
632
632
|
* All multistream media requests sent out for this meeting have to go through them.
|
|
633
633
|
*/
|
|
634
634
|
this.mediaRequestManagers = {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
635
|
+
audio: new MediaRequestManager(
|
|
636
|
+
(mediaRequests) => {
|
|
637
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
638
|
+
LoggerProxy.logger.warn(
|
|
639
|
+
'Meeting:index#mediaRequestManager --> trying to send audio media request before media connection was created'
|
|
640
|
+
);
|
|
641
641
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
video: new MediaRequestManager(this.config.degradationPreferences, (mediaRequests) => {
|
|
648
|
-
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
649
|
-
LoggerProxy.logger.warn(
|
|
650
|
-
'Meeting:index#mediaRequestManager --> trying to send video media request before media connection was created'
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
this.mediaProperties.webrtcMediaConnection.requestMedia(
|
|
645
|
+
MediaType.AudioMain,
|
|
646
|
+
mediaRequests
|
|
651
647
|
);
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
// @ts-ignore - config coming from registerPlugin
|
|
651
|
+
degradationPreferences: this.config.degradationPreferences,
|
|
652
|
+
kind: 'audio',
|
|
653
|
+
}
|
|
654
|
+
),
|
|
655
|
+
video: new MediaRequestManager(
|
|
656
|
+
(mediaRequests) => {
|
|
657
|
+
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
658
|
+
LoggerProxy.logger.warn(
|
|
659
|
+
'Meeting:index#mediaRequestManager --> trying to send video media request before media connection was created'
|
|
660
|
+
);
|
|
652
661
|
|
|
653
|
-
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
this.mediaProperties.webrtcMediaConnection.requestMedia(
|
|
665
|
+
MediaType.VideoMain,
|
|
666
|
+
mediaRequests
|
|
667
|
+
);
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
// @ts-ignore - config coming from registerPlugin
|
|
671
|
+
degradationPreferences: this.config.degradationPreferences,
|
|
672
|
+
kind: 'video',
|
|
654
673
|
}
|
|
655
|
-
|
|
656
|
-
}),
|
|
674
|
+
),
|
|
657
675
|
screenShareAudio: new MediaRequestManager(
|
|
658
|
-
// @ts-ignore - config coming from registerPlugin
|
|
659
|
-
this.config.degradationPreferences,
|
|
660
676
|
(mediaRequests) => {
|
|
661
677
|
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
662
678
|
LoggerProxy.logger.warn(
|
|
@@ -669,11 +685,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
669
685
|
MediaType.AudioSlides,
|
|
670
686
|
mediaRequests
|
|
671
687
|
);
|
|
688
|
+
},
|
|
689
|
+
{
|
|
690
|
+
// @ts-ignore - config coming from registerPlugin
|
|
691
|
+
degradationPreferences: this.config.degradationPreferences,
|
|
692
|
+
kind: 'audio',
|
|
672
693
|
}
|
|
673
694
|
),
|
|
674
695
|
screenShareVideo: new MediaRequestManager(
|
|
675
|
-
// @ts-ignore - config coming from registerPlugin
|
|
676
|
-
this.config.degradationPreferences,
|
|
677
696
|
(mediaRequests) => {
|
|
678
697
|
if (!this.mediaProperties.webrtcMediaConnection) {
|
|
679
698
|
LoggerProxy.logger.warn(
|
|
@@ -686,6 +705,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
686
705
|
MediaType.VideoSlides,
|
|
687
706
|
mediaRequests
|
|
688
707
|
);
|
|
708
|
+
},
|
|
709
|
+
{
|
|
710
|
+
// @ts-ignore - config coming from registerPlugin
|
|
711
|
+
degradationPreferences: this.config.degradationPreferences,
|
|
712
|
+
kind: 'video',
|
|
689
713
|
}
|
|
690
714
|
),
|
|
691
715
|
};
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
ReceiverSelectedInfo,
|
|
7
7
|
CodecInfo as WcmeCodecInfo,
|
|
8
8
|
H264Codec,
|
|
9
|
+
getRecommendedMaxBitrateForFrameSize,
|
|
10
|
+
RecommendedOpusBitrates,
|
|
9
11
|
} from '@webex/internal-media-core';
|
|
10
12
|
import {cloneDeep, debounce, isEmpty} from 'lodash';
|
|
11
13
|
|
|
@@ -64,10 +66,17 @@ type DegradationPreferences = {
|
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
type SendMediaRequestsCallback = (mediaRequests: WcmeMediaRequest[]) => void;
|
|
69
|
+
type Kind = 'audio' | 'video';
|
|
67
70
|
|
|
71
|
+
type Options = {
|
|
72
|
+
degradationPreferences: DegradationPreferences;
|
|
73
|
+
kind: Kind;
|
|
74
|
+
};
|
|
68
75
|
export class MediaRequestManager {
|
|
69
76
|
private sendMediaRequestsCallback: SendMediaRequestsCallback;
|
|
70
77
|
|
|
78
|
+
private kind: Kind;
|
|
79
|
+
|
|
71
80
|
private counter: number;
|
|
72
81
|
|
|
73
82
|
private clientRequests: {[key: MediaRequestId]: MediaRequest};
|
|
@@ -80,14 +89,12 @@ export class MediaRequestManager {
|
|
|
80
89
|
|
|
81
90
|
private previousWCMEMediaRequests: Array<WcmeMediaRequest> = [];
|
|
82
91
|
|
|
83
|
-
constructor(
|
|
84
|
-
degradationPreferences: DegradationPreferences,
|
|
85
|
-
sendMediaRequestsCallback: SendMediaRequestsCallback
|
|
86
|
-
) {
|
|
92
|
+
constructor(sendMediaRequestsCallback: SendMediaRequestsCallback, options: Options) {
|
|
87
93
|
this.sendMediaRequestsCallback = sendMediaRequestsCallback;
|
|
88
94
|
this.counter = 0;
|
|
89
95
|
this.clientRequests = {};
|
|
90
|
-
this.degradationPreferences = degradationPreferences;
|
|
96
|
+
this.degradationPreferences = options.degradationPreferences;
|
|
97
|
+
this.kind = options.kind;
|
|
91
98
|
this.sourceUpdateListener = this.commit.bind(this);
|
|
92
99
|
this.debouncedSourceUpdateListener = debounce(
|
|
93
100
|
this.sourceUpdateListener,
|
|
@@ -175,6 +182,45 @@ export class MediaRequestManager {
|
|
|
175
182
|
);
|
|
176
183
|
}
|
|
177
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Returns the maxPayloadBitsPerSecond per Stream
|
|
187
|
+
*
|
|
188
|
+
* If MediaRequestManager kind is "audio", a constant bitrate will be returned.
|
|
189
|
+
* If MediaRequestManager kind is "video", the bitrate will be calculated based
|
|
190
|
+
* on maxFs (default h264 maxFs as fallback if maxFs is not defined)
|
|
191
|
+
*
|
|
192
|
+
* @param {MediaRequest} mediaRequest - mediaRequest to take data from
|
|
193
|
+
* @returns {number} maxPayloadBitsPerSecond
|
|
194
|
+
*/
|
|
195
|
+
private getMaxPayloadBitsPerSecond(mediaRequest: MediaRequest): number {
|
|
196
|
+
if (this.kind === 'audio') {
|
|
197
|
+
// return mono_music bitrate default if the kind of mediarequest manager is audio:
|
|
198
|
+
return RecommendedOpusBitrates.FB_MONO_MUSIC;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return getRecommendedMaxBitrateForFrameSize(
|
|
202
|
+
mediaRequest.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Returns the max Macro Blocks per second (maxMbps) per H264 Stream
|
|
208
|
+
*
|
|
209
|
+
* The maxMbps will be calculated based on maxFs and maxFps
|
|
210
|
+
* (default h264 maxFps as fallback if maxFps is not defined)
|
|
211
|
+
*
|
|
212
|
+
* @param {MediaRequest} mediaRequest - mediaRequest to take data from
|
|
213
|
+
* @returns {number} maxMbps
|
|
214
|
+
*/
|
|
215
|
+
// eslint-disable-next-line class-methods-use-this
|
|
216
|
+
private getH264MaxMbps(mediaRequest: MediaRequest): number {
|
|
217
|
+
// fallback for maxFps (not needed for maxFs, since there is a fallback already in getDegradedClientRequests)
|
|
218
|
+
const maxFps = mediaRequest.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps;
|
|
219
|
+
|
|
220
|
+
// divided by 100 since maxFps is 3000 (for 30 frames per seconds)
|
|
221
|
+
return (mediaRequest.codecInfo.maxFs * maxFps) / 100;
|
|
222
|
+
}
|
|
223
|
+
|
|
178
224
|
/**
|
|
179
225
|
* Clears the previous media requests.
|
|
180
226
|
*
|
|
@@ -188,7 +234,6 @@ export class MediaRequestManager {
|
|
|
188
234
|
const wcmeMediaRequests: WcmeMediaRequest[] = [];
|
|
189
235
|
|
|
190
236
|
const clientRequests = this.getDegradedClientRequests();
|
|
191
|
-
const maxPayloadBitsPerSecond = 10 * 1000 * 1000;
|
|
192
237
|
|
|
193
238
|
// map all the client media requests to wcme media requests
|
|
194
239
|
Object.values(clientRequests).forEach((mr) => {
|
|
@@ -206,14 +251,14 @@ export class MediaRequestManager {
|
|
|
206
251
|
)
|
|
207
252
|
: new ReceiverSelectedInfo(mr.policyInfo.csi),
|
|
208
253
|
mr.receiveSlots.map((receiveSlot) => receiveSlot.wcmeReceiveSlot),
|
|
209
|
-
|
|
254
|
+
this.getMaxPayloadBitsPerSecond(mr),
|
|
210
255
|
mr.codecInfo && [
|
|
211
256
|
new WcmeCodecInfo(
|
|
212
257
|
0x80,
|
|
213
258
|
new H264Codec(
|
|
214
259
|
mr.codecInfo.maxFs,
|
|
215
260
|
mr.codecInfo.maxFps || CODEC_DEFAULTS.h264.maxFps,
|
|
216
|
-
mr
|
|
261
|
+
this.getH264MaxMbps(mr),
|
|
217
262
|
mr.codecInfo.maxWidth,
|
|
218
263
|
mr.codecInfo.maxHeight
|
|
219
264
|
)
|
|
@@ -4,7 +4,7 @@ import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
|
|
|
4
4
|
import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
|
|
5
5
|
import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
|
|
6
6
|
import Metrics from '@webex/plugin-meetings/src/metrics/index';
|
|
7
|
-
import {DISPLAY_HINTS} from '@webex/plugin-meetings/
|
|
7
|
+
import {DISPLAY_HINTS} from '@webex/plugin-meetings/src/constants';
|
|
8
8
|
|
|
9
9
|
describe('plugin-meetings', () => {
|
|
10
10
|
describe('Meeting utils function', () => {
|