@webex/plugin-meetings 3.0.0-beta.54 → 3.0.0-beta.56

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.
@@ -130,7 +130,7 @@ var Breakout = _webexCore.WebexPlugin.extend({
130
130
  sessionId: this.sessionId
131
131
  });
132
132
  },
133
- version: "3.0.0-beta.54"
133
+ version: "3.0.0-beta.56"
134
134
  });
135
135
  var _default = Breakout;
136
136
  exports.default = _default;
@@ -718,7 +718,7 @@ var Breakouts = _webexCore.WebexPlugin.extend({
718
718
  }
719
719
  });
720
720
  },
721
- version: "3.0.0-beta.54"
721
+ version: "3.0.0-beta.56"
722
722
  });
723
723
  var _default = Breakouts;
724
724
  exports.default = _default;
@@ -1,13 +1,19 @@
1
1
  "use strict";
2
2
 
3
+ var _Object$keys2 = require("@babel/runtime-corejs2/core-js/object/keys");
4
+ var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs2/core-js/object/get-own-property-symbols");
5
+ var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");
6
+ var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptors");
7
+ var _Object$defineProperties = require("@babel/runtime-corejs2/core-js/object/define-properties");
3
8
  var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
4
9
  var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
5
10
  _Object$defineProperty(exports, "__esModule", {
6
11
  value: true
7
12
  });
8
13
  exports.default = void 0;
9
- var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
14
+ var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
10
15
  var _entries = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/entries"));
16
+ var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
11
17
  var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
12
18
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/slicedToArray"));
13
19
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
@@ -20,6 +26,8 @@ var _loggerProxy = _interopRequireDefault(require("../common/logs/logger-proxy")
20
26
  var _enums = _interopRequireDefault(require("./enums"));
21
27
  var _util = _interopRequireDefault(require("./util"));
22
28
  var _constants2 = require("./constants");
29
+ function ownKeys(object, enumerableOnly) { var keys = _Object$keys2(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
30
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } return target; }
23
31
  /**
24
32
  * docs
25
33
  * https://sqbu-github.cisco.com/pages/WebExSquared/locus/guides/mute.html
@@ -163,28 +171,39 @@ var ControlsOptionsManager = /*#__PURE__*/function () {
163
171
  }, {
164
172
  key: "setControls",
165
173
  value: function setControls(setting) {
166
- var muteUnmuteAll = (0, _keys.default)(setting).includes(_enums.default.muted);
167
- var body = muteUnmuteAll ? {
168
- audio: {}
169
- } : {};
170
- for (var _i = 0, _Object$entries = (0, _entries.default)(setting); _i < _Object$entries.length; _i++) {
171
- var _Object$entries$_i = (0, _slicedToArray2.default)(_Object$entries[_i], 2),
172
- key = _Object$entries$_i[0],
173
- value = _Object$entries$_i[1];
174
- _loggerProxy.default.logger.log("ControlsOptionsManager:index#setControls --> ".concat(key, " [").concat(value, "]"));
175
- // mute unmute all has different body structure than toggling disable hard mute
176
- // or mute on entry by themselves
177
- if (muteUnmuteAll) {
178
- if (_util.default !== null && _util.default !== void 0 && _util.default["".concat(value ? _constants2.CAN_SET : _constants2.CAN_UNSET).concat(_enums.default.muted)](this.displayHints)) {
179
- body.audio[(0, _camelCase2.default)(key)] = value;
180
- } else {
181
- return _promise.default.reject(new _permission.default("".concat(_enums.default.muted, " [").concat(value, "] not allowed, due to moderator property.")));
182
- }
183
- } else if (_util.default !== null && _util.default !== void 0 && _util.default["".concat(value ? _constants2.CAN_SET : _constants2.CAN_UNSET).concat(key)](this.displayHints)) {
184
- body[(0, _camelCase2.default)(key)] = (0, _defineProperty2.default)({}, _constants2.ENABLED, value);
185
- } else {
186
- return _promise.default.reject(new _permission.default("".concat(key, " [").concat(value, "] not allowed, due to moderator property.")));
174
+ var _this = this;
175
+ _loggerProxy.default.logger.log("ControlsOptionsManager:index#setControls --> ".concat((0, _stringify.default)(setting)));
176
+ var body = {};
177
+ var error;
178
+ (0, _entries.default)(setting).forEach(function (_ref) {
179
+ var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
180
+ key = _ref2[0],
181
+ value = _ref2[1];
182
+ if (!(_util.default !== null && _util.default !== void 0 && _util.default["".concat(value ? _constants2.CAN_SET : _constants2.CAN_UNSET).concat(key)](_this.displayHints))) {
183
+ error = new _permission.default("".concat(key, " [").concat(value, "] not allowed, due to moderator property."));
184
+ }
185
+ if (error) {
186
+ return;
187
187
  }
188
+ switch (key) {
189
+ case _enums.default.muted:
190
+ body.audio = body.audio ? _objectSpread(_objectSpread({}, body.audio), {}, (0, _defineProperty2.default)({}, (0, _camelCase2.default)(key), value)) : (0, _defineProperty2.default)({}, (0, _camelCase2.default)(key), value);
191
+ break;
192
+ case _enums.default.disallowUnmute:
193
+ case _enums.default.muteOnEntry:
194
+ if ((0, _keys.default)(setting).includes(_enums.default.muted)) {
195
+ body.audio = body.audio ? _objectSpread(_objectSpread({}, body.audio), {}, (0, _defineProperty2.default)({}, (0, _camelCase2.default)(key), value)) : (0, _defineProperty2.default)({}, (0, _camelCase2.default)(key), value);
196
+ body.audio[(0, _camelCase2.default)(key)] = value;
197
+ } else {
198
+ body[(0, _camelCase2.default)(key)] = (0, _defineProperty2.default)({}, _constants2.ENABLED, value);
199
+ }
200
+ break;
201
+ default:
202
+ error = new _permission.default("".concat(key, " [").concat(value, "] not allowed, due to moderator property."));
203
+ }
204
+ });
205
+ if (error) {
206
+ return _promise.default.reject(error);
188
207
  }
189
208
 
190
209
  // @ts-ignore
@@ -1 +1 @@
1
- {"version":3,"names":["ControlsOptionsManager","request","options","initialize","set","extract","url","locusUrl","hints","displayHints","setDisplayHints","setLocusUrl","setting","muteUnmuteAll","includes","Setting","muted","body","audio","key","value","LoggerProxy","logger","log","Util","CAN_SET","CAN_UNSET","reject","PermissionError","ENABLED","uri","CONTROLS","method","HTTP_VERBS","PATCH","enabled","setControls","muteOnEntry","disallowUnmute","mutedEnabled","disallowUnmuteEnabled","muteOnEntryEnabled"],"sources":["index.ts"],"sourcesContent":["import {camelCase} from 'lodash';\nimport PermissionError from '../common/errors/permission';\nimport {CONTROLS, HTTP_VERBS} from '../constants';\nimport MeetingRequest from '../meeting/request';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport Setting from './enums';\nimport Util from './util';\nimport {CAN_SET, CAN_UNSET, ENABLED} from './constants';\n\n/**\n * docs\n * https://sqbu-github.cisco.com/pages/WebExSquared/locus/guides/mute.html\n * https://confluence-eng-gpk2.cisco.com/conf/display/LOCUS/Hard+Mute+and+Audio+Privacy#HardMuteandAudioPrivacy-SelfMuteonEntry\n * https://confluence-eng-gpk2.cisco.com/conf/pages/viewpage.action?spaceKey=UC&title=WEBEX-124454%3A+UCF%3A+Hard+mute+support+for+Teams+joining+Webex+meeting\n * https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-180867\n * https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-393351\n */\n\n/**\n * @description ControlsOptionsManager is responsible for handling the behavior of participant controls when somebody joins a meeting\n * @export\n * @private\n * @class Recording\n */\nexport default class ControlsOptionsManager {\n /**\n * @instance\n * @type {MeetingRequest}\n * @private\n * @memberof ControlsOptionsManager\n */\n private request: MeetingRequest;\n\n /**\n * @instance\n * @type {Array}\n * @private\n * @memberof ControlsOptionsManager\n */\n private displayHints: Array<string> = [];\n\n /**\n * @instance\n * @type {string}\n * @private\n * @memberof ControlsOptionsManager\n */\n private locusUrl: string;\n\n /**\n * @param {MeetingRequest} request\n * @param {Object} options\n * @constructor\n * @memberof ControlsOptionsManager\n */\n constructor(\n request: MeetingRequest,\n options?: {\n locusUrl: string;\n displayHints?: Array<string>;\n }\n ) {\n this.initialize(request);\n this.set(options);\n }\n\n /**\n * @param {MeetingRequest} request\n * @returns {void}\n * @private\n * @memberof ControlsOptionsManager\n */\n private initialize(request: MeetingRequest) {\n this.request = request;\n }\n\n /**\n * @param {Object} options\n * @returns {void}\n * @public\n * @memberof ControlsOptionsManager\n */\n public set(options?: {locusUrl: string; displayHints?: Array<string>}) {\n this.extract(options);\n }\n\n /**\n * @param {string} url\n * @returns {void}\n * @public\n * @memberof ControlsOptionsManager\n */\n public setLocusUrl(url: string) {\n this.locusUrl = url;\n }\n\n /**\n * @param {Array} hints\n * @returns {void}\n * @public\n * @memberof ControlsOptionsManager\n */\n public setDisplayHints(hints: Array<string>) {\n this.displayHints = hints;\n }\n\n /**\n * @returns {string}\n * @public\n * @memberof ControlsOptionsManager\n */\n public getLocusUrl() {\n return this.locusUrl;\n }\n\n /**\n * @returns {Array}\n * @public\n * @memberof ControlsOptionsManager\n */\n public getDisplayHints() {\n return this.displayHints;\n }\n\n /**\n * @param {Object} options\n * @returns {void}\n * @private\n * @memberof ControlsOptionsManager\n */\n private extract(options?: {locusUrl: string; displayHints?: Array<string>}) {\n this.setDisplayHints(options?.displayHints);\n this.setLocusUrl(options?.locusUrl);\n }\n\n /**\n * @param {Setting} setting\n * @private\n * @memberof ControlsOptionsManager\n * @returns {Promise}\n */\n private setControls(setting: {[key in Setting]?: boolean}): Promise<any> {\n const muteUnmuteAll = Object.keys(setting).includes(Setting.muted);\n\n const body = muteUnmuteAll ? {audio: {}} : {};\n for (const [key, value] of Object.entries(setting)) {\n LoggerProxy.logger.log(`ControlsOptionsManager:index#setControls --> ${key} [${value}]`);\n // mute unmute all has different body structure than toggling disable hard mute\n // or mute on entry by themselves\n if (muteUnmuteAll) {\n if (Util?.[`${value ? CAN_SET : CAN_UNSET}${Setting.muted}`](this.displayHints)) {\n body.audio[camelCase(key)] = value;\n } else {\n return Promise.reject(\n new PermissionError(\n `${Setting.muted} [${value}] not allowed, due to moderator property.`\n )\n );\n }\n } else if (Util?.[`${value ? CAN_SET : CAN_UNSET}${key}`](this.displayHints)) {\n body[camelCase(key)] = {\n [ENABLED]: value,\n };\n } else {\n return Promise.reject(\n new PermissionError(`${key} [${value}] not allowed, due to moderator property.`)\n );\n }\n }\n\n // @ts-ignore\n return this.request.request({\n uri: `${this.locusUrl}/${CONTROLS}`,\n body,\n method: HTTP_VERBS.PATCH,\n });\n }\n\n /**\n * @public\n * @param {boolean} enabled\n * @memberof ControlsOptionsManager\n * @returns {Promise}\n */\n public setMuteOnEntry(enabled: boolean): Promise<any> {\n return this.setControls({[Setting.muteOnEntry]: enabled});\n }\n\n /**\n * @public\n * @param {boolean} enabled\n * @memberof ControlsOptionsManager\n * @returns {Promise}\n */\n public setDisallowUnmute(enabled: boolean): Promise<any> {\n return this.setControls({[Setting.disallowUnmute]: enabled});\n }\n\n /**\n * @public\n * @param {boolean} mutedEnabled\n * @param {boolean} disallowUnmuteEnabled\n * @param {boolean} muteOnEntryEnabled\n * @memberof ControlsOptionsManager\n * @returns {Promise}\n */\n public setMuteAll(\n mutedEnabled: boolean,\n disallowUnmuteEnabled: boolean,\n muteOnEntryEnabled: boolean\n ): Promise<any> {\n return this.setControls({\n [Setting.muted]: mutedEnabled,\n [Setting.disallowUnmute]: disallowUnmuteEnabled,\n [Setting.muteOnEntry]: muteOnEntryEnabled,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["ControlsOptionsManager","request","options","initialize","set","extract","url","locusUrl","hints","displayHints","setDisplayHints","setLocusUrl","setting","LoggerProxy","logger","log","body","error","forEach","key","value","Util","CAN_SET","CAN_UNSET","PermissionError","Setting","muted","audio","disallowUnmute","muteOnEntry","includes","ENABLED","reject","uri","CONTROLS","method","HTTP_VERBS","PATCH","enabled","setControls","mutedEnabled","disallowUnmuteEnabled","muteOnEntryEnabled"],"sources":["index.ts"],"sourcesContent":["import {camelCase} from 'lodash';\nimport PermissionError from '../common/errors/permission';\nimport {CONTROLS, HTTP_VERBS} from '../constants';\nimport MeetingRequest from '../meeting/request';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport Setting from './enums';\nimport Util from './util';\nimport {CAN_SET, CAN_UNSET, ENABLED} from './constants';\n\n/**\n * docs\n * https://sqbu-github.cisco.com/pages/WebExSquared/locus/guides/mute.html\n * https://confluence-eng-gpk2.cisco.com/conf/display/LOCUS/Hard+Mute+and+Audio+Privacy#HardMuteandAudioPrivacy-SelfMuteonEntry\n * https://confluence-eng-gpk2.cisco.com/conf/pages/viewpage.action?spaceKey=UC&title=WEBEX-124454%3A+UCF%3A+Hard+mute+support+for+Teams+joining+Webex+meeting\n * https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-180867\n * https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-393351\n */\n\n/**\n * @description ControlsOptionsManager is responsible for handling the behavior of participant controls when somebody joins a meeting\n * @export\n * @private\n * @class Recording\n */\nexport default class ControlsOptionsManager {\n /**\n * @instance\n * @type {MeetingRequest}\n * @private\n * @memberof ControlsOptionsManager\n */\n private request: MeetingRequest;\n\n /**\n * @instance\n * @type {Array}\n * @private\n * @memberof ControlsOptionsManager\n */\n private displayHints: Array<string> = [];\n\n /**\n * @instance\n * @type {string}\n * @private\n * @memberof ControlsOptionsManager\n */\n private locusUrl: string;\n\n /**\n * @param {MeetingRequest} request\n * @param {Object} options\n * @constructor\n * @memberof ControlsOptionsManager\n */\n constructor(\n request: MeetingRequest,\n options?: {\n locusUrl: string;\n displayHints?: Array<string>;\n }\n ) {\n this.initialize(request);\n this.set(options);\n }\n\n /**\n * @param {MeetingRequest} request\n * @returns {void}\n * @private\n * @memberof ControlsOptionsManager\n */\n private initialize(request: MeetingRequest) {\n this.request = request;\n }\n\n /**\n * @param {Object} options\n * @returns {void}\n * @public\n * @memberof ControlsOptionsManager\n */\n public set(options?: {locusUrl: string; displayHints?: Array<string>}) {\n this.extract(options);\n }\n\n /**\n * @param {string} url\n * @returns {void}\n * @public\n * @memberof ControlsOptionsManager\n */\n public setLocusUrl(url: string) {\n this.locusUrl = url;\n }\n\n /**\n * @param {Array} hints\n * @returns {void}\n * @public\n * @memberof ControlsOptionsManager\n */\n public setDisplayHints(hints: Array<string>) {\n this.displayHints = hints;\n }\n\n /**\n * @returns {string}\n * @public\n * @memberof ControlsOptionsManager\n */\n public getLocusUrl() {\n return this.locusUrl;\n }\n\n /**\n * @returns {Array}\n * @public\n * @memberof ControlsOptionsManager\n */\n public getDisplayHints() {\n return this.displayHints;\n }\n\n /**\n * @param {Object} options\n * @returns {void}\n * @private\n * @memberof ControlsOptionsManager\n */\n private extract(options?: {locusUrl: string; displayHints?: Array<string>}) {\n this.setDisplayHints(options?.displayHints);\n this.setLocusUrl(options?.locusUrl);\n }\n\n /**\n * @param {Setting} setting\n * @private\n * @memberof ControlsOptionsManager\n * @returns {Promise}\n */\n private setControls(setting: {[key in Setting]?: boolean}): Promise<any> {\n LoggerProxy.logger.log(\n `ControlsOptionsManager:index#setControls --> ${JSON.stringify(setting)}`\n );\n\n const body: Record<string, any> = {};\n let error: PermissionError;\n\n Object.entries(setting).forEach(([key, value]) => {\n if (!Util?.[`${value ? CAN_SET : CAN_UNSET}${key}`](this.displayHints)) {\n error = new PermissionError(`${key} [${value}] not allowed, due to moderator property.`);\n }\n\n if (error) {\n return;\n }\n\n switch (key) {\n case Setting.muted:\n body.audio = body.audio\n ? {...body.audio, [camelCase(key)]: value}\n : {[camelCase(key)]: value};\n break;\n\n case Setting.disallowUnmute:\n case Setting.muteOnEntry:\n if (Object.keys(setting).includes(Setting.muted)) {\n body.audio = body.audio\n ? {...body.audio, [camelCase(key)]: value}\n : {[camelCase(key)]: value};\n body.audio[camelCase(key)] = value;\n } else {\n body[camelCase(key)] = {[ENABLED]: value};\n }\n break;\n\n default:\n error = new PermissionError(`${key} [${value}] not allowed, due to moderator property.`);\n }\n });\n\n if (error) {\n return Promise.reject(error);\n }\n\n // @ts-ignore\n return this.request.request({\n uri: `${this.locusUrl}/${CONTROLS}`,\n body,\n method: HTTP_VERBS.PATCH,\n });\n }\n\n /**\n * @public\n * @param {boolean} enabled\n * @memberof ControlsOptionsManager\n * @returns {Promise}\n */\n public setMuteOnEntry(enabled: boolean): Promise<any> {\n return this.setControls({[Setting.muteOnEntry]: enabled});\n }\n\n /**\n * @public\n * @param {boolean} enabled\n * @memberof ControlsOptionsManager\n * @returns {Promise}\n */\n public setDisallowUnmute(enabled: boolean): Promise<any> {\n return this.setControls({[Setting.disallowUnmute]: enabled});\n }\n\n /**\n * @public\n * @param {boolean} mutedEnabled\n * @param {boolean} disallowUnmuteEnabled\n * @param {boolean} muteOnEntryEnabled\n * @memberof ControlsOptionsManager\n * @returns {Promise}\n */\n public setMuteAll(\n mutedEnabled: boolean,\n disallowUnmuteEnabled: boolean,\n muteOnEntryEnabled: boolean\n ): Promise<any> {\n return this.setControls({\n [Setting.muted]: mutedEnabled,\n [Setting.disallowUnmute]: disallowUnmuteEnabled,\n [Setting.muteOnEntry]: muteOnEntryEnabled,\n });\n }\n}\n"],"mappings":"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"}
@@ -113,8 +113,10 @@ var RemoteMedia = /*#__PURE__*/function (_EventsScope) {
113
113
  fs = 240;
114
114
  } else if (height < 540) {
115
115
  fs = 920;
116
- } else {
116
+ } else if (height <= 720) {
117
117
  fs = 3600;
118
+ } else {
119
+ fs = 8192;
118
120
  }
119
121
  (_this$receiveSlot = this.receiveSlot) === null || _this$receiveSlot === void 0 ? void 0 : _this$receiveSlot.setMaxFs(fs);
120
122
  }
@@ -1 +1 @@
1
- {"version":3,"names":["RemoteMediaEvents","SourceUpdate","ReceiveSlotEvents","Stopped","getMaxFs","paneSize","maxFs","LoggerProxy","logger","warn","remoteMediaCounter","RemoteMedia","receiveSlot","mediaRequestManager","options","setupEventListeners","id","width","height","fs","setMaxFs","commit","cancelMediaRequest","removeAllListeners","undefined","emit","file","function","csi","mediaRequestId","Error","addRequest","policyInfo","policy","receiveSlots","codecInfo","resolution","codec","cancelRequest","scope","on","data","mediaType","memberId","sourceState","stream","EventsScope"],"sources":["remoteMedia.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport {MediaType, SourceState} from '@webex/internal-media-core';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport EventsScope from '../common/events/events-scope';\n\nimport {MediaRequestId, MediaRequestManager} from './mediaRequestManager';\nimport {CSI, ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';\n\nexport const RemoteMediaEvents = {\n SourceUpdate: ReceiveSlotEvents.SourceUpdate,\n Stopped: 'stopped',\n};\n\nexport type RemoteVideoResolution =\n | 'thumbnail' // the smallest possible resolution, 90p or less\n | 'very small' // 180p or less\n | 'small' // 360p or less\n | 'medium' // 720p or less\n | 'large' // 1080p or less\n | 'best'; // highest possible resolution\n\n/**\n * Converts pane size into h264 maxFs\n * @param {PaneSize} paneSize\n * @returns {number}\n */\nexport function getMaxFs(paneSize: RemoteVideoResolution): number {\n let maxFs;\n\n switch (paneSize) {\n case 'thumbnail':\n maxFs = 60;\n break;\n case 'very small':\n maxFs = 240;\n break;\n case 'small':\n maxFs = 920;\n break;\n case 'medium':\n maxFs = 3600;\n break;\n case 'large':\n maxFs = 8192;\n break;\n case 'best':\n maxFs = 8192; // for now 'best' is 1080p, so same as 'large'\n break;\n default:\n LoggerProxy.logger.warn(\n `RemoteMedia#getMaxFs --> unsupported paneSize: ${paneSize}, using \"medium\" instead`\n );\n maxFs = 3600;\n }\n\n return maxFs;\n}\n\ntype Options = {\n resolution?: RemoteVideoResolution; // applies only to groups of type MediaType.VideoMain and MediaType.VideoSlides\n};\n\nexport type RemoteMediaId = string;\n\nlet remoteMediaCounter = 0;\n\n/**\n * Class representing a remote audio/video stream.\n *\n * Internally it is associated with a specific receive slot\n * and a media request for it.\n */\nexport class RemoteMedia extends EventsScope {\n private receiveSlot?: ReceiveSlot;\n\n private readonly mediaRequestManager: MediaRequestManager;\n\n private readonly options: Options;\n\n private mediaRequestId?: MediaRequestId;\n\n public readonly id: RemoteMediaId;\n\n /**\n * Constructs RemoteMedia instance\n *\n * @param receiveSlot\n * @param mediaRequestManager\n * @param options\n */\n constructor(\n receiveSlot: ReceiveSlot,\n mediaRequestManager: MediaRequestManager,\n options?: Options\n ) {\n super();\n remoteMediaCounter += 1;\n this.receiveSlot = receiveSlot;\n this.mediaRequestManager = mediaRequestManager;\n this.options = options || {};\n this.setupEventListeners();\n this.id = `RM${remoteMediaCounter}-${this.receiveSlot.id}`;\n }\n\n /**\n * Supply the width and height of the video element\n * to restrict the requested resolution to this size\n * @param width width of the video element\n * @param height height of the video element\n */\n public setSizeHint(width, height) {\n // only base on height for now\n let fs: number;\n\n if (height < 135) {\n fs = 60;\n } else if (height < 270) {\n fs = 240;\n } else if (height < 540) {\n fs = 920;\n } else {\n fs = 3600;\n }\n\n this.receiveSlot?.setMaxFs(fs);\n }\n\n /**\n * Invalidates the remote media by clearing the reference to a receive slot and\n * cancelling the media request.\n * After this call the remote media is unusable.\n *\n * @param {boolean} commit - whether to commit the cancellation of the media request\n * @internal\n */\n public stop(commit = true) {\n this.cancelMediaRequest(commit);\n this.receiveSlot?.removeAllListeners();\n this.receiveSlot = undefined;\n this.emit(\n {\n file: 'multistream/remoteMedia',\n function: 'stop',\n },\n RemoteMediaEvents.Stopped,\n {}\n );\n }\n\n /**\n * Sends a new media request. This method can only be used for receiver-selected policy,\n * because only in that policy we have a 1-1 relationship between RemoteMedia and MediaRequest\n * and the request id is then stored in this RemoteMedia instance.\n * For active-speaker policy, the same request is shared among many RemoteMedia instances,\n * so it's managed through RemoteMediaGroup\n *\n * @internal\n */\n public sendMediaRequest(csi: CSI, commit: boolean) {\n if (this.mediaRequestId) {\n this.cancelMediaRequest(false);\n }\n\n if (!this.receiveSlot) {\n throw new Error('sendMediaRequest() called on an invalidated RemoteMedia instance');\n }\n\n this.mediaRequestId = this.mediaRequestManager.addRequest(\n {\n policyInfo: {\n policy: 'receiver-selected',\n csi,\n },\n receiveSlots: [this.receiveSlot],\n codecInfo: this.options.resolution && {\n codec: 'h264',\n maxFs: getMaxFs(this.options.resolution),\n },\n },\n commit\n );\n }\n\n /**\n * @internal\n */\n public cancelMediaRequest(commit: boolean) {\n if (this.mediaRequestId) {\n this.mediaRequestManager.cancelRequest(this.mediaRequestId, commit);\n this.mediaRequestId = undefined;\n }\n }\n\n /**\n * registers event listeners on the receive slot and forwards all the events\n */\n private setupEventListeners() {\n if (this.receiveSlot) {\n const scope = {\n file: 'multistream/remoteMedia',\n function: 'setupEventListeners',\n };\n\n this.receiveSlot.on(ReceiveSlotEvents.SourceUpdate, (data) => {\n this.emit(scope, RemoteMediaEvents.SourceUpdate, data);\n });\n }\n }\n\n /**\n * Getter for mediaType\n */\n public get mediaType(): MediaType {\n return this.receiveSlot?.mediaType;\n }\n\n /**\n * Getter for memberId\n */\n public get memberId() {\n return this.receiveSlot?.memberId;\n }\n\n /**\n * Getter for csi\n */\n public get csi() {\n return this.receiveSlot?.csi;\n }\n\n /**\n * Getter for source state\n */\n public get sourceState(): SourceState {\n return this.receiveSlot?.sourceState;\n }\n\n /**\n * Getter for remote media stream\n */\n public get stream() {\n return this.receiveSlot?.stream;\n }\n\n /**\n * @internal\n * @returns {ReceiveSlot}\n */\n public getUnderlyingReceiveSlot() {\n return this.receiveSlot;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["RemoteMediaEvents","SourceUpdate","ReceiveSlotEvents","Stopped","getMaxFs","paneSize","maxFs","LoggerProxy","logger","warn","remoteMediaCounter","RemoteMedia","receiveSlot","mediaRequestManager","options","setupEventListeners","id","width","height","fs","setMaxFs","commit","cancelMediaRequest","removeAllListeners","undefined","emit","file","function","csi","mediaRequestId","Error","addRequest","policyInfo","policy","receiveSlots","codecInfo","resolution","codec","cancelRequest","scope","on","data","mediaType","memberId","sourceState","stream","EventsScope"],"sources":["remoteMedia.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport {MediaType, SourceState} from '@webex/internal-media-core';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport EventsScope from '../common/events/events-scope';\n\nimport {MediaRequestId, MediaRequestManager} from './mediaRequestManager';\nimport {CSI, ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';\n\nexport const RemoteMediaEvents = {\n SourceUpdate: ReceiveSlotEvents.SourceUpdate,\n Stopped: 'stopped',\n};\n\nexport type RemoteVideoResolution =\n | 'thumbnail' // the smallest possible resolution, 90p or less\n | 'very small' // 180p or less\n | 'small' // 360p or less\n | 'medium' // 720p or less\n | 'large' // 1080p or less\n | 'best'; // highest possible resolution\n\n/**\n * Converts pane size into h264 maxFs\n * @param {PaneSize} paneSize\n * @returns {number}\n */\nexport function getMaxFs(paneSize: RemoteVideoResolution): number {\n let maxFs;\n\n switch (paneSize) {\n case 'thumbnail':\n maxFs = 60;\n break;\n case 'very small':\n maxFs = 240;\n break;\n case 'small':\n maxFs = 920;\n break;\n case 'medium':\n maxFs = 3600;\n break;\n case 'large':\n maxFs = 8192;\n break;\n case 'best':\n maxFs = 8192; // for now 'best' is 1080p, so same as 'large'\n break;\n default:\n LoggerProxy.logger.warn(\n `RemoteMedia#getMaxFs --> unsupported paneSize: ${paneSize}, using \"medium\" instead`\n );\n maxFs = 3600;\n }\n\n return maxFs;\n}\n\ntype Options = {\n resolution?: RemoteVideoResolution; // applies only to groups of type MediaType.VideoMain and MediaType.VideoSlides\n};\n\nexport type RemoteMediaId = string;\n\nlet remoteMediaCounter = 0;\n\n/**\n * Class representing a remote audio/video stream.\n *\n * Internally it is associated with a specific receive slot\n * and a media request for it.\n */\nexport class RemoteMedia extends EventsScope {\n private receiveSlot?: ReceiveSlot;\n\n private readonly mediaRequestManager: MediaRequestManager;\n\n private readonly options: Options;\n\n private mediaRequestId?: MediaRequestId;\n\n public readonly id: RemoteMediaId;\n\n /**\n * Constructs RemoteMedia instance\n *\n * @param receiveSlot\n * @param mediaRequestManager\n * @param options\n */\n constructor(\n receiveSlot: ReceiveSlot,\n mediaRequestManager: MediaRequestManager,\n options?: Options\n ) {\n super();\n remoteMediaCounter += 1;\n this.receiveSlot = receiveSlot;\n this.mediaRequestManager = mediaRequestManager;\n this.options = options || {};\n this.setupEventListeners();\n this.id = `RM${remoteMediaCounter}-${this.receiveSlot.id}`;\n }\n\n /**\n * Supply the width and height of the video element\n * to restrict the requested resolution to this size\n * @param width width of the video element\n * @param height height of the video element\n */\n public setSizeHint(width, height) {\n // only base on height for now\n let fs: number;\n\n if (height < 135) {\n fs = 60;\n } else if (height < 270) {\n fs = 240;\n } else if (height < 540) {\n fs = 920;\n } else if (height <= 720) {\n fs = 3600;\n } else {\n fs = 8192;\n }\n\n this.receiveSlot?.setMaxFs(fs);\n }\n\n /**\n * Invalidates the remote media by clearing the reference to a receive slot and\n * cancelling the media request.\n * After this call the remote media is unusable.\n *\n * @param {boolean} commit - whether to commit the cancellation of the media request\n * @internal\n */\n public stop(commit = true) {\n this.cancelMediaRequest(commit);\n this.receiveSlot?.removeAllListeners();\n this.receiveSlot = undefined;\n this.emit(\n {\n file: 'multistream/remoteMedia',\n function: 'stop',\n },\n RemoteMediaEvents.Stopped,\n {}\n );\n }\n\n /**\n * Sends a new media request. This method can only be used for receiver-selected policy,\n * because only in that policy we have a 1-1 relationship between RemoteMedia and MediaRequest\n * and the request id is then stored in this RemoteMedia instance.\n * For active-speaker policy, the same request is shared among many RemoteMedia instances,\n * so it's managed through RemoteMediaGroup\n *\n * @internal\n */\n public sendMediaRequest(csi: CSI, commit: boolean) {\n if (this.mediaRequestId) {\n this.cancelMediaRequest(false);\n }\n\n if (!this.receiveSlot) {\n throw new Error('sendMediaRequest() called on an invalidated RemoteMedia instance');\n }\n\n this.mediaRequestId = this.mediaRequestManager.addRequest(\n {\n policyInfo: {\n policy: 'receiver-selected',\n csi,\n },\n receiveSlots: [this.receiveSlot],\n codecInfo: this.options.resolution && {\n codec: 'h264',\n maxFs: getMaxFs(this.options.resolution),\n },\n },\n commit\n );\n }\n\n /**\n * @internal\n */\n public cancelMediaRequest(commit: boolean) {\n if (this.mediaRequestId) {\n this.mediaRequestManager.cancelRequest(this.mediaRequestId, commit);\n this.mediaRequestId = undefined;\n }\n }\n\n /**\n * registers event listeners on the receive slot and forwards all the events\n */\n private setupEventListeners() {\n if (this.receiveSlot) {\n const scope = {\n file: 'multistream/remoteMedia',\n function: 'setupEventListeners',\n };\n\n this.receiveSlot.on(ReceiveSlotEvents.SourceUpdate, (data) => {\n this.emit(scope, RemoteMediaEvents.SourceUpdate, data);\n });\n }\n }\n\n /**\n * Getter for mediaType\n */\n public get mediaType(): MediaType {\n return this.receiveSlot?.mediaType;\n }\n\n /**\n * Getter for memberId\n */\n public get memberId() {\n return this.receiveSlot?.memberId;\n }\n\n /**\n * Getter for csi\n */\n public get csi() {\n return this.receiveSlot?.csi;\n }\n\n /**\n * Getter for source state\n */\n public get sourceState(): SourceState {\n return this.receiveSlot?.sourceState;\n }\n\n /**\n * Getter for remote media stream\n */\n public get stream() {\n return this.receiveSlot?.stream;\n }\n\n /**\n * @internal\n * @returns {ReceiveSlot}\n */\n public getUnderlyingReceiveSlot() {\n return this.receiveSlot;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.54",
3
+ "version": "3.0.0-beta.56",
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.54",
36
- "@webex/test-helper-chai": "3.0.0-beta.54",
37
- "@webex/test-helper-mocha": "3.0.0-beta.54",
38
- "@webex/test-helper-mock-webex": "3.0.0-beta.54",
39
- "@webex/test-helper-retry": "3.0.0-beta.54",
40
- "@webex/test-helper-test-users": "3.0.0-beta.54",
35
+ "@webex/plugin-meetings": "3.0.0-beta.56",
36
+ "@webex/test-helper-chai": "3.0.0-beta.56",
37
+ "@webex/test-helper-mocha": "3.0.0-beta.56",
38
+ "@webex/test-helper-mock-webex": "3.0.0-beta.56",
39
+ "@webex/test-helper-retry": "3.0.0-beta.56",
40
+ "@webex/test-helper-test-users": "3.0.0-beta.56",
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.54",
49
+ "@webex/common": "3.0.0-beta.56",
50
50
  "@webex/internal-media-core": "1.35.3",
51
- "@webex/internal-plugin-conversation": "3.0.0-beta.54",
52
- "@webex/internal-plugin-device": "3.0.0-beta.54",
53
- "@webex/internal-plugin-llm": "3.0.0-beta.54",
54
- "@webex/internal-plugin-mercury": "3.0.0-beta.54",
55
- "@webex/internal-plugin-metrics": "3.0.0-beta.54",
56
- "@webex/internal-plugin-support": "3.0.0-beta.54",
57
- "@webex/internal-plugin-user": "3.0.0-beta.54",
58
- "@webex/plugin-people": "3.0.0-beta.54",
59
- "@webex/plugin-rooms": "3.0.0-beta.54",
60
- "@webex/webex-core": "3.0.0-beta.54",
51
+ "@webex/internal-plugin-conversation": "3.0.0-beta.56",
52
+ "@webex/internal-plugin-device": "3.0.0-beta.56",
53
+ "@webex/internal-plugin-llm": "3.0.0-beta.56",
54
+ "@webex/internal-plugin-mercury": "3.0.0-beta.56",
55
+ "@webex/internal-plugin-metrics": "3.0.0-beta.56",
56
+ "@webex/internal-plugin-support": "3.0.0-beta.56",
57
+ "@webex/internal-plugin-user": "3.0.0-beta.56",
58
+ "@webex/plugin-people": "3.0.0-beta.56",
59
+ "@webex/plugin-rooms": "3.0.0-beta.56",
60
+ "@webex/webex-core": "3.0.0-beta.56",
61
61
  "ampersand-collection": "^2.0.2",
62
62
  "bowser": "^2.11.0",
63
63
  "btoa": "^1.2.1",
@@ -140,32 +140,48 @@ export default class ControlsOptionsManager {
140
140
  * @returns {Promise}
141
141
  */
142
142
  private setControls(setting: {[key in Setting]?: boolean}): Promise<any> {
143
- const muteUnmuteAll = Object.keys(setting).includes(Setting.muted);
144
-
145
- const body = muteUnmuteAll ? {audio: {}} : {};
146
- for (const [key, value] of Object.entries(setting)) {
147
- LoggerProxy.logger.log(`ControlsOptionsManager:index#setControls --> ${key} [${value}]`);
148
- // mute unmute all has different body structure than toggling disable hard mute
149
- // or mute on entry by themselves
150
- if (muteUnmuteAll) {
151
- if (Util?.[`${value ? CAN_SET : CAN_UNSET}${Setting.muted}`](this.displayHints)) {
152
- body.audio[camelCase(key)] = value;
153
- } else {
154
- return Promise.reject(
155
- new PermissionError(
156
- `${Setting.muted} [${value}] not allowed, due to moderator property.`
157
- )
158
- );
159
- }
160
- } else if (Util?.[`${value ? CAN_SET : CAN_UNSET}${key}`](this.displayHints)) {
161
- body[camelCase(key)] = {
162
- [ENABLED]: value,
163
- };
164
- } else {
165
- return Promise.reject(
166
- new PermissionError(`${key} [${value}] not allowed, due to moderator property.`)
167
- );
143
+ LoggerProxy.logger.log(
144
+ `ControlsOptionsManager:index#setControls --> ${JSON.stringify(setting)}`
145
+ );
146
+
147
+ const body: Record<string, any> = {};
148
+ let error: PermissionError;
149
+
150
+ Object.entries(setting).forEach(([key, value]) => {
151
+ if (!Util?.[`${value ? CAN_SET : CAN_UNSET}${key}`](this.displayHints)) {
152
+ error = new PermissionError(`${key} [${value}] not allowed, due to moderator property.`);
153
+ }
154
+
155
+ if (error) {
156
+ return;
168
157
  }
158
+
159
+ switch (key) {
160
+ case Setting.muted:
161
+ body.audio = body.audio
162
+ ? {...body.audio, [camelCase(key)]: value}
163
+ : {[camelCase(key)]: value};
164
+ break;
165
+
166
+ case Setting.disallowUnmute:
167
+ case Setting.muteOnEntry:
168
+ if (Object.keys(setting).includes(Setting.muted)) {
169
+ body.audio = body.audio
170
+ ? {...body.audio, [camelCase(key)]: value}
171
+ : {[camelCase(key)]: value};
172
+ body.audio[camelCase(key)] = value;
173
+ } else {
174
+ body[camelCase(key)] = {[ENABLED]: value};
175
+ }
176
+ break;
177
+
178
+ default:
179
+ error = new PermissionError(`${key} [${value}] not allowed, due to moderator property.`);
180
+ }
181
+ });
182
+
183
+ if (error) {
184
+ return Promise.reject(error);
169
185
  }
170
186
 
171
187
  // @ts-ignore
@@ -118,8 +118,10 @@ export class RemoteMedia extends EventsScope {
118
118
  fs = 240;
119
119
  } else if (height < 540) {
120
120
  fs = 920;
121
- } else {
121
+ } else if (height <= 720) {
122
122
  fs = 3600;
123
+ } else {
124
+ fs = 8192;
123
125
  }
124
126
 
125
127
  this.receiveSlot?.setMaxFs(fs);
@@ -240,6 +240,8 @@ describe('RemoteMedia', () => {
240
240
  {height: 270, fs: 920},
241
241
  {height: 539, fs: 920},
242
242
  {height: 540, fs: 3600},
243
+ {height: 720, fs: 3600},
244
+ {height: 721, fs: 8192},
243
245
  ],
244
246
  ({height, fs}) => {
245
247
  it(`sets the max fs to ${fs} correctly when height is ${height}`, () => {