@webex/plugin-meetings 3.0.0-beta.30 → 3.0.0-beta.32

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.
@@ -15,6 +15,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/he
15
15
  var _cloneDeep2 = _interopRequireDefault(require("lodash/cloneDeep"));
16
16
  var _internalMediaCore = require("@webex/internal-media-core");
17
17
  var _loggerProxy = _interopRequireDefault(require("../common/logs/logger-proxy"));
18
+ var _receiveSlot = require("./receiveSlot");
18
19
  var _remoteMedia = require("./remoteMedia");
19
20
  /* eslint-disable require-jsdoc */
20
21
 
@@ -33,11 +34,13 @@ var MediaRequestManager = /*#__PURE__*/function () {
33
34
  (0, _defineProperty2.default)(this, "clientRequests", void 0);
34
35
  (0, _defineProperty2.default)(this, "slotsActiveInLastMediaRequest", void 0);
35
36
  (0, _defineProperty2.default)(this, "degradationPreferences", void 0);
37
+ (0, _defineProperty2.default)(this, "sourceUpdateListener", void 0);
36
38
  this.sendMediaRequestsCallback = sendMediaRequestsCallback;
37
39
  this.counter = 0;
38
40
  this.clientRequests = {};
39
41
  this.slotsActiveInLastMediaRequest = {};
40
42
  this.degradationPreferences = degradationPreferences;
43
+ this.sourceUpdateListener = this.commit.bind(this);
41
44
  }
42
45
  (0, _createClass2.default)(MediaRequestManager, [{
43
46
  key: "resetInactiveReceiveSlots",
@@ -81,15 +84,22 @@ var MediaRequestManager = /*#__PURE__*/function () {
81
84
  // reduce max-fs until total macroblocks is below limit
82
85
  var _loop = function _loop(i) {
83
86
  var totalMacroblocksRequested = 0;
84
- (0, _values.default)(clientRequests).forEach(function (mr) {
87
+ (0, _entries.default)(clientRequests).forEach(function (_ref) {
88
+ var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
89
+ id = _ref2[0],
90
+ mr = _ref2[1];
85
91
  if (mr.codecInfo) {
86
92
  mr.codecInfo.maxFs = Math.min(mr.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs, maxFsLimits[i]);
87
- totalMacroblocksRequested += mr.codecInfo.maxFs * mr.receiveSlots.length;
93
+ // we only consider sources with "live" state
94
+ var slotsWithLiveSource = _this.clientRequests[id].receiveSlots.filter(function (rs) {
95
+ return rs.sourceState === 'live';
96
+ });
97
+ totalMacroblocksRequested += mr.codecInfo.maxFs * slotsWithLiveSource.length;
88
98
  }
89
99
  });
90
100
  if (totalMacroblocksRequested <= _this.degradationPreferences.maxMacroblocksLimit) {
91
101
  if (i !== 0) {
92
- _loggerProxy.default.logger.warn("multistream:mediaRequestManager --> too many requests with high max-fs, frame size will be limited to ".concat(maxFsLimits[i]));
102
+ _loggerProxy.default.logger.warn("multistream:mediaRequestManager --> too many streams with high max-fs, frame size will be limited to ".concat(maxFsLimits[i]));
93
103
  }
94
104
  return "break";
95
105
  } else if (i === maxFsLimits.length - 1) {
@@ -121,10 +131,14 @@ var MediaRequestManager = /*#__PURE__*/function () {
121
131
  }, {
122
132
  key: "addRequest",
123
133
  value: function addRequest(mediaRequest) {
134
+ var _this2 = this;
124
135
  var commit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
125
136
  // eslint-disable-next-line no-plusplus
126
137
  var newId = "".concat(this.counter++);
127
138
  this.clientRequests[newId] = mediaRequest;
139
+ mediaRequest.receiveSlots.forEach(function (rs) {
140
+ rs.on(_receiveSlot.ReceiveSlotEvents.SourceUpdate, _this2.sourceUpdateListener);
141
+ });
128
142
  if (commit) {
129
143
  this.commit();
130
144
  }
@@ -133,7 +147,12 @@ var MediaRequestManager = /*#__PURE__*/function () {
133
147
  }, {
134
148
  key: "cancelRequest",
135
149
  value: function cancelRequest(requestId) {
150
+ var _this$clientRequests$,
151
+ _this3 = this;
136
152
  var commit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
153
+ (_this$clientRequests$ = this.clientRequests[requestId]) === null || _this$clientRequests$ === void 0 ? void 0 : _this$clientRequests$.receiveSlots.forEach(function (rs) {
154
+ rs.off(_receiveSlot.ReceiveSlotEvents.SourceUpdate, _this3.sourceUpdateListener);
155
+ });
137
156
  delete this.clientRequests[requestId];
138
157
  if (commit) {
139
158
  this.commit();
@@ -1 +1 @@
1
- {"version":3,"names":["CODEC_DEFAULTS","h264","maxFs","maxFps","maxMbps","MediaRequestManager","degradationPreferences","sendMediaRequestsCallback","counter","clientRequests","slotsActiveInLastMediaRequest","activeSlots","forEach","request","receiveSlots","slot","id","slotId","LoggerProxy","logger","info","resetSourceState","sendRequests","maxFsLimits","getMaxFs","totalMacroblocksRequested","mr","codecInfo","Math","min","i","length","maxMacroblocksLimit","warn","wcmeMediaRequests","getDegradedClientRequests","maxPayloadBitsPerSecond","push","WcmeMediaRequest","policyInfo","policy","Policy","ActiveSpeaker","ReceiverSelected","ActiveSpeakerInfo","priority","crossPriorityDuplication","crossPolicyDuplication","preferLiveVideo","ReceiverSelectedInfo","csi","map","receiveSlot","wcmeReceiveSlot","WcmeCodecInfo","H264Codec","maxWidth","maxHeight","resetInactiveReceiveSlots","mediaRequest","commit","newId","requestId"],"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} from 'lodash';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\n\nimport {ReceiveSlot, ReceiveSlotId} 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}\n\nexport type MediaRequestId = string;\n\nconst CODEC_DEFAULTS = {\n h264: {\n maxFs: 8192,\n maxFps: 3000,\n maxMbps: 245760,\n },\n};\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 slotsActiveInLastMediaRequest: {[key: ReceiveSlotId]: ReceiveSlot};\n\n private degradationPreferences: DegradationPreferences;\n\n constructor(\n degradationPreferences: DegradationPreferences,\n sendMediaRequestsCallback: SendMediaRequestsCallback\n ) {\n this.sendMediaRequestsCallback = sendMediaRequestsCallback;\n this.counter = 0;\n this.clientRequests = {};\n this.slotsActiveInLastMediaRequest = {};\n this.degradationPreferences = degradationPreferences;\n }\n\n private resetInactiveReceiveSlots() {\n const activeSlots: {[key: ReceiveSlotId]: ReceiveSlot} = {};\n\n // create a map of all currently used slot ids\n Object.values(this.clientRequests).forEach((request) =>\n request.receiveSlots.forEach((slot) => {\n activeSlots[slot.id] = slot;\n })\n );\n\n // when we stop using some receive slots and they are not included in the new media request,\n // we will never get a 'no source' notification for them, so we reset their state,\n // so that the client doesn't try to display their video anymore\n for (const [slotId, slot] of Object.entries(this.slotsActiveInLastMediaRequest)) {\n if (!(slotId in activeSlots)) {\n LoggerProxy.logger.info(\n `multistream:mediaRequestManager --> resetting sourceState to \"no source\" for slot ${slot.id}`\n );\n slot.resetSourceState();\n }\n }\n\n this.slotsActiveInLastMediaRequest = activeSlots;\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.values(clientRequests).forEach((mr) => {\n if (mr.codecInfo) {\n mr.codecInfo.maxFs = Math.min(\n mr.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs,\n maxFsLimits[i]\n );\n totalMacroblocksRequested += mr.codecInfo.maxFs * mr.receiveSlots.length;\n }\n });\n if (totalMacroblocksRequested <= this.degradationPreferences.maxMacroblocksLimit) {\n if (i !== 0) {\n LoggerProxy.logger.warn(\n `multistream:mediaRequestManager --> too many requests 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 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 this.sendMediaRequestsCallback(wcmeMediaRequests);\n\n this.resetInactiveReceiveSlots();\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 if (commit) {\n this.commit();\n }\n\n return newId;\n }\n\n public cancelRequest(requestId: MediaRequestId, commit = true) {\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 this.slotsActiveInLastMediaRequest = {};\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["CODEC_DEFAULTS","h264","maxFs","maxFps","maxMbps","MediaRequestManager","degradationPreferences","sendMediaRequestsCallback","counter","clientRequests","slotsActiveInLastMediaRequest","sourceUpdateListener","commit","bind","activeSlots","forEach","request","receiveSlots","slot","id","slotId","LoggerProxy","logger","info","resetSourceState","sendRequests","maxFsLimits","getMaxFs","totalMacroblocksRequested","mr","codecInfo","Math","min","i","slotsWithLiveSource","filter","rs","sourceState","length","maxMacroblocksLimit","warn","wcmeMediaRequests","getDegradedClientRequests","maxPayloadBitsPerSecond","push","WcmeMediaRequest","policyInfo","policy","Policy","ActiveSpeaker","ReceiverSelected","ActiveSpeakerInfo","priority","crossPriorityDuplication","crossPolicyDuplication","preferLiveVideo","ReceiverSelectedInfo","csi","map","receiveSlot","wcmeReceiveSlot","WcmeCodecInfo","H264Codec","maxWidth","maxHeight","resetInactiveReceiveSlots","mediaRequest","newId","on","ReceiveSlotEvents","SourceUpdate","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} from 'lodash';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\n\nimport {ReceiveSlot, ReceiveSlotEvents, ReceiveSlotId} 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}\n\nexport type MediaRequestId = string;\n\nconst CODEC_DEFAULTS = {\n h264: {\n maxFs: 8192,\n maxFps: 3000,\n maxMbps: 245760,\n },\n};\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 slotsActiveInLastMediaRequest: {[key: ReceiveSlotId]: ReceiveSlot};\n\n private degradationPreferences: DegradationPreferences;\n\n private sourceUpdateListener: () => void;\n\n constructor(\n degradationPreferences: DegradationPreferences,\n sendMediaRequestsCallback: SendMediaRequestsCallback\n ) {\n this.sendMediaRequestsCallback = sendMediaRequestsCallback;\n this.counter = 0;\n this.clientRequests = {};\n this.slotsActiveInLastMediaRequest = {};\n this.degradationPreferences = degradationPreferences;\n this.sourceUpdateListener = this.commit.bind(this);\n }\n\n private resetInactiveReceiveSlots() {\n const activeSlots: {[key: ReceiveSlotId]: ReceiveSlot} = {};\n\n // create a map of all currently used slot ids\n Object.values(this.clientRequests).forEach((request) =>\n request.receiveSlots.forEach((slot) => {\n activeSlots[slot.id] = slot;\n })\n );\n\n // when we stop using some receive slots and they are not included in the new media request,\n // we will never get a 'no source' notification for them, so we reset their state,\n // so that the client doesn't try to display their video anymore\n for (const [slotId, slot] of Object.entries(this.slotsActiveInLastMediaRequest)) {\n if (!(slotId in activeSlots)) {\n LoggerProxy.logger.info(\n `multistream:mediaRequestManager --> resetting sourceState to \"no source\" for slot ${slot.id}`\n );\n slot.resetSourceState();\n }\n }\n\n this.slotsActiveInLastMediaRequest = activeSlots;\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.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 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 this.sendMediaRequestsCallback(wcmeMediaRequests);\n\n this.resetInactiveReceiveSlots();\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 });\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 this.slotsActiveInLastMediaRequest = {};\n }\n}\n"],"mappings":"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"}
@@ -150,7 +150,7 @@ var RoapRequest = /*#__PURE__*/function (_StatelessWebexPlugin) {
150
150
 
151
151
  // always it will be the first mediaConnection Object
152
152
  var mediaConnections = res.body.mediaConnections && res.body.mediaConnections.length > 0 && res.body.mediaConnections[0];
153
- _loggerProxy.default.logger.info("Roap:request#sendRoap --> response:".concat((0, _stringify.default)(mediaConnections, null, 2), "'\n StatusCode:'").concat(res.statusCode));
153
+ _loggerProxy.default.logger.debug("Roap:request#sendRoap --> response:".concat((0, _stringify.default)(mediaConnections, null, 2), "'\n StatusCode:'").concat(res.statusCode));
154
154
  var locus = res.body.locus;
155
155
  locus.roapSeq = options.roapMessage.seq;
156
156
  return _objectSpread({
@@ -1 +1 @@
1
- {"version":3,"names":["RoapRequest","localSdp","webex","boundedStorage","get","REACHABILITY","namespace","localStorage","catch","reachabilityData","reachabilityResult","JSON","parse","length","reachability","e","LoggerProxy","logger","error","options","roapMessage","locusSelfUrl","mediaId","correlationId","meetingId","info","mediaUrl","MEDIA","deviceUrl","internal","device","url","messageType","seq","Metrics","postEvent","event","eventType","MEDIA_REQUEST","attachRechabilityData","audioMuted","videoMuted","then","sdpWithReachability","request","uri","method","HTTP_VERBS","PUT","body","deviceType","config","meetings","localMedias","clientMediaPreferences","preferTranscoding","res","MEDIA_RESPONSE","mediaConnections","statusCode","locus","roapSeq","err","data","parseLocusError","StatelessWebexPlugin"],"sources":["request.ts"],"sourcesContent":["/* global window */\n// @ts-ignore\nimport {StatelessWebexPlugin} from '@webex/webex-core';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport {MEDIA, HTTP_VERBS, REACHABILITY} from '../constants';\nimport Metrics from '../metrics';\nimport {eventType} from '../metrics/config';\n\n/**\n * @class RoapRequest\n */\nexport default class RoapRequest extends StatelessWebexPlugin {\n /**\n * Joins a meeting via ROAP\n * @param {Object} localSdp\n * @returns {Promise} returns a promise that resolves/rejects whatever the request does\n */\n async attachRechabilityData(localSdp) {\n // @ts-ignore\n const reachabilityData = await this.webex.boundedStorage\n .get(REACHABILITY.namespace, REACHABILITY.localStorage)\n .catch(() => {});\n\n if (reachabilityData) {\n try {\n const reachabilityResult = JSON.parse(reachabilityData);\n\n /* istanbul ignore else */\n if (reachabilityResult && Object.keys(reachabilityResult).length) {\n localSdp.reachability = reachabilityResult;\n }\n } catch (e) {\n LoggerProxy.logger.error(\n `Roap:request#attachReachabilityData --> Error in parsing reachability data: ${e}`\n );\n }\n }\n\n return localSdp;\n }\n\n /**\n * Sends a ROAP message\n * @param {Object} options\n * @param {Object} options.roapMessage\n * @param {String} options.locusSelfUrl\n * @param {String} options.mediaId\n * @param {String} options.correlationId\n * @param {Boolean} options.audioMuted\n * @param {Boolean} options.videoMuted\n * @param {String} options.meetingId\n * @param {Boolean} options.preferTranscoding\n * @returns {Promise} returns the response/failure of the request\n */\n sendRoap(options: {\n roapMessage: any;\n locusSelfUrl: string;\n mediaId: string;\n correlationId: string;\n audioMuted: boolean;\n videoMuted: boolean;\n meetingId: string;\n preferTranscoding?: boolean;\n }) {\n const {roapMessage, locusSelfUrl, mediaId, correlationId, meetingId} = options;\n\n if (!mediaId) {\n LoggerProxy.logger.info('Roap:request#sendRoap --> Race Condition /call mediaID not present');\n }\n\n const mediaUrl = `${locusSelfUrl}/${MEDIA}`;\n // @ts-ignore\n const deviceUrl = this.webex.internal.device.url;\n\n LoggerProxy.logger.info(\n `Roap:request#sendRoap --> ${mediaUrl} \\n ${roapMessage.messageType} \\n seq:${roapMessage.seq}`\n );\n\n Metrics.postEvent({event: eventType.MEDIA_REQUEST, meetingId});\n\n return this.attachRechabilityData({\n roapMessage,\n // eslint-disable-next-line no-warning-comments\n // TODO: check whats the need for video and audiomute\n audioMuted: !!options.audioMuted,\n videoMuted: !!options.videoMuted,\n }).then((sdpWithReachability) => {\n // @ts-ignore\n return this.webex\n .request({\n uri: mediaUrl,\n method: HTTP_VERBS.PUT,\n body: {\n device: {\n url: deviceUrl,\n // @ts-ignore\n deviceType: this.config.meetings.deviceType,\n },\n correlationId,\n localMedias: [\n {\n localSdp: JSON.stringify(sdpWithReachability),\n mediaId: options.mediaId,\n },\n ],\n clientMediaPreferences: {\n preferTranscoding: options.preferTranscoding ?? true,\n },\n },\n })\n .then((res) => {\n Metrics.postEvent({event: eventType.MEDIA_RESPONSE, meetingId});\n\n // always it will be the first mediaConnection Object\n const mediaConnections =\n res.body.mediaConnections &&\n res.body.mediaConnections.length > 0 &&\n res.body.mediaConnections[0];\n\n LoggerProxy.logger.info(\n `Roap:request#sendRoap --> response:${JSON.stringify(\n mediaConnections,\n null,\n 2\n )}'\\n StatusCode:'${res.statusCode}`\n );\n const {locus} = res.body;\n\n locus.roapSeq = options.roapMessage.seq;\n\n return {\n locus,\n ...(mediaConnections && {mediaConnections: res.body.mediaConnections}),\n };\n })\n .catch((err) => {\n Metrics.postEvent({\n event: eventType.MEDIA_RESPONSE,\n meetingId,\n data: {error: Metrics.parseLocusError(err, true)},\n });\n LoggerProxy.logger.error(\n `Roap:request#sendRoap --> Error:${JSON.stringify(err, null, 2)}`\n );\n LoggerProxy.logger.error(\n `Roap:request#sendRoapRequest --> errorBody:${JSON.stringify(\n roapMessage,\n null,\n 2\n )} + '\\\\n mediaId:'${options.mediaId}`\n );\n throw err;\n });\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAEA;AAEA;AACA;AACA;AACA;AAA4C;AAAA;AAAA;AAAA;AAE5C;AACA;AACA;AAFA,IAGqBA,WAAW;EAAA;EAAA;EAAA;IAAA;IAAA;EAAA;EAAA;IAAA;IAAA;IAC9B;AACF;AACA;AACA;AACA;IAJE;MAAA,qGAKA,iBAA4BC,QAAQ;QAAA;QAAA;UAAA;YAAA;cAAA;cAAA,OAEH,IAAI,CAACC,KAAK,CAACC,cAAc,CACrDC,GAAG,CAACC,uBAAY,CAACC,SAAS,EAAED,uBAAY,CAACE,YAAY,CAAC,CACtDC,KAAK,CAAC,YAAM,CAAC,CAAC,CAAC;YAAA;cAFZC,gBAAgB;cAItB,IAAIA,gBAAgB,EAAE;gBACpB,IAAI;kBACIC,kBAAkB,GAAGC,IAAI,CAACC,KAAK,CAACH,gBAAgB,CAAC;kBAEvD;kBACA,IAAIC,kBAAkB,IAAI,mBAAYA,kBAAkB,CAAC,CAACG,MAAM,EAAE;oBAChEZ,QAAQ,CAACa,YAAY,GAAGJ,kBAAkB;kBAC5C;gBACF,CAAC,CAAC,OAAOK,CAAC,EAAE;kBACVC,oBAAW,CAACC,MAAM,CAACC,KAAK,uFACyDH,CAAC,EACjF;gBACH;cACF;cAAC,iCAEMd,QAAQ;YAAA;YAAA;cAAA;UAAA;QAAA;MAAA,CAChB;MAAA;QAAA;MAAA;MAAA;IAAA;IAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EAZE;IAAA;IAAA,OAaA,kBAASkB,OASR,EAAE;MAAA;MACD,IAAOC,WAAW,GAAqDD,OAAO,CAAvEC,WAAW;QAAEC,YAAY,GAAuCF,OAAO,CAA1DE,YAAY;QAAEC,OAAO,GAA8BH,OAAO,CAA5CG,OAAO;QAAEC,aAAa,GAAeJ,OAAO,CAAnCI,aAAa;QAAEC,SAAS,GAAIL,OAAO,CAApBK,SAAS;MAEnE,IAAI,CAACF,OAAO,EAAE;QACZN,oBAAW,CAACC,MAAM,CAACQ,IAAI,CAAC,oEAAoE,CAAC;MAC/F;MAEA,IAAMC,QAAQ,aAAML,YAAY,cAAIM,gBAAK,CAAE;MAC3C;MACA,IAAMC,SAAS,GAAG,IAAI,CAAC1B,KAAK,CAAC2B,QAAQ,CAACC,MAAM,CAACC,GAAG;MAEhDf,oBAAW,CAACC,MAAM,CAACQ,IAAI,qCACQC,QAAQ,iBAAON,WAAW,CAACY,WAAW,qBAAWZ,WAAW,CAACa,GAAG,EAC9F;MAEDC,gBAAO,CAACC,SAAS,CAAC;QAACC,KAAK,EAAEC,iBAAS,CAACC,aAAa;QAAEd,SAAS,EAATA;MAAS,CAAC,CAAC;MAE9D,OAAO,IAAI,CAACe,qBAAqB,CAAC;QAChCnB,WAAW,EAAXA,WAAW;QACX;QACA;QACAoB,UAAU,EAAE,CAAC,CAACrB,OAAO,CAACqB,UAAU;QAChCC,UAAU,EAAE,CAAC,CAACtB,OAAO,CAACsB;MACxB,CAAC,CAAC,CAACC,IAAI,CAAC,UAACC,mBAAmB,EAAK;QAAA;QAC/B;QACA,OAAO,KAAI,CAACzC,KAAK,CACd0C,OAAO,CAAC;UACPC,GAAG,EAAEnB,QAAQ;UACboB,MAAM,EAAEC,qBAAU,CAACC,GAAG;UACtBC,IAAI,EAAE;YACJnB,MAAM,EAAE;cACNC,GAAG,EAAEH,SAAS;cACd;cACAsB,UAAU,EAAE,KAAI,CAACC,MAAM,CAACC,QAAQ,CAACF;YACnC,CAAC;YACD3B,aAAa,EAAbA,aAAa;YACb8B,WAAW,EAAE,CACX;cACEpD,QAAQ,EAAE,wBAAe0C,mBAAmB,CAAC;cAC7CrB,OAAO,EAAEH,OAAO,CAACG;YACnB,CAAC,CACF;YACDgC,sBAAsB,EAAE;cACtBC,iBAAiB,2BAAEpC,OAAO,CAACoC,iBAAiB,yEAAI;YAClD;UACF;QACF,CAAC,CAAC,CACDb,IAAI,CAAC,UAACc,GAAG,EAAK;UACbtB,gBAAO,CAACC,SAAS,CAAC;YAACC,KAAK,EAAEC,iBAAS,CAACoB,cAAc;YAAEjC,SAAS,EAATA;UAAS,CAAC,CAAC;;UAE/D;UACA,IAAMkC,gBAAgB,GACpBF,GAAG,CAACP,IAAI,CAACS,gBAAgB,IACzBF,GAAG,CAACP,IAAI,CAACS,gBAAgB,CAAC7C,MAAM,GAAG,CAAC,IACpC2C,GAAG,CAACP,IAAI,CAACS,gBAAgB,CAAC,CAAC,CAAC;UAE9B1C,oBAAW,CAACC,MAAM,CAACQ,IAAI,8CACiB,wBACpCiC,gBAAgB,EAChB,IAAI,EACJ,CAAC,CACF,6BAAmBF,GAAG,CAACG,UAAU,EACnC;UACD,IAAOC,KAAK,GAAIJ,GAAG,CAACP,IAAI,CAAjBW,KAAK;UAEZA,KAAK,CAACC,OAAO,GAAG1C,OAAO,CAACC,WAAW,CAACa,GAAG;UAEvC;YACE2B,KAAK,EAALA;UAAK,GACDF,gBAAgB,IAAI;YAACA,gBAAgB,EAAEF,GAAG,CAACP,IAAI,CAACS;UAAgB,CAAC;QAEzE,CAAC,CAAC,CACDlD,KAAK,CAAC,UAACsD,GAAG,EAAK;UACd5B,gBAAO,CAACC,SAAS,CAAC;YAChBC,KAAK,EAAEC,iBAAS,CAACoB,cAAc;YAC/BjC,SAAS,EAATA,SAAS;YACTuC,IAAI,EAAE;cAAC7C,KAAK,EAAEgB,gBAAO,CAAC8B,eAAe,CAACF,GAAG,EAAE,IAAI;YAAC;UAClD,CAAC,CAAC;UACF9C,oBAAW,CAACC,MAAM,CAACC,KAAK,2CACa,wBAAe4C,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAChE;UACD9C,oBAAW,CAACC,MAAM,CAACC,KAAK,sDACwB,wBAC5CE,WAAW,EACX,IAAI,EACJ,CAAC,CACF,8BAAoBD,OAAO,CAACG,OAAO,EACrC;UACD,MAAMwC,GAAG;QACX,CAAC,CAAC;MACN,CAAC,CAAC;IACJ;EAAC;EAAA;AAAA,EA/IsCG,+BAAoB;AAAA"}
1
+ {"version":3,"names":["RoapRequest","localSdp","webex","boundedStorage","get","REACHABILITY","namespace","localStorage","catch","reachabilityData","reachabilityResult","JSON","parse","length","reachability","e","LoggerProxy","logger","error","options","roapMessage","locusSelfUrl","mediaId","correlationId","meetingId","info","mediaUrl","MEDIA","deviceUrl","internal","device","url","messageType","seq","Metrics","postEvent","event","eventType","MEDIA_REQUEST","attachRechabilityData","audioMuted","videoMuted","then","sdpWithReachability","request","uri","method","HTTP_VERBS","PUT","body","deviceType","config","meetings","localMedias","clientMediaPreferences","preferTranscoding","res","MEDIA_RESPONSE","mediaConnections","debug","statusCode","locus","roapSeq","err","data","parseLocusError","StatelessWebexPlugin"],"sources":["request.ts"],"sourcesContent":["/* global window */\n// @ts-ignore\nimport {StatelessWebexPlugin} from '@webex/webex-core';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport {MEDIA, HTTP_VERBS, REACHABILITY} from '../constants';\nimport Metrics from '../metrics';\nimport {eventType} from '../metrics/config';\n\n/**\n * @class RoapRequest\n */\nexport default class RoapRequest extends StatelessWebexPlugin {\n /**\n * Joins a meeting via ROAP\n * @param {Object} localSdp\n * @returns {Promise} returns a promise that resolves/rejects whatever the request does\n */\n async attachRechabilityData(localSdp) {\n // @ts-ignore\n const reachabilityData = await this.webex.boundedStorage\n .get(REACHABILITY.namespace, REACHABILITY.localStorage)\n .catch(() => {});\n\n if (reachabilityData) {\n try {\n const reachabilityResult = JSON.parse(reachabilityData);\n\n /* istanbul ignore else */\n if (reachabilityResult && Object.keys(reachabilityResult).length) {\n localSdp.reachability = reachabilityResult;\n }\n } catch (e) {\n LoggerProxy.logger.error(\n `Roap:request#attachReachabilityData --> Error in parsing reachability data: ${e}`\n );\n }\n }\n\n return localSdp;\n }\n\n /**\n * Sends a ROAP message\n * @param {Object} options\n * @param {Object} options.roapMessage\n * @param {String} options.locusSelfUrl\n * @param {String} options.mediaId\n * @param {String} options.correlationId\n * @param {Boolean} options.audioMuted\n * @param {Boolean} options.videoMuted\n * @param {String} options.meetingId\n * @param {Boolean} options.preferTranscoding\n * @returns {Promise} returns the response/failure of the request\n */\n sendRoap(options: {\n roapMessage: any;\n locusSelfUrl: string;\n mediaId: string;\n correlationId: string;\n audioMuted: boolean;\n videoMuted: boolean;\n meetingId: string;\n preferTranscoding?: boolean;\n }) {\n const {roapMessage, locusSelfUrl, mediaId, correlationId, meetingId} = options;\n\n if (!mediaId) {\n LoggerProxy.logger.info('Roap:request#sendRoap --> Race Condition /call mediaID not present');\n }\n\n const mediaUrl = `${locusSelfUrl}/${MEDIA}`;\n // @ts-ignore\n const deviceUrl = this.webex.internal.device.url;\n\n LoggerProxy.logger.info(\n `Roap:request#sendRoap --> ${mediaUrl} \\n ${roapMessage.messageType} \\n seq:${roapMessage.seq}`\n );\n\n Metrics.postEvent({event: eventType.MEDIA_REQUEST, meetingId});\n\n return this.attachRechabilityData({\n roapMessage,\n // eslint-disable-next-line no-warning-comments\n // TODO: check whats the need for video and audiomute\n audioMuted: !!options.audioMuted,\n videoMuted: !!options.videoMuted,\n }).then((sdpWithReachability) => {\n // @ts-ignore\n return this.webex\n .request({\n uri: mediaUrl,\n method: HTTP_VERBS.PUT,\n body: {\n device: {\n url: deviceUrl,\n // @ts-ignore\n deviceType: this.config.meetings.deviceType,\n },\n correlationId,\n localMedias: [\n {\n localSdp: JSON.stringify(sdpWithReachability),\n mediaId: options.mediaId,\n },\n ],\n clientMediaPreferences: {\n preferTranscoding: options.preferTranscoding ?? true,\n },\n },\n })\n .then((res) => {\n Metrics.postEvent({event: eventType.MEDIA_RESPONSE, meetingId});\n\n // always it will be the first mediaConnection Object\n const mediaConnections =\n res.body.mediaConnections &&\n res.body.mediaConnections.length > 0 &&\n res.body.mediaConnections[0];\n\n LoggerProxy.logger.debug(\n `Roap:request#sendRoap --> response:${JSON.stringify(\n mediaConnections,\n null,\n 2\n )}'\\n StatusCode:'${res.statusCode}`\n );\n const {locus} = res.body;\n\n locus.roapSeq = options.roapMessage.seq;\n\n return {\n locus,\n ...(mediaConnections && {mediaConnections: res.body.mediaConnections}),\n };\n })\n .catch((err) => {\n Metrics.postEvent({\n event: eventType.MEDIA_RESPONSE,\n meetingId,\n data: {error: Metrics.parseLocusError(err, true)},\n });\n LoggerProxy.logger.error(\n `Roap:request#sendRoap --> Error:${JSON.stringify(err, null, 2)}`\n );\n LoggerProxy.logger.error(\n `Roap:request#sendRoapRequest --> errorBody:${JSON.stringify(\n roapMessage,\n null,\n 2\n )} + '\\\\n mediaId:'${options.mediaId}`\n );\n throw err;\n });\n });\n }\n}\n"],"mappings":"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"}
@@ -37,6 +37,7 @@ export declare class MediaRequestManager {
37
37
  private clientRequests;
38
38
  private slotsActiveInLastMediaRequest;
39
39
  private degradationPreferences;
40
+ private sourceUpdateListener;
40
41
  constructor(degradationPreferences: DegradationPreferences, sendMediaRequestsCallback: SendMediaRequestsCallback);
41
42
  private resetInactiveReceiveSlots;
42
43
  setDegradationPreferences(degradationPreferences: DegradationPreferences): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.30",
3
+ "version": "3.0.0-beta.32",
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.30",
36
- "@webex/test-helper-chai": "3.0.0-beta.30",
37
- "@webex/test-helper-mocha": "3.0.0-beta.30",
38
- "@webex/test-helper-mock-webex": "3.0.0-beta.30",
39
- "@webex/test-helper-retry": "3.0.0-beta.30",
40
- "@webex/test-helper-test-users": "3.0.0-beta.30",
35
+ "@webex/plugin-meetings": "3.0.0-beta.32",
36
+ "@webex/test-helper-chai": "3.0.0-beta.32",
37
+ "@webex/test-helper-mocha": "3.0.0-beta.32",
38
+ "@webex/test-helper-mock-webex": "3.0.0-beta.32",
39
+ "@webex/test-helper-retry": "3.0.0-beta.32",
40
+ "@webex/test-helper-test-users": "3.0.0-beta.32",
41
41
  "chai": "^4.3.4",
42
42
  "chai-as-promised": "^7.1.1",
43
43
  "jsdom-global": "3.0.2",
@@ -45,18 +45,18 @@
45
45
  "typed-emitter": "^2.1.0"
46
46
  },
47
47
  "dependencies": {
48
- "@webex/common": "3.0.0-beta.30",
49
- "@webex/internal-media-core": "1.33.2",
50
- "@webex/internal-plugin-conversation": "3.0.0-beta.30",
51
- "@webex/internal-plugin-device": "3.0.0-beta.30",
52
- "@webex/internal-plugin-llm": "3.0.0-beta.30",
53
- "@webex/internal-plugin-mercury": "3.0.0-beta.30",
54
- "@webex/internal-plugin-metrics": "3.0.0-beta.30",
55
- "@webex/internal-plugin-support": "3.0.0-beta.30",
56
- "@webex/internal-plugin-user": "3.0.0-beta.30",
57
- "@webex/plugin-people": "3.0.0-beta.30",
58
- "@webex/plugin-rooms": "3.0.0-beta.30",
59
- "@webex/webex-core": "3.0.0-beta.30",
48
+ "@webex/common": "3.0.0-beta.32",
49
+ "@webex/internal-media-core": "1.35.0",
50
+ "@webex/internal-plugin-conversation": "3.0.0-beta.32",
51
+ "@webex/internal-plugin-device": "3.0.0-beta.32",
52
+ "@webex/internal-plugin-llm": "3.0.0-beta.32",
53
+ "@webex/internal-plugin-mercury": "3.0.0-beta.32",
54
+ "@webex/internal-plugin-metrics": "3.0.0-beta.32",
55
+ "@webex/internal-plugin-support": "3.0.0-beta.32",
56
+ "@webex/internal-plugin-user": "3.0.0-beta.32",
57
+ "@webex/plugin-people": "3.0.0-beta.32",
58
+ "@webex/plugin-rooms": "3.0.0-beta.32",
59
+ "@webex/webex-core": "3.0.0-beta.32",
60
60
  "ampersand-collection": "^2.0.2",
61
61
  "bowser": "^2.11.0",
62
62
  "btoa": "^1.2.1",
@@ -4981,7 +4981,7 @@ export default class Meeting extends StatelessWebexPlugin {
4981
4981
 
4982
4982
  this.mediaProperties.webrtcMediaConnection.on(
4983
4983
  Event.VIDEO_SOURCES_COUNT_CHANGED,
4984
- (numTotalSources, numLiveSources) => {
4984
+ (numTotalSources, numLiveSources, mediaContent) => {
4985
4985
  Trigger.trigger(
4986
4986
  this,
4987
4987
  {
@@ -4992,6 +4992,7 @@ export default class Meeting extends StatelessWebexPlugin {
4992
4992
  {
4993
4993
  numTotalSources,
4994
4994
  numLiveSources,
4995
+ mediaContent,
4995
4996
  }
4996
4997
  );
4997
4998
  }
@@ -4999,7 +5000,7 @@ export default class Meeting extends StatelessWebexPlugin {
4999
5000
 
5000
5001
  this.mediaProperties.webrtcMediaConnection.on(
5001
5002
  Event.AUDIO_SOURCES_COUNT_CHANGED,
5002
- (numTotalSources, numLiveSources) => {
5003
+ (numTotalSources, numLiveSources, mediaContent) => {
5003
5004
  Trigger.trigger(
5004
5005
  this,
5005
5006
  {
@@ -5010,6 +5011,7 @@ export default class Meeting extends StatelessWebexPlugin {
5010
5011
  {
5011
5012
  numTotalSources,
5012
5013
  numLiveSources,
5014
+ mediaContent,
5013
5015
  }
5014
5016
  );
5015
5017
  }
@@ -11,7 +11,7 @@ import {cloneDeep} from 'lodash';
11
11
 
12
12
  import LoggerProxy from '../common/logs/logger-proxy';
13
13
 
14
- import {ReceiveSlot, ReceiveSlotId} from './receiveSlot';
14
+ import {ReceiveSlot, ReceiveSlotEvents, ReceiveSlotId} from './receiveSlot';
15
15
  import {getMaxFs} from './remoteMedia';
16
16
 
17
17
  export interface ActiveSpeakerPolicyInfo {
@@ -73,6 +73,8 @@ export class MediaRequestManager {
73
73
 
74
74
  private degradationPreferences: DegradationPreferences;
75
75
 
76
+ private sourceUpdateListener: () => void;
77
+
76
78
  constructor(
77
79
  degradationPreferences: DegradationPreferences,
78
80
  sendMediaRequestsCallback: SendMediaRequestsCallback
@@ -82,6 +84,7 @@ export class MediaRequestManager {
82
84
  this.clientRequests = {};
83
85
  this.slotsActiveInLastMediaRequest = {};
84
86
  this.degradationPreferences = degradationPreferences;
87
+ this.sourceUpdateListener = this.commit.bind(this);
85
88
  }
86
89
 
87
90
  private resetInactiveReceiveSlots() {
@@ -128,19 +131,23 @@ export class MediaRequestManager {
128
131
  // reduce max-fs until total macroblocks is below limit
129
132
  for (let i = 0; i < maxFsLimits.length; i += 1) {
130
133
  let totalMacroblocksRequested = 0;
131
- Object.values(clientRequests).forEach((mr) => {
134
+ Object.entries(clientRequests).forEach(([id, mr]) => {
132
135
  if (mr.codecInfo) {
133
136
  mr.codecInfo.maxFs = Math.min(
134
137
  mr.codecInfo.maxFs || CODEC_DEFAULTS.h264.maxFs,
135
138
  maxFsLimits[i]
136
139
  );
137
- totalMacroblocksRequested += mr.codecInfo.maxFs * mr.receiveSlots.length;
140
+ // we only consider sources with "live" state
141
+ const slotsWithLiveSource = this.clientRequests[id].receiveSlots.filter(
142
+ (rs) => rs.sourceState === 'live'
143
+ );
144
+ totalMacroblocksRequested += mr.codecInfo.maxFs * slotsWithLiveSource.length;
138
145
  }
139
146
  });
140
147
  if (totalMacroblocksRequested <= this.degradationPreferences.maxMacroblocksLimit) {
141
148
  if (i !== 0) {
142
149
  LoggerProxy.logger.warn(
143
- `multistream:mediaRequestManager --> too many requests with high max-fs, frame size will be limited to ${maxFsLimits[i]}`
150
+ `multistream:mediaRequestManager --> too many streams with high max-fs, frame size will be limited to ${maxFsLimits[i]}`
144
151
  );
145
152
  }
146
153
  break;
@@ -204,6 +211,10 @@ export class MediaRequestManager {
204
211
 
205
212
  this.clientRequests[newId] = mediaRequest;
206
213
 
214
+ mediaRequest.receiveSlots.forEach((rs) => {
215
+ rs.on(ReceiveSlotEvents.SourceUpdate, this.sourceUpdateListener);
216
+ });
217
+
207
218
  if (commit) {
208
219
  this.commit();
209
220
  }
@@ -212,6 +223,10 @@ export class MediaRequestManager {
212
223
  }
213
224
 
214
225
  public cancelRequest(requestId: MediaRequestId, commit = true) {
226
+ this.clientRequests[requestId]?.receiveSlots.forEach((rs) => {
227
+ rs.off(ReceiveSlotEvents.SourceUpdate, this.sourceUpdateListener);
228
+ });
229
+
215
230
  delete this.clientRequests[requestId];
216
231
 
217
232
  if (commit) {
@@ -118,7 +118,7 @@ export default class RoapRequest extends StatelessWebexPlugin {
118
118
  res.body.mediaConnections.length > 0 &&
119
119
  res.body.mediaConnections[0];
120
120
 
121
- LoggerProxy.logger.info(
121
+ LoggerProxy.logger.debug(
122
122
  `Roap:request#sendRoap --> response:${JSON.stringify(
123
123
  mediaConnections,
124
124
  null,
@@ -58,6 +58,9 @@ describe('MediaRequestManager', () => {
58
58
  (_, index) =>
59
59
  ({
60
60
  id: `fake receive slot ${index}`,
61
+ on: sinon.stub(),
62
+ off: sinon.stub(),
63
+ sourceState: 'live',
61
64
  wcmeReceiveSlot: fakeWcmeSlots[index],
62
65
  resetSourceState: sinon.stub(),
63
66
  } as unknown as ReceiveSlot)
@@ -684,6 +687,30 @@ describe('MediaRequestManager', () => {
684
687
  assert.calledOnce(sendMediaRequestsCallback);
685
688
  });
686
689
 
690
+ it('should not degrade max-fs if receive slot sources are not live', () => {
691
+ // set receive slot source states to "no source"
692
+ fakeReceiveSlots.forEach((slot) => {
693
+ slot.sourceState = 'no source';
694
+ });
695
+
696
+ // set max macroblocks limit
697
+ mediaRequestManager.setDegradationPreferences({maxMacroblocksLimit: 32400});
698
+ sendMediaRequestsCallback.resetHistory();
699
+
700
+ // request 4 "large" 1080p streams, which should degrade to 720p if live
701
+ addActiveSpeakerRequest(255, fakeReceiveSlots.slice(0, 4), getMaxFs('large'), true);
702
+
703
+ // check that resulting requests are 4 "large" 1080p streams
704
+ checkMediaRequestsSent([
705
+ {
706
+ policy: 'active-speaker',
707
+ priority: 255,
708
+ receiveSlots: fakeWcmeSlots.slice(0, 4),
709
+ maxFs: getMaxFs('large'),
710
+ },
711
+ ]);
712
+ });
713
+
687
714
  it('can degrade max-fs once when request exceeds max macroblocks limit', () => {
688
715
  // set max macroblocks limit
689
716
  mediaRequestManager.setDegradationPreferences({maxMacroblocksLimit: 32400});