@webex/plugin-meetings 3.0.0-beta.60 → 3.0.0-beta.61

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.60"
133
+ version: "3.0.0-beta.61"
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.60"
721
+ version: "3.0.0-beta.61"
722
722
  });
723
723
  var _default = Breakouts;
724
724
  exports.default = _default;
@@ -7,6 +7,7 @@ _Object$defineProperty(exports, "__esModule", {
7
7
  value: true
8
8
  });
9
9
  exports.ReceiveSlotEvents = exports.ReceiveSlot = void 0;
10
+ var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
10
11
  var _weakMap = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/weak-map"));
11
12
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
12
13
  var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
@@ -166,6 +167,15 @@ var ReceiveSlot = /*#__PURE__*/function (_EventsScope) {
166
167
  }
167
168
  }
168
169
 
170
+ /**
171
+ * @returns {string} a log message used to identify the receive slot
172
+ */
173
+ }, {
174
+ key: "logString",
175
+ get: function get() {
176
+ return "ReceiveSlot - ".concat(this.id, ": ").concat((0, _stringify.default)(this.mcReceiveSlot.id));
177
+ }
178
+
169
179
  /**
170
180
  * The MediaStream object associated with this slot.
171
181
  *
@@ -1 +1 @@
1
- {"version":3,"names":["ReceiveSlotEvents","SourceUpdate","MaxFsUpdate","receiveSlotCounter","ReceiveSlot","mediaType","mcReceiveSlot","findMemberIdCallback","id","setupEventListeners","newFs","emit","file","function","maxFs","scope","on","WcmeReceiveSlotEvents","state","csi","LoggerProxy","logger","log","undefined","memberId","stream","EventsScope"],"sources":["receiveSlot.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport {\n MediaType,\n ReceiveSlot as WcmeReceiveSlot,\n ReceiveSlotEvents as WcmeReceiveSlotEvents,\n SourceState,\n} from '@webex/internal-media-core';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport EventsScope from '../common/events/events-scope';\n\nexport const ReceiveSlotEvents = {\n SourceUpdate: 'sourceUpdate',\n MaxFsUpdate: 'maxFsUpdate',\n};\n\nexport type {SourceState} from '@webex/internal-media-core';\nexport type CSI = number;\nexport type MemberId = string;\nexport type ReceiveSlotId = string;\n\nlet receiveSlotCounter = 0;\n\nexport type FindMemberIdCallback = (csi: CSI) => MemberId | undefined;\n\n/**\n * Class representing a receive slot. A single receive slot is able to receive a single track\n * for example some participant's main video or audio\n */\nexport class ReceiveSlot extends EventsScope {\n private readonly mcReceiveSlot: WcmeReceiveSlot;\n\n private readonly findMemberIdCallback: FindMemberIdCallback;\n\n public readonly id: ReceiveSlotId;\n\n public readonly mediaType: MediaType;\n\n #memberId?: MemberId;\n\n #csi?: CSI;\n\n #sourceState: SourceState;\n\n /**\n * constructor - don't use it directly, you should always use meeting.receiveSlotManager.allocateSlot()\n * to create any receive slots\n *\n * @param {MediaType} mediaType\n * @param {ReceiveSlot} mcReceiveSlot\n * @param {FindMemberIdCallback} findMemberIdCallback callback for finding memberId for given CSI\n */\n constructor(\n mediaType: MediaType,\n mcReceiveSlot: WcmeReceiveSlot,\n findMemberIdCallback: FindMemberIdCallback\n ) {\n super();\n\n receiveSlotCounter += 1;\n\n this.findMemberIdCallback = findMemberIdCallback;\n this.mediaType = mediaType;\n this.mcReceiveSlot = mcReceiveSlot;\n this.#sourceState = 'no source';\n this.id = `r${receiveSlotCounter}`;\n\n this.setupEventListeners();\n }\n\n /**\n * Getter for memberId\n */\n public get memberId() {\n return this.#memberId;\n }\n\n /**\n * Getter for csi\n */\n public get csi() {\n return this.#csi;\n }\n\n /**\n * Set the max frame size for this slot\n * @param newFs frame size\n */\n public setMaxFs(newFs) {\n // emit event for media request manager to listen to\n\n this.emit(\n {\n file: 'meeting/receiveSlot',\n function: 'findMemberId',\n },\n ReceiveSlotEvents.MaxFsUpdate,\n {\n maxFs: newFs,\n }\n );\n }\n\n /**\n * Getter for sourceState\n */\n public get sourceState() {\n return this.#sourceState;\n }\n\n /**\n * registers event handlers with the underlying ReceiveSlot\n */\n private setupEventListeners() {\n const scope = {\n file: 'meeting/receiveSlot',\n function: 'setupEventListeners',\n };\n\n this.mcReceiveSlot.on(\n WcmeReceiveSlotEvents.SourceUpdate,\n (state: SourceState, csi?: number) => {\n LoggerProxy.logger.log(\n `ReceiveSlot#setupEventListeners --> got source update on receive slot ${this.id}, mediaType=${this.mediaType}, csi=${csi}, state=${state}`\n );\n this.#memberId = csi ? this.findMemberIdCallback(csi) : undefined;\n this.#csi = csi;\n this.#sourceState = state;\n\n this.emit(scope, ReceiveSlotEvents.SourceUpdate, {\n state: this.#sourceState,\n csi: this.#csi,\n memberId: this.#memberId,\n });\n }\n );\n }\n\n /** Tries to find the member id for this receive slot if it hasn't got one */\n public findMemberId() {\n if (this.#memberId === undefined && this.#csi) {\n this.#memberId = this.findMemberIdCallback(this.#csi);\n\n if (this.#memberId) {\n // if we found the memberId, simulate source update so that the client app knows that something's changed\n this.emit(\n {\n file: 'meeting/receiveSlot',\n function: 'findMemberId',\n },\n ReceiveSlotEvents.SourceUpdate,\n {\n state: this.#sourceState,\n csi: this.#csi,\n memberId: this.#memberId,\n }\n );\n }\n }\n }\n\n /**\n * The MediaStream object associated with this slot.\n *\n * @returns {MediaStream} The MediaStreamTrack.\n */\n get stream(): MediaStream {\n return this.mcReceiveSlot.stream;\n }\n\n /**\n * The underlying WCME receive slot\n */\n get wcmeReceiveSlot(): WcmeReceiveSlot {\n return this.mcReceiveSlot;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["ReceiveSlotEvents","SourceUpdate","MaxFsUpdate","receiveSlotCounter","ReceiveSlot","mediaType","mcReceiveSlot","findMemberIdCallback","id","setupEventListeners","newFs","emit","file","function","maxFs","scope","on","WcmeReceiveSlotEvents","state","csi","LoggerProxy","logger","log","undefined","memberId","stream","EventsScope"],"sources":["receiveSlot.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport {\n MediaType,\n ReceiveSlot as WcmeReceiveSlot,\n ReceiveSlotEvents as WcmeReceiveSlotEvents,\n SourceState,\n} from '@webex/internal-media-core';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport EventsScope from '../common/events/events-scope';\n\nexport const ReceiveSlotEvents = {\n SourceUpdate: 'sourceUpdate',\n MaxFsUpdate: 'maxFsUpdate',\n};\n\nexport type {SourceState} from '@webex/internal-media-core';\nexport type CSI = number;\nexport type MemberId = string;\nexport type ReceiveSlotId = string;\n\nlet receiveSlotCounter = 0;\n\nexport type FindMemberIdCallback = (csi: CSI) => MemberId | undefined;\n\n/**\n * Class representing a receive slot. A single receive slot is able to receive a single track\n * for example some participant's main video or audio\n */\nexport class ReceiveSlot extends EventsScope {\n private readonly mcReceiveSlot: WcmeReceiveSlot;\n\n private readonly findMemberIdCallback: FindMemberIdCallback;\n\n public readonly id: ReceiveSlotId;\n\n public readonly mediaType: MediaType;\n\n #memberId?: MemberId;\n\n #csi?: CSI;\n\n #sourceState: SourceState;\n\n /**\n * constructor - don't use it directly, you should always use meeting.receiveSlotManager.allocateSlot()\n * to create any receive slots\n *\n * @param {MediaType} mediaType\n * @param {ReceiveSlot} mcReceiveSlot\n * @param {FindMemberIdCallback} findMemberIdCallback callback for finding memberId for given CSI\n */\n constructor(\n mediaType: MediaType,\n mcReceiveSlot: WcmeReceiveSlot,\n findMemberIdCallback: FindMemberIdCallback\n ) {\n super();\n\n receiveSlotCounter += 1;\n\n this.findMemberIdCallback = findMemberIdCallback;\n this.mediaType = mediaType;\n this.mcReceiveSlot = mcReceiveSlot;\n this.#sourceState = 'no source';\n this.id = `r${receiveSlotCounter}`;\n\n this.setupEventListeners();\n }\n\n /**\n * Getter for memberId\n */\n public get memberId() {\n return this.#memberId;\n }\n\n /**\n * Getter for csi\n */\n public get csi() {\n return this.#csi;\n }\n\n /**\n * Set the max frame size for this slot\n * @param newFs frame size\n */\n public setMaxFs(newFs) {\n // emit event for media request manager to listen to\n\n this.emit(\n {\n file: 'meeting/receiveSlot',\n function: 'findMemberId',\n },\n ReceiveSlotEvents.MaxFsUpdate,\n {\n maxFs: newFs,\n }\n );\n }\n\n /**\n * Getter for sourceState\n */\n public get sourceState() {\n return this.#sourceState;\n }\n\n /**\n * registers event handlers with the underlying ReceiveSlot\n */\n private setupEventListeners() {\n const scope = {\n file: 'meeting/receiveSlot',\n function: 'setupEventListeners',\n };\n\n this.mcReceiveSlot.on(\n WcmeReceiveSlotEvents.SourceUpdate,\n (state: SourceState, csi?: number) => {\n LoggerProxy.logger.log(\n `ReceiveSlot#setupEventListeners --> got source update on receive slot ${this.id}, mediaType=${this.mediaType}, csi=${csi}, state=${state}`\n );\n this.#memberId = csi ? this.findMemberIdCallback(csi) : undefined;\n this.#csi = csi;\n this.#sourceState = state;\n\n this.emit(scope, ReceiveSlotEvents.SourceUpdate, {\n state: this.#sourceState,\n csi: this.#csi,\n memberId: this.#memberId,\n });\n }\n );\n }\n\n /** Tries to find the member id for this receive slot if it hasn't got one */\n public findMemberId() {\n if (this.#memberId === undefined && this.#csi) {\n this.#memberId = this.findMemberIdCallback(this.#csi);\n\n if (this.#memberId) {\n // if we found the memberId, simulate source update so that the client app knows that something's changed\n this.emit(\n {\n file: 'meeting/receiveSlot',\n function: 'findMemberId',\n },\n ReceiveSlotEvents.SourceUpdate,\n {\n state: this.#sourceState,\n csi: this.#csi,\n memberId: this.#memberId,\n }\n );\n }\n }\n }\n\n /**\n * @returns {string} a log message used to identify the receive slot\n */\n public get logString() {\n return `ReceiveSlot - ${this.id}: ${JSON.stringify(this.mcReceiveSlot.id)}`;\n }\n\n /**\n * The MediaStream object associated with this slot.\n *\n * @returns {MediaStream} The MediaStreamTrack.\n */\n get stream(): MediaStream {\n return this.mcReceiveSlot.stream;\n }\n\n /**\n * The underlying WCME receive slot\n */\n get wcmeReceiveSlot(): WcmeReceiveSlot {\n return this.mcReceiveSlot;\n }\n}\n"],"mappings":"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"}
@@ -23,6 +23,7 @@ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime
23
23
  var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/getPrototypeOf"));
24
24
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
25
25
  var _remove2 = _interopRequireDefault(require("lodash/remove"));
26
+ var _forEach2 = _interopRequireDefault(require("lodash/forEach"));
26
27
  var _cloneDeep2 = _interopRequireDefault(require("lodash/cloneDeep"));
27
28
  var _internalMediaCore = require("@webex/internal-media-core");
28
29
  var _loggerProxy = _interopRequireDefault(require("../common/logs/logger-proxy"));
@@ -735,6 +736,25 @@ var RemoteMediaManager = /*#__PURE__*/function (_EventsScope) {
735
736
  this.slots.video.activeSpeaker.length = 0;
736
737
  }
737
738
 
739
+ /**
740
+ * Logs the state of the receive slots
741
+ */
742
+ }, {
743
+ key: "logReceieveSlots",
744
+ value: function logReceieveSlots() {
745
+ var logMessage = '';
746
+ (0, _forEach2.default)(this.receiveSlotAllocations.activeSpeaker, function (group, groupName) {
747
+ logMessage += "group: ".concat(groupName, "\n").concat(group.slots.map(function (slot) {
748
+ return slot.logString;
749
+ }).join(' '));
750
+ });
751
+ logMessage += '\nreceiverSelected:\n';
752
+ (0, _forEach2.default)(this.receiveSlotAllocations.receiverSelected, function (slot, key) {
753
+ logMessage += " ".concat(key, ": ").concat(slot.logString, "\n");
754
+ });
755
+ _loggerProxy.default.logger.log("RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=".concat(this.slots.video.unused.length, ", activeSpeaker=").concat(this.slots.video.activeSpeaker.length, ", receiverSelected=").concat(this.slots.video.receiverSelected.length, "\n").concat(logMessage));
756
+ }
757
+
738
758
  /**
739
759
  * Makes sure we have the right number of receive slots created for the current layout
740
760
  * and allocates them to the right video panes / pane groups
@@ -768,7 +788,7 @@ var RemoteMediaManager = /*#__PURE__*/function (_EventsScope) {
768
788
  this.allocateSlotsToActiveSpeakerPaneGroups();
769
789
  // allocate receiver selected
770
790
  this.allocateSlotsToReceiverSelectedVideoPaneGroups();
771
- _loggerProxy.default.logger.log("RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=".concat(this.slots.video.unused.length, ", activeSpeaker=").concat(this.slots.video.activeSpeaker.length, ", receiverSelected=").concat(this.slots.video.receiverSelected.length));
791
+ this.logReceieveSlots();
772
792
 
773
793
  // If this is the initial layout, there may be some "unused" slots left because of the preallocation
774
794
  // done in this.preallocateVideoReceiveSlots(), so release them now
@@ -1 +1 @@
1
- {"version":3,"names":["AllEqualLayout","activeSpeakerVideoPaneGroups","id","numPanes","size","priority","SingleLayout","OnePlusFiveLayout","TwoMainPlusSixSmallLayout","RemoteScreenShareWithSmallThumbnailsLayout","screenShareVideo","Stage2x2With6ThumbnailsLayout","memberVideoPanes","csi","undefined","DefaultConfiguration","audio","numOfActiveSpeakerStreams","numOfScreenShareStreams","video","preferLiveVideo","initialLayoutId","layouts","AllEqual","OnePlusFive","Single","Stage","ScreenShareView","Event","RemoteMediaManager","receiveSlotManager","mediaRequestManagers","config","started","media","activeSpeakerGroups","memberPanes","screenShare","checkConfigValidity","slots","unused","activeSpeaker","receiverSelected","receiveSlotAllocations","LoggerProxy","logger","log","Error","forEach","layout","groupIds","paneIds","groupPriorites","group","pane","createAudioMedia","createScreenShareReceiveSlots","createScreenShareAudioMedia","preallocateVideoReceiveSlots","setLayout","invalidateCurrentRemoteMedia","screenShareAudio","commit","slot","releaseSlot","length","push","releaseUnusedVideoSlots","currentLayout","currentLayoutId","activeSpeakerCount","reduce","sum","paneGroup","receiverSelectedCount","maxNumVideoPanesRequired","maxValue","Math","max","getRequiredNumVideoSlotsForLayout","allocateSlot","MediaType","VideoMain","layoutId","updateVideoReceiveSlots","updateVideoRemoteMediaObjects","updateScreenShareVideoRemoteMediaObject","emitVideoLayoutChangedEvent","i","AudioMain","RemoteMediaGroup","emit","file","function","AudioCreated","AudioSlides","isAnyLayoutContainingScreenShareVideo","some","VideoSlides","ScreenShareAudioCreated","requiredCsis","memberVideoPane","isCsiNeededByCurrentLayout","notNeededReceiverSelectedSlots","sort","a","b","paneIndex","freeSlot","shift","memberPane","existingSlot","find","isExistingSlotAlreadyAllocated","includes","pop","requiredNumSlots","totalNumSlots","numSlotsToCreate","trimActiveSpeakerSlots","trimReceiverSelectedSlots","refillRequiredSlotsIfNeeded","allocateSlotsToActiveSpeakerPaneGroups","allocateSlotsToReceiverSelectedVideoPaneGroups","groupId","paneGroupInCurrentLayout","groupInLayout","mediaGroup","resolution","warn","paneId","paneInCurrentLayout","paneInLayout","remoteMedia","RemoteMedia","sendMediaRequest","options","stop","remoteMediaGroup","VideoLayoutChanged","activeSpeakerVideoPanes","getRemoteMedia","cancelMediaRequest","newPane","receiveSlot","reject","resolve","getUnderlyingReceiveSlot","index","indexOf","splice","pin","unpin","isPinned","EventsScope"],"sources":["remoteMediaManager.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport {cloneDeep, remove} from 'lodash';\nimport {EventMap} from 'typed-emitter';\nimport {MediaType} from '@webex/internal-media-core';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport EventsScope from '../common/events/events-scope';\n\nimport {RemoteMedia, RemoteVideoResolution} from './remoteMedia';\nimport {ReceiveSlot, CSI} from './receiveSlot';\nimport {ReceiveSlotManager} from './receiveSlotManager';\nimport {RemoteMediaGroup} from './remoteMediaGroup';\nimport {MediaRequestManager} from './mediaRequestManager';\n\nexport type PaneSize = RemoteVideoResolution;\nexport type LayoutId = string;\nexport type PaneId = string;\nexport type PaneGroupId = string;\n\nexport interface ActiveSpeakerVideoPaneGroup {\n id: PaneGroupId;\n numPanes: number; // maximum number of panes in the group (actual number may be lower, if there are not enough participants in the meeting)\n size: PaneSize; // preferred size for all panes in the group\n priority: number; // 0-255 (255 = highest priority), each group must have a different priority from all other groups\n}\n\nexport interface MemberVideoPane {\n id: PaneId;\n size: PaneSize;\n csi?: CSI;\n}\n\nexport interface VideoLayout {\n screenShareVideo?: {\n size: PaneSize;\n };\n activeSpeakerVideoPaneGroups?: ActiveSpeakerVideoPaneGroup[]; // list of active speaker video pane groups\n memberVideoPanes?: MemberVideoPane[]; // list of video panes for specific members, CSI values can be changed later via setVideoPaneCsi()\n}\n\nexport interface Configuration {\n audio: {\n numOfActiveSpeakerStreams: number; // number of audio streams we want to receive\n numOfScreenShareStreams: number; // 1 should be enough, because in webex only 1 person at a time can be presenting screen share\n };\n video: {\n preferLiveVideo: boolean; // applies to all pane groups with active speaker policy\n initialLayoutId: LayoutId;\n\n layouts: {[key: LayoutId]: VideoLayout}; // a map of all available layouts, a layout can be set via setLayout() method\n };\n}\n\n/* Predefined layouts: */\n\n// An \"all equal\" grid, with size up to 3 x 3 = 9:\nconst AllEqualLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'main',\n numPanes: 9,\n size: 'best',\n priority: 255,\n },\n ],\n};\n\n// A layout with just a single remote active speaker video pane:\nconst SingleLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'main',\n numPanes: 1,\n size: 'best',\n priority: 255,\n },\n ],\n};\n\n// A layout with 1 big pane for the highest priority active speaker and 5 small panes for other active speakers:\nconst OnePlusFiveLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'mainBigOne',\n numPanes: 1,\n size: 'large',\n priority: 255,\n },\n {\n id: 'secondarySetOfSmallPanes',\n numPanes: 5,\n size: 'very small',\n priority: 254,\n },\n ],\n};\n\n// A layout with 2 big panes for 2 main active speakers and a strip of 6 small panes for other active speakers:\nconst TwoMainPlusSixSmallLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'mainGroupWith2BigPanes',\n numPanes: 2,\n size: 'large',\n priority: 255,\n },\n {\n id: 'secondaryGroupOfSmallPanes',\n numPanes: 6,\n size: 'small',\n priority: 254,\n },\n ],\n};\n\n// A strip of 8 small video panes (thumbnails) displayed at the top of a remote screenshare:\nconst RemoteScreenShareWithSmallThumbnailsLayout: VideoLayout = {\n screenShareVideo: {size: 'best'},\n activeSpeakerVideoPaneGroups: [\n {\n id: 'thumbnails',\n numPanes: 8,\n size: 'thumbnail',\n priority: 255,\n },\n ],\n};\n\n// A staged layout with 4 pre-selected meeting participants in the main 2x2 grid and 6 small panes for other active speakers at the top:\nconst Stage2x2With6ThumbnailsLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'thumbnails',\n numPanes: 6,\n size: 'thumbnail',\n priority: 255,\n },\n ],\n memberVideoPanes: [\n {id: 'stage-1', size: 'medium', csi: undefined},\n {id: 'stage-2', size: 'medium', csi: undefined},\n {id: 'stage-3', size: 'medium', csi: undefined},\n {id: 'stage-4', size: 'medium', csi: undefined},\n ],\n};\n\n/**\n * Default configuration:\n * - uses 3 audio streams\n * - prefers active speakers with live video (e.g. are not audio only or video muted) over active speakers without live video\n * - has a few layouts defined, including 1 that contains remote screen share (ScreenShareView)\n */\nexport const DefaultConfiguration: Configuration = {\n audio: {\n numOfActiveSpeakerStreams: 3,\n numOfScreenShareStreams: 1,\n },\n video: {\n preferLiveVideo: true,\n initialLayoutId: 'AllEqual',\n\n layouts: {\n AllEqual: AllEqualLayout,\n OnePlusFive: OnePlusFiveLayout,\n Single: SingleLayout,\n Stage: Stage2x2With6ThumbnailsLayout,\n ScreenShareView: RemoteScreenShareWithSmallThumbnailsLayout,\n },\n },\n};\n\nexport enum Event {\n // events for audio streams\n AudioCreated = 'AudioCreated',\n ScreenShareAudioCreated = 'ScreenShareAudioCreated',\n\n // events for video streams\n VideoLayoutChanged = 'VideoLayoutChanged',\n}\n\nexport interface VideoLayoutChangedEventData {\n layoutId: LayoutId;\n activeSpeakerVideoPanes: {\n [key: PaneGroupId]: RemoteMediaGroup;\n };\n memberVideoPanes: {[key: PaneId]: RemoteMedia};\n screenShareVideo?: RemoteMedia;\n}\nexport interface Events extends EventMap {\n // audio\n [Event.AudioCreated]: (audio: RemoteMediaGroup) => void;\n [Event.ScreenShareAudioCreated]: (screenShareAudio: RemoteMediaGroup) => void;\n\n // video\n [Event.VideoLayoutChanged]: (data: VideoLayoutChangedEventData) => void;\n}\n\n/**\n * A helper class that manages all remote audio/video streams in order to achieve a predefined set of layouts.\n * It also creates a fixed number of audio streams and these don't change during the meeting.\n *\n * Things that RemoteMediaManager does:\n * - owns the receive slots (creates them when needed, and re-uses them when switching layouts)\n * - constructs appropriate RemoteMedia and RemoteMediaGroup objects and sends appropriate mediaRequests\n */\nexport class RemoteMediaManager extends EventsScope {\n private config: Configuration;\n\n private started: boolean;\n\n private receiveSlotManager: ReceiveSlotManager;\n\n private mediaRequestManagers: {\n audio: MediaRequestManager;\n video: MediaRequestManager;\n screenShareAudio: MediaRequestManager;\n screenShareVideo: MediaRequestManager;\n };\n\n private currentLayout?: VideoLayout;\n\n private slots: {\n audio: ReceiveSlot[];\n screenShare: {\n audio: ReceiveSlot[];\n video?: ReceiveSlot;\n };\n video: {\n unused: ReceiveSlot[];\n activeSpeaker: ReceiveSlot[];\n receiverSelected: ReceiveSlot[];\n };\n };\n\n private media: {\n audio?: RemoteMediaGroup;\n video: {\n activeSpeakerGroups: {\n [key: PaneGroupId]: RemoteMediaGroup;\n };\n memberPanes: {[key: PaneId]: RemoteMedia};\n };\n screenShare: {\n audio?: RemoteMediaGroup;\n video?: RemoteMediaGroup;\n };\n };\n\n private receiveSlotAllocations: {\n activeSpeaker: {[key: PaneGroupId]: {slots: ReceiveSlot[]}};\n receiverSelected: {[key: PaneId]: ReceiveSlot};\n };\n\n private currentLayoutId?: LayoutId;\n\n /**\n * Constructor\n *\n * @param {ReceiveSlotManager} receiveSlotManager\n * @param {{audio: MediaRequestManager, video: mediaRequestManagers}} mediaRequestManagers\n * @param {Configuration} config Configuration describing what video layouts to use during the meeting\n */\n constructor(\n receiveSlotManager: ReceiveSlotManager,\n mediaRequestManagers: {\n audio: MediaRequestManager;\n video: MediaRequestManager;\n screenShareAudio: MediaRequestManager;\n screenShareVideo: MediaRequestManager;\n },\n config: Configuration = DefaultConfiguration\n ) {\n super();\n this.started = false;\n this.config = config;\n this.receiveSlotManager = receiveSlotManager;\n this.mediaRequestManagers = mediaRequestManagers;\n this.media = {\n audio: undefined,\n video: {\n activeSpeakerGroups: {},\n memberPanes: {},\n },\n screenShare: {\n audio: undefined,\n video: undefined,\n },\n };\n\n this.checkConfigValidity();\n\n this.slots = {\n audio: [],\n screenShare: {\n audio: [],\n video: undefined,\n },\n video: {\n unused: [],\n activeSpeaker: [],\n receiverSelected: [],\n },\n };\n\n this.receiveSlotAllocations = {activeSpeaker: {}, receiverSelected: {}};\n\n LoggerProxy.logger.log(\n `RemoteMediaManager#constructor --> RemoteMediaManager created with config: ${JSON.stringify(\n this.config\n )}`\n );\n }\n\n /**\n * Checks if configuration is valid, throws an error if it's not\n */\n private checkConfigValidity() {\n if (!(this.config.video.initialLayoutId in this.config.video.layouts)) {\n throw new Error(\n `invalid config: initialLayoutId \"${this.config.video.initialLayoutId}\" doesn't match any of the layouts`\n );\n }\n\n // check if each layout is valid\n Object.values(this.config.video.layouts).forEach((layout) => {\n const groupIds = {};\n const paneIds = {};\n const groupPriorites = {};\n\n layout.activeSpeakerVideoPaneGroups?.forEach((group) => {\n if (groupIds[group.id]) {\n throw new Error(\n `invalid config: duplicate active speaker video pane group id: ${group.id}`\n );\n }\n groupIds[group.id] = true;\n\n if (groupPriorites[group.priority]) {\n throw new Error(\n `invalid config: multiple active speaker video pane groups have same priority: ${group.priority}`\n );\n }\n groupPriorites[group.priority] = true;\n });\n\n layout.memberVideoPanes?.forEach((pane) => {\n if (paneIds[pane.id]) {\n throw new Error(`invalid config: duplicate member video pane id: ${pane.id}`);\n }\n paneIds[pane.id] = true;\n });\n });\n }\n\n /**\n * Starts the RemoteMediaManager.\n *\n * @returns {Promise}\n */\n public async start() {\n if (this.started) {\n throw new Error('start() failure: already started');\n }\n this.started = true;\n\n await this.createAudioMedia();\n\n await this.createScreenShareReceiveSlots();\n this.createScreenShareAudioMedia();\n\n await this.preallocateVideoReceiveSlots();\n\n await this.setLayout(this.config.video.initialLayoutId);\n }\n\n /**\n * Releases all the used resources (like allocated receive slots). This function needs\n * to be called when we leave the meeting, etc.\n */\n public stop() {\n // invalidate all remoteMedia objects\n this.invalidateCurrentRemoteMedia({\n audio: true,\n video: true,\n screenShareAudio: true,\n screenShareVideo: true,\n commit: true,\n });\n\n // release all audio receive slots\n this.slots.audio.forEach((slot) => this.receiveSlotManager.releaseSlot(slot));\n this.slots.audio.length = 0;\n\n // release screen share slots\n this.slots.screenShare.audio.forEach((slot) => this.receiveSlotManager.releaseSlot(slot));\n this.slots.screenShare.audio.length = 0;\n if (this.slots.screenShare.video) {\n this.receiveSlotManager.releaseSlot(this.slots.screenShare.video);\n this.slots.screenShare.video = undefined;\n }\n\n // release video slots\n this.receiveSlotAllocations = {activeSpeaker: {}, receiverSelected: {}};\n\n this.slots.video.unused.push(...this.slots.video.activeSpeaker);\n this.slots.video.activeSpeaker.length = 0;\n\n this.slots.video.unused.push(...this.slots.video.receiverSelected);\n this.slots.video.receiverSelected.length = 0;\n\n this.releaseUnusedVideoSlots();\n\n this.currentLayout = undefined;\n this.currentLayoutId = undefined;\n this.started = false;\n }\n\n /**\n * Returns the total number of main video panes required for a given layout\n *\n * @param {VideoLayout} layout\n * @returns {number}\n */\n private getRequiredNumVideoSlotsForLayout(layout?: VideoLayout) {\n if (!layout) {\n return 0;\n }\n\n const activeSpeakerCount =\n layout.activeSpeakerVideoPaneGroups?.reduce(\n (sum, paneGroup) => sum + paneGroup.numPanes,\n 0\n ) || 0;\n\n const receiverSelectedCount = layout.memberVideoPanes?.length || 0;\n\n return activeSpeakerCount + receiverSelectedCount;\n }\n\n /**\n * Allocates the maximum number of panes that any of the configured layouts will require.\n * We do this at the beginning, because it's more efficient (much faster) then allocating receive slots\n * later, after the SDP exchange was done.\n */\n private async preallocateVideoReceiveSlots() {\n const maxNumVideoPanesRequired = Object.values(this.config.video.layouts).reduce(\n (maxValue, layout) => Math.max(maxValue, this.getRequiredNumVideoSlotsForLayout(layout)),\n 0\n );\n\n while (this.slots.video.unused.length < maxNumVideoPanesRequired) {\n // eslint-disable-next-line no-await-in-loop\n this.slots.video.unused.push(\n // eslint-disable-next-line no-await-in-loop\n await this.receiveSlotManager.allocateSlot(MediaType.VideoMain)\n );\n }\n }\n\n /**\n * Changes the layout (triggers Event.VideoLayoutChanged)\n *\n * @param {LayoutId} layoutId new layout id\n * @returns {Promise}\n */\n public async setLayout(layoutId: LayoutId) {\n if (!(layoutId in this.config.video.layouts)) {\n throw new Error(\n `invalid layoutId: \"${layoutId}\" doesn't match any of the configured layouts`\n );\n }\n if (!this.started) {\n throw new Error('setLayout() called before start()');\n }\n this.currentLayoutId = layoutId;\n this.currentLayout = cloneDeep(this.config.video.layouts[this.currentLayoutId]);\n\n await this.updateVideoReceiveSlots();\n this.updateVideoRemoteMediaObjects();\n this.updateScreenShareVideoRemoteMediaObject();\n this.emitVideoLayoutChangedEvent();\n }\n\n /**\n * Returns the currently selected layout id\n *\n * @returns {LayoutId}\n */\n public getLayoutId(): LayoutId | undefined {\n return this.currentLayoutId;\n }\n\n /**\n * Creates the audio slots\n */\n private async createAudioMedia() {\n // create the audio receive slots\n for (let i = 0; i < this.config.audio.numOfActiveSpeakerStreams; i += 1) {\n // eslint-disable-next-line no-await-in-loop\n const slot = await this.receiveSlotManager.allocateSlot(MediaType.AudioMain);\n\n this.slots.audio.push(slot);\n }\n\n // create a remote media group\n this.media.audio = new RemoteMediaGroup(\n this.mediaRequestManagers.audio,\n this.slots.audio,\n 255,\n true\n );\n\n this.emit(\n {file: 'multistream/remoteMediaManager', function: 'createAudioMedia'},\n Event.AudioCreated,\n this.media.audio\n );\n }\n\n /**\n * Creates receive slots required for receiving screen share audio and video\n */\n private async createScreenShareReceiveSlots() {\n // audio\n for (let i = 0; i < this.config.audio.numOfScreenShareStreams; i += 1) {\n // eslint-disable-next-line no-await-in-loop\n const slot = await this.receiveSlotManager.allocateSlot(MediaType.AudioSlides);\n\n this.slots.screenShare.audio.push(slot);\n }\n\n // video\n const isAnyLayoutContainingScreenShareVideo = Object.values(this.config.video.layouts).some(\n (layout) => !!layout.screenShareVideo\n );\n\n if (isAnyLayoutContainingScreenShareVideo) {\n this.slots.screenShare.video = await this.receiveSlotManager.allocateSlot(\n MediaType.VideoSlides\n );\n }\n }\n\n /**\n * Creates RemoteMedia objects for screen share\n */\n private createScreenShareAudioMedia() {\n if (this.slots.screenShare.audio.length > 0) {\n this.media.screenShare.audio = new RemoteMediaGroup(\n this.mediaRequestManagers.screenShareAudio,\n this.slots.screenShare.audio,\n 255,\n true\n );\n\n this.emit(\n {file: 'multistream/remoteMediaManager', function: 'createScreenShareAudioMedia'},\n Event.ScreenShareAudioCreated,\n this.media.screenShare.audio\n );\n }\n }\n\n /**\n * Goes over all receiver-selected slots and keeps only the ones that are required by a given layout,\n * the rest are all moved to the \"unused\" list\n */\n private trimReceiverSelectedSlots() {\n const requiredCsis = {};\n\n // fill requiredCsis with all the CSIs that the given layout requires\n this.currentLayout?.memberVideoPanes?.forEach((memberVideoPane) => {\n if (memberVideoPane.csi !== undefined) {\n requiredCsis[memberVideoPane.csi] = true;\n }\n });\n\n const isCsiNeededByCurrentLayout = (csi?: CSI): boolean => {\n if (csi === undefined) {\n return false;\n }\n\n return !!requiredCsis[csi];\n };\n\n // keep receiverSelected slots that match our new requiredCsis, move the rest of receiverSelected slots to unused\n const notNeededReceiverSelectedSlots = remove(\n this.slots.video.receiverSelected,\n (slot) => isCsiNeededByCurrentLayout(slot.csi) === false\n );\n\n this.slots.video.unused.push(...notNeededReceiverSelectedSlots);\n }\n\n /**\n * Releases all the \"unused\" video slots.\n */\n private releaseUnusedVideoSlots() {\n this.slots.video.unused.forEach((slot) => this.receiveSlotManager.releaseSlot(slot));\n this.slots.video.unused.length = 0;\n }\n\n /**\n * Allocates receive slots to all active speaker video panes\n * in the current selected layout.\n *\n * Allocation tries to keep the same order of the slots between the previous\n * layout and the new one. Sorting helps making sure that highest priority slots\n * go in the same order in the new layout.\n */\n private allocateSlotsToActiveSpeakerPaneGroups() {\n this.currentLayout?.activeSpeakerVideoPaneGroups\n // sorting in descending order based on group priority\n ?.sort((a, b) => (a.priority < b.priority ? 1 : -1))\n ?.forEach((group) => {\n this.receiveSlotAllocations.activeSpeaker[group.id] = {slots: []};\n\n for (let paneIndex = 0; paneIndex < group.numPanes; paneIndex += 1) {\n // allocate a slot from the \"unused\" list, by grabbing in same order (shift) as previous layout\n const freeSlot = this.slots.video.unused.shift();\n\n if (freeSlot) {\n this.slots.video.activeSpeaker.push(freeSlot);\n this.receiveSlotAllocations.activeSpeaker[group.id].slots.push(freeSlot);\n }\n }\n });\n }\n\n /**\n * Allocates receive slots to all receiver selected video panes\n * in the current selected layout\n */\n private allocateSlotsToReceiverSelectedVideoPaneGroups() {\n this.currentLayout?.memberVideoPanes?.forEach((memberPane) => {\n // check if there is existing slot for this csi\n const existingSlot = this.slots.video.receiverSelected.find(\n (slot) => slot.csi === memberPane.csi\n );\n\n const isExistingSlotAlreadyAllocated = Object.values(\n this.receiveSlotAllocations.receiverSelected\n ).includes(existingSlot);\n\n if (memberPane.csi !== undefined && existingSlot && !isExistingSlotAlreadyAllocated) {\n // found it, so use it\n this.receiveSlotAllocations.receiverSelected[memberPane.id] = existingSlot;\n } else {\n // allocate a slot from the \"unused\" list\n const freeSlot = this.slots.video.unused.pop();\n\n if (freeSlot) {\n this.slots.video.receiverSelected.push(freeSlot);\n this.receiveSlotAllocations.receiverSelected[memberPane.id] = freeSlot;\n }\n }\n });\n }\n\n /**\n * Ensures that we have enough slots for the current layout.\n */\n private async refillRequiredSlotsIfNeeded() {\n const requiredNumSlots = this.getRequiredNumVideoSlotsForLayout(this.currentLayout);\n const totalNumSlots =\n this.slots.video.unused.length +\n this.slots.video.activeSpeaker.length +\n this.slots.video.receiverSelected.length;\n\n if (totalNumSlots < requiredNumSlots) {\n let numSlotsToCreate = requiredNumSlots - totalNumSlots;\n\n while (numSlotsToCreate > 0) {\n // eslint-disable-next-line no-await-in-loop\n this.slots.video.unused.push(\n // eslint-disable-next-line no-await-in-loop\n await this.receiveSlotManager.allocateSlot(MediaType.VideoMain)\n );\n numSlotsToCreate -= 1;\n }\n }\n }\n\n /**\n * Move all active speaker slots to \"unused\"\n */\n private trimActiveSpeakerSlots() {\n this.slots.video.unused.push(...this.slots.video.activeSpeaker);\n this.slots.video.activeSpeaker.length = 0;\n }\n\n /**\n * Makes sure we have the right number of receive slots created for the current layout\n * and allocates them to the right video panes / pane groups\n *\n * @returns {Promise}\n */\n private async updateVideoReceiveSlots() {\n // move all active speaker slots to \"unused\"\n this.trimActiveSpeakerSlots();\n\n // move all no longer needed receiver-selected slots to \"unused\"\n this.trimReceiverSelectedSlots();\n\n // ensure we have enough total slots for current layout\n await this.refillRequiredSlotsIfNeeded();\n\n // allocate the slots to the right panes / pane groups\n // reset allocations\n this.receiveSlotAllocations = {activeSpeaker: {}, receiverSelected: {}};\n // allocate active speaker\n this.allocateSlotsToActiveSpeakerPaneGroups();\n // allocate receiver selected\n this.allocateSlotsToReceiverSelectedVideoPaneGroups();\n\n LoggerProxy.logger.log(\n `RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=${this.slots.video.unused.length}, activeSpeaker=${this.slots.video.activeSpeaker.length}, receiverSelected=${this.slots.video.receiverSelected.length}`\n );\n\n // If this is the initial layout, there may be some \"unused\" slots left because of the preallocation\n // done in this.preallocateVideoReceiveSlots(), so release them now\n this.releaseUnusedVideoSlots();\n }\n\n /**\n * Creates new RemoteMedia and RemoteMediaGroup objects for the current layout\n * and sends the media requests for all of them.\n */\n private updateVideoRemoteMediaObjects() {\n // invalidate all the previous remote media objects and cancel their media requests\n this.invalidateCurrentRemoteMedia({\n audio: false,\n video: true,\n screenShareAudio: false,\n screenShareVideo: false,\n commit: false,\n });\n\n // create new remoteMediaGroup objects\n this.media.video.activeSpeakerGroups = {};\n this.media.video.memberPanes = {};\n\n for (const [groupId, group] of Object.entries(this.receiveSlotAllocations.activeSpeaker)) {\n const paneGroupInCurrentLayout = this.currentLayout?.activeSpeakerVideoPaneGroups?.find(\n (groupInLayout) => groupInLayout.id === groupId\n );\n\n if (paneGroupInCurrentLayout) {\n const mediaGroup = new RemoteMediaGroup(\n this.mediaRequestManagers.video,\n group.slots,\n paneGroupInCurrentLayout.priority,\n false,\n {\n preferLiveVideo: this.config.video.preferLiveVideo,\n resolution: paneGroupInCurrentLayout.size,\n }\n );\n\n this.media.video.activeSpeakerGroups[groupId] = mediaGroup;\n } else {\n // this should never happen, because this.receiveSlotAllocations are created based on current layout configuration\n LoggerProxy.logger.warn(\n `a group id ${groupId} from this.receiveSlotAllocations.activeSpeaker cannot be found in the current layout configuration`\n );\n }\n }\n\n // create new remoteMedia objects\n for (const [paneId, slot] of Object.entries(this.receiveSlotAllocations.receiverSelected)) {\n const paneInCurrentLayout = this.currentLayout?.memberVideoPanes?.find(\n (paneInLayout) => paneInLayout.id === paneId\n );\n\n if (paneInCurrentLayout) {\n const remoteMedia = new RemoteMedia(slot, this.mediaRequestManagers.video, {\n resolution: paneInCurrentLayout.size,\n });\n\n if (paneInCurrentLayout.csi) {\n remoteMedia.sendMediaRequest(paneInCurrentLayout.csi, false);\n }\n\n this.media.video.memberPanes[paneId] = remoteMedia;\n } else {\n // this should never happen, because this.receiveSlotAllocations are created based on current layout configuration\n LoggerProxy.logger.warn(\n `a pane id ${paneId} from this.receiveSlotAllocations.receiverSelected cannot be found in the current layout configuration`\n );\n }\n }\n\n this.mediaRequestManagers.video.commit();\n }\n\n /**\n * Checks if current layout requires a screen share.\n * If it does, it creates new RemoteMediaGroup object for screen share\n * and sends the media requests for it.\n * If it doesn't, it makes sure we clean up any RemoteMediaGroup objects\n * created earlier for screen share (for previous layout).\n */\n private updateScreenShareVideoRemoteMediaObject() {\n this.invalidateCurrentRemoteMedia({\n audio: false,\n video: false,\n screenShareAudio: false,\n screenShareVideo: true,\n commit: false,\n });\n\n this.media.screenShare.video = undefined;\n\n if (this.currentLayout?.screenShareVideo) {\n // we create a group of 1, because for screen share we need to use the \"active speaker\" policy\n this.media.screenShare.video = new RemoteMediaGroup(\n this.mediaRequestManagers.screenShareVideo,\n [this.slots.screenShare.video],\n 255,\n false,\n {resolution: this.currentLayout.screenShareVideo.size}\n );\n }\n\n this.mediaRequestManagers.screenShareVideo.commit();\n }\n\n /**\n * Invalidates all remote media objects belonging to currently selected layout\n */\n private invalidateCurrentRemoteMedia(options: {\n audio: boolean;\n video: boolean;\n screenShareAudio: boolean;\n screenShareVideo: boolean;\n commit: boolean;\n }) {\n const {audio, video, screenShareAudio, screenShareVideo, commit} = options;\n\n if (audio && this.media.audio) {\n this.media.audio.stop(commit);\n }\n if (video) {\n Object.values(this.media.video.activeSpeakerGroups).forEach((remoteMediaGroup) => {\n remoteMediaGroup.stop(false);\n });\n Object.values(this.media.video.memberPanes).forEach((remoteMedia) => {\n remoteMedia.stop(false);\n });\n if (commit) {\n this.mediaRequestManagers.video.commit();\n }\n }\n\n if (screenShareAudio && this.media.screenShare.audio) {\n this.media.screenShare.audio.stop(commit);\n }\n if (screenShareVideo && this.media.screenShare.video) {\n this.media.screenShare.video.stop(commit);\n }\n }\n\n /** emits Event.VideoLayoutChanged */\n private emitVideoLayoutChangedEvent() {\n // todo: at this point the receive slots might still be showing a participant from previous layout, we should\n // wait for our media requests to be fulfilled, but there is no API for that right now (we could wait for source updates\n // but in some cases they might never come, or would need to always make sure to use a new set of receiver slots)\n // for now it's fine to have it like this, we will re-evaluate if it needs improving after more testing\n\n this.emit(\n {\n file: 'multistream/remoteMediaManager',\n function: 'emitVideoLayoutChangedEvent',\n },\n Event.VideoLayoutChanged,\n {\n layoutId: this.currentLayoutId,\n activeSpeakerVideoPanes: this.media.video.activeSpeakerGroups,\n memberVideoPanes: this.media.video.memberPanes,\n screenShareVideo: this.media.screenShare.video?.getRemoteMedia()[0],\n }\n );\n }\n\n /**\n * Sets a new CSI on a given remote media object\n *\n * @param {RemoteMedia} remoteMedia remote Media object to modify\n * @param {CSI} csi new CSI value, can be null if we want to stop receiving media\n */\n public setRemoteVideoCsi(remoteMedia: RemoteMedia, csi: CSI | null) {\n if (!Object.values(this.media.video.memberPanes).includes(remoteMedia)) {\n throw new Error('remoteMedia not found');\n }\n\n if (csi) {\n remoteMedia.sendMediaRequest(csi, true);\n } else {\n remoteMedia.cancelMediaRequest(true);\n }\n }\n\n /**\n * Adds a new member video pane to the currently selected layout.\n *\n * Changes to the layout are lost after a layout change.\n *\n * @param {MemberVideoPane} newPane\n * @returns {Promise<RemoteMedia>}\n */\n public async addMemberVideoPane(newPane: MemberVideoPane): Promise<RemoteMedia> {\n if (!this.currentLayout) {\n throw new Error('There is no current layout selected, call start() first');\n }\n\n if (!this.currentLayout?.memberVideoPanes) {\n this.currentLayout.memberVideoPanes = [];\n }\n\n if (newPane.id in this.currentLayout.memberVideoPanes) {\n throw new Error(\n `duplicate pane id ${newPane.id} - this pane already exists in current layout's memberVideoPanes`\n );\n }\n\n this.currentLayout.memberVideoPanes.push(newPane);\n\n const receiveSlot = await this.receiveSlotManager.allocateSlot(MediaType.VideoMain);\n\n this.slots.video.receiverSelected.push(receiveSlot);\n\n const remoteMedia = new RemoteMedia(receiveSlot, this.mediaRequestManagers.video, {\n resolution: newPane.size,\n });\n\n if (newPane.csi) {\n remoteMedia.sendMediaRequest(newPane.csi, true);\n }\n\n this.media.video.memberPanes[newPane.id] = remoteMedia;\n\n return remoteMedia;\n }\n\n /**\n * Removes a member video pane from the currently selected layout.\n *\n * Changes to the layout are lost after a layout change.\n *\n * @param {PaneId} paneId pane id of the pane to remove\n * @returns {Promise<void>}\n */\n public removeMemberVideoPane(paneId: PaneId): Promise<void> {\n if (!this.currentLayout) {\n return Promise.reject(new Error('There is no current layout selected, call start() first'));\n }\n\n if (!this.currentLayout.memberVideoPanes?.find((pane) => pane.id === paneId)) {\n // pane id doesn't exist, so nothing to do\n LoggerProxy.logger.log(\n `RemoteMediaManager#removeMemberVideoPane --> removeMemberVideoPane() called for a non-existent paneId: ${paneId} (pane not found in currentLayout.memberVideoPanes)`\n );\n\n return Promise.resolve();\n }\n\n if (!this.media.video.memberPanes[paneId]) {\n // pane id doesn't exist, so nothing to do\n LoggerProxy.logger.log(\n `RemoteMediaManager#removeMemberVideoPane --> removeMemberVideoPane() called for a non-existent paneId: ${paneId} (pane not found in this.media.video.memberPanes)`\n );\n\n return Promise.resolve();\n }\n\n const remoteMedia = this.media.video.memberPanes[paneId];\n\n const receiveSlot = remoteMedia.getUnderlyingReceiveSlot();\n\n if (receiveSlot) {\n this.receiveSlotManager.releaseSlot(receiveSlot);\n\n const index = this.slots.video.receiverSelected.indexOf(receiveSlot);\n\n if (index >= 0) {\n this.slots.video.receiverSelected.splice(index, 1);\n }\n }\n remoteMedia.stop();\n\n delete this.media.video.memberPanes[paneId];\n delete this.currentLayout.memberVideoPanes?.[paneId];\n\n return Promise.resolve();\n }\n\n /**\n * Pins an active speaker remote media object to the given CSI value. From that moment\n * onwards the remote media will only play audio/video from that specific CSI until\n * unpinActiveSpeakerVideoPane() is called or current layout is changed.\n *\n * @param {RemoteMedia} remoteMedia remote media object reference\n * @param {CSI} csi CSI value to pin to, if undefined, then current CSI value is used\n */\n public pinActiveSpeakerVideoPane(remoteMedia: RemoteMedia, csi?: CSI): void {\n const remoteMediaGroup = Object.values(this.media.video.activeSpeakerGroups).find((group) =>\n group.includes(remoteMedia, 'unpinned')\n );\n\n if (!remoteMediaGroup) {\n throw new Error(\n 'remoteMedia not found among the unpinned remote media from any active speaker group'\n );\n }\n\n remoteMediaGroup.pin(remoteMedia, csi);\n }\n\n /**\n * Unpins a remote media object from the fixed CSI value it was pinned to.\n *\n * @param {RemoteMedia} remoteMedia remote media object reference\n */\n public unpinActiveSpeakerVideoPane(remoteMedia: RemoteMedia) {\n const remoteMediaGroup = Object.values(this.media.video.activeSpeakerGroups).find((group) =>\n group.includes(remoteMedia, 'pinned')\n );\n\n if (!remoteMediaGroup) {\n throw new Error(\n 'remoteMedia not found among the pinned remote media from any active speaker group'\n );\n }\n\n remoteMediaGroup.unpin(remoteMedia);\n }\n\n /**\n * Returns true if a given remote media object belongs to an active speaker group and has been pinned.\n * Throws an error if the remote media object doesn't belong to any active speaker remote media group.\n *\n * @param {RemoteMedia} remoteMedia remote media object\n * @returns {boolean}\n */\n public isPinned(remoteMedia: RemoteMedia) {\n const remoteMediaGroup = Object.values(this.media.video.activeSpeakerGroups).find((group) =>\n group.includes(remoteMedia)\n );\n\n if (!remoteMediaGroup) {\n throw new Error(\n 'remoteMedia not found among any remote media (pinned or unpinned) from any active speaker group'\n );\n }\n\n return remoteMediaGroup.isPinned(remoteMedia);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["AllEqualLayout","activeSpeakerVideoPaneGroups","id","numPanes","size","priority","SingleLayout","OnePlusFiveLayout","TwoMainPlusSixSmallLayout","RemoteScreenShareWithSmallThumbnailsLayout","screenShareVideo","Stage2x2With6ThumbnailsLayout","memberVideoPanes","csi","undefined","DefaultConfiguration","audio","numOfActiveSpeakerStreams","numOfScreenShareStreams","video","preferLiveVideo","initialLayoutId","layouts","AllEqual","OnePlusFive","Single","Stage","ScreenShareView","Event","RemoteMediaManager","receiveSlotManager","mediaRequestManagers","config","started","media","activeSpeakerGroups","memberPanes","screenShare","checkConfigValidity","slots","unused","activeSpeaker","receiverSelected","receiveSlotAllocations","LoggerProxy","logger","log","Error","forEach","layout","groupIds","paneIds","groupPriorites","group","pane","createAudioMedia","createScreenShareReceiveSlots","createScreenShareAudioMedia","preallocateVideoReceiveSlots","setLayout","invalidateCurrentRemoteMedia","screenShareAudio","commit","slot","releaseSlot","length","push","releaseUnusedVideoSlots","currentLayout","currentLayoutId","activeSpeakerCount","reduce","sum","paneGroup","receiverSelectedCount","maxNumVideoPanesRequired","maxValue","Math","max","getRequiredNumVideoSlotsForLayout","allocateSlot","MediaType","VideoMain","layoutId","updateVideoReceiveSlots","updateVideoRemoteMediaObjects","updateScreenShareVideoRemoteMediaObject","emitVideoLayoutChangedEvent","i","AudioMain","RemoteMediaGroup","emit","file","function","AudioCreated","AudioSlides","isAnyLayoutContainingScreenShareVideo","some","VideoSlides","ScreenShareAudioCreated","requiredCsis","memberVideoPane","isCsiNeededByCurrentLayout","notNeededReceiverSelectedSlots","sort","a","b","paneIndex","freeSlot","shift","memberPane","existingSlot","find","isExistingSlotAlreadyAllocated","includes","pop","requiredNumSlots","totalNumSlots","numSlotsToCreate","logMessage","groupName","map","logString","join","key","trimActiveSpeakerSlots","trimReceiverSelectedSlots","refillRequiredSlotsIfNeeded","allocateSlotsToActiveSpeakerPaneGroups","allocateSlotsToReceiverSelectedVideoPaneGroups","logReceieveSlots","groupId","paneGroupInCurrentLayout","groupInLayout","mediaGroup","resolution","warn","paneId","paneInCurrentLayout","paneInLayout","remoteMedia","RemoteMedia","sendMediaRequest","options","stop","remoteMediaGroup","VideoLayoutChanged","activeSpeakerVideoPanes","getRemoteMedia","cancelMediaRequest","newPane","receiveSlot","reject","resolve","getUnderlyingReceiveSlot","index","indexOf","splice","pin","unpin","isPinned","EventsScope"],"sources":["remoteMediaManager.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport {cloneDeep, forEach, remove} from 'lodash';\nimport {EventMap} from 'typed-emitter';\nimport {MediaType} from '@webex/internal-media-core';\n\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport EventsScope from '../common/events/events-scope';\n\nimport {RemoteMedia, RemoteVideoResolution} from './remoteMedia';\nimport {ReceiveSlot, CSI} from './receiveSlot';\nimport {ReceiveSlotManager} from './receiveSlotManager';\nimport {RemoteMediaGroup} from './remoteMediaGroup';\nimport {MediaRequestManager} from './mediaRequestManager';\n\nexport type PaneSize = RemoteVideoResolution;\nexport type LayoutId = string;\nexport type PaneId = string;\nexport type PaneGroupId = string;\n\nexport interface ActiveSpeakerVideoPaneGroup {\n id: PaneGroupId;\n numPanes: number; // maximum number of panes in the group (actual number may be lower, if there are not enough participants in the meeting)\n size: PaneSize; // preferred size for all panes in the group\n priority: number; // 0-255 (255 = highest priority), each group must have a different priority from all other groups\n}\n\nexport interface MemberVideoPane {\n id: PaneId;\n size: PaneSize;\n csi?: CSI;\n}\n\nexport interface VideoLayout {\n screenShareVideo?: {\n size: PaneSize;\n };\n activeSpeakerVideoPaneGroups?: ActiveSpeakerVideoPaneGroup[]; // list of active speaker video pane groups\n memberVideoPanes?: MemberVideoPane[]; // list of video panes for specific members, CSI values can be changed later via setVideoPaneCsi()\n}\n\nexport interface Configuration {\n audio: {\n numOfActiveSpeakerStreams: number; // number of audio streams we want to receive\n numOfScreenShareStreams: number; // 1 should be enough, because in webex only 1 person at a time can be presenting screen share\n };\n video: {\n preferLiveVideo: boolean; // applies to all pane groups with active speaker policy\n initialLayoutId: LayoutId;\n\n layouts: {[key: LayoutId]: VideoLayout}; // a map of all available layouts, a layout can be set via setLayout() method\n };\n}\n\n/* Predefined layouts: */\n\n// An \"all equal\" grid, with size up to 3 x 3 = 9:\nconst AllEqualLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'main',\n numPanes: 9,\n size: 'best',\n priority: 255,\n },\n ],\n};\n\n// A layout with just a single remote active speaker video pane:\nconst SingleLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'main',\n numPanes: 1,\n size: 'best',\n priority: 255,\n },\n ],\n};\n\n// A layout with 1 big pane for the highest priority active speaker and 5 small panes for other active speakers:\nconst OnePlusFiveLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'mainBigOne',\n numPanes: 1,\n size: 'large',\n priority: 255,\n },\n {\n id: 'secondarySetOfSmallPanes',\n numPanes: 5,\n size: 'very small',\n priority: 254,\n },\n ],\n};\n\n// A layout with 2 big panes for 2 main active speakers and a strip of 6 small panes for other active speakers:\nconst TwoMainPlusSixSmallLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'mainGroupWith2BigPanes',\n numPanes: 2,\n size: 'large',\n priority: 255,\n },\n {\n id: 'secondaryGroupOfSmallPanes',\n numPanes: 6,\n size: 'small',\n priority: 254,\n },\n ],\n};\n\n// A strip of 8 small video panes (thumbnails) displayed at the top of a remote screenshare:\nconst RemoteScreenShareWithSmallThumbnailsLayout: VideoLayout = {\n screenShareVideo: {size: 'best'},\n activeSpeakerVideoPaneGroups: [\n {\n id: 'thumbnails',\n numPanes: 8,\n size: 'thumbnail',\n priority: 255,\n },\n ],\n};\n\n// A staged layout with 4 pre-selected meeting participants in the main 2x2 grid and 6 small panes for other active speakers at the top:\nconst Stage2x2With6ThumbnailsLayout: VideoLayout = {\n activeSpeakerVideoPaneGroups: [\n {\n id: 'thumbnails',\n numPanes: 6,\n size: 'thumbnail',\n priority: 255,\n },\n ],\n memberVideoPanes: [\n {id: 'stage-1', size: 'medium', csi: undefined},\n {id: 'stage-2', size: 'medium', csi: undefined},\n {id: 'stage-3', size: 'medium', csi: undefined},\n {id: 'stage-4', size: 'medium', csi: undefined},\n ],\n};\n\n/**\n * Default configuration:\n * - uses 3 audio streams\n * - prefers active speakers with live video (e.g. are not audio only or video muted) over active speakers without live video\n * - has a few layouts defined, including 1 that contains remote screen share (ScreenShareView)\n */\nexport const DefaultConfiguration: Configuration = {\n audio: {\n numOfActiveSpeakerStreams: 3,\n numOfScreenShareStreams: 1,\n },\n video: {\n preferLiveVideo: true,\n initialLayoutId: 'AllEqual',\n\n layouts: {\n AllEqual: AllEqualLayout,\n OnePlusFive: OnePlusFiveLayout,\n Single: SingleLayout,\n Stage: Stage2x2With6ThumbnailsLayout,\n ScreenShareView: RemoteScreenShareWithSmallThumbnailsLayout,\n },\n },\n};\n\nexport enum Event {\n // events for audio streams\n AudioCreated = 'AudioCreated',\n ScreenShareAudioCreated = 'ScreenShareAudioCreated',\n\n // events for video streams\n VideoLayoutChanged = 'VideoLayoutChanged',\n}\n\nexport interface VideoLayoutChangedEventData {\n layoutId: LayoutId;\n activeSpeakerVideoPanes: {\n [key: PaneGroupId]: RemoteMediaGroup;\n };\n memberVideoPanes: {[key: PaneId]: RemoteMedia};\n screenShareVideo?: RemoteMedia;\n}\nexport interface Events extends EventMap {\n // audio\n [Event.AudioCreated]: (audio: RemoteMediaGroup) => void;\n [Event.ScreenShareAudioCreated]: (screenShareAudio: RemoteMediaGroup) => void;\n\n // video\n [Event.VideoLayoutChanged]: (data: VideoLayoutChangedEventData) => void;\n}\n\n/**\n * A helper class that manages all remote audio/video streams in order to achieve a predefined set of layouts.\n * It also creates a fixed number of audio streams and these don't change during the meeting.\n *\n * Things that RemoteMediaManager does:\n * - owns the receive slots (creates them when needed, and re-uses them when switching layouts)\n * - constructs appropriate RemoteMedia and RemoteMediaGroup objects and sends appropriate mediaRequests\n */\nexport class RemoteMediaManager extends EventsScope {\n private config: Configuration;\n\n private started: boolean;\n\n private receiveSlotManager: ReceiveSlotManager;\n\n private mediaRequestManagers: {\n audio: MediaRequestManager;\n video: MediaRequestManager;\n screenShareAudio: MediaRequestManager;\n screenShareVideo: MediaRequestManager;\n };\n\n private currentLayout?: VideoLayout;\n\n private slots: {\n audio: ReceiveSlot[];\n screenShare: {\n audio: ReceiveSlot[];\n video?: ReceiveSlot;\n };\n video: {\n unused: ReceiveSlot[];\n activeSpeaker: ReceiveSlot[];\n receiverSelected: ReceiveSlot[];\n };\n };\n\n private media: {\n audio?: RemoteMediaGroup;\n video: {\n activeSpeakerGroups: {\n [key: PaneGroupId]: RemoteMediaGroup;\n };\n memberPanes: {[key: PaneId]: RemoteMedia};\n };\n screenShare: {\n audio?: RemoteMediaGroup;\n video?: RemoteMediaGroup;\n };\n };\n\n private receiveSlotAllocations: {\n activeSpeaker: {[key: PaneGroupId]: {slots: ReceiveSlot[]}};\n receiverSelected: {[key: PaneId]: ReceiveSlot};\n };\n\n private currentLayoutId?: LayoutId;\n\n /**\n * Constructor\n *\n * @param {ReceiveSlotManager} receiveSlotManager\n * @param {{audio: MediaRequestManager, video: mediaRequestManagers}} mediaRequestManagers\n * @param {Configuration} config Configuration describing what video layouts to use during the meeting\n */\n constructor(\n receiveSlotManager: ReceiveSlotManager,\n mediaRequestManagers: {\n audio: MediaRequestManager;\n video: MediaRequestManager;\n screenShareAudio: MediaRequestManager;\n screenShareVideo: MediaRequestManager;\n },\n config: Configuration = DefaultConfiguration\n ) {\n super();\n this.started = false;\n this.config = config;\n this.receiveSlotManager = receiveSlotManager;\n this.mediaRequestManagers = mediaRequestManagers;\n this.media = {\n audio: undefined,\n video: {\n activeSpeakerGroups: {},\n memberPanes: {},\n },\n screenShare: {\n audio: undefined,\n video: undefined,\n },\n };\n\n this.checkConfigValidity();\n\n this.slots = {\n audio: [],\n screenShare: {\n audio: [],\n video: undefined,\n },\n video: {\n unused: [],\n activeSpeaker: [],\n receiverSelected: [],\n },\n };\n\n this.receiveSlotAllocations = {activeSpeaker: {}, receiverSelected: {}};\n\n LoggerProxy.logger.log(\n `RemoteMediaManager#constructor --> RemoteMediaManager created with config: ${JSON.stringify(\n this.config\n )}`\n );\n }\n\n /**\n * Checks if configuration is valid, throws an error if it's not\n */\n private checkConfigValidity() {\n if (!(this.config.video.initialLayoutId in this.config.video.layouts)) {\n throw new Error(\n `invalid config: initialLayoutId \"${this.config.video.initialLayoutId}\" doesn't match any of the layouts`\n );\n }\n\n // check if each layout is valid\n Object.values(this.config.video.layouts).forEach((layout) => {\n const groupIds = {};\n const paneIds = {};\n const groupPriorites = {};\n\n layout.activeSpeakerVideoPaneGroups?.forEach((group) => {\n if (groupIds[group.id]) {\n throw new Error(\n `invalid config: duplicate active speaker video pane group id: ${group.id}`\n );\n }\n groupIds[group.id] = true;\n\n if (groupPriorites[group.priority]) {\n throw new Error(\n `invalid config: multiple active speaker video pane groups have same priority: ${group.priority}`\n );\n }\n groupPriorites[group.priority] = true;\n });\n\n layout.memberVideoPanes?.forEach((pane) => {\n if (paneIds[pane.id]) {\n throw new Error(`invalid config: duplicate member video pane id: ${pane.id}`);\n }\n paneIds[pane.id] = true;\n });\n });\n }\n\n /**\n * Starts the RemoteMediaManager.\n *\n * @returns {Promise}\n */\n public async start() {\n if (this.started) {\n throw new Error('start() failure: already started');\n }\n this.started = true;\n\n await this.createAudioMedia();\n\n await this.createScreenShareReceiveSlots();\n this.createScreenShareAudioMedia();\n\n await this.preallocateVideoReceiveSlots();\n\n await this.setLayout(this.config.video.initialLayoutId);\n }\n\n /**\n * Releases all the used resources (like allocated receive slots). This function needs\n * to be called when we leave the meeting, etc.\n */\n public stop() {\n // invalidate all remoteMedia objects\n this.invalidateCurrentRemoteMedia({\n audio: true,\n video: true,\n screenShareAudio: true,\n screenShareVideo: true,\n commit: true,\n });\n\n // release all audio receive slots\n this.slots.audio.forEach((slot) => this.receiveSlotManager.releaseSlot(slot));\n this.slots.audio.length = 0;\n\n // release screen share slots\n this.slots.screenShare.audio.forEach((slot) => this.receiveSlotManager.releaseSlot(slot));\n this.slots.screenShare.audio.length = 0;\n if (this.slots.screenShare.video) {\n this.receiveSlotManager.releaseSlot(this.slots.screenShare.video);\n this.slots.screenShare.video = undefined;\n }\n\n // release video slots\n this.receiveSlotAllocations = {activeSpeaker: {}, receiverSelected: {}};\n\n this.slots.video.unused.push(...this.slots.video.activeSpeaker);\n this.slots.video.activeSpeaker.length = 0;\n\n this.slots.video.unused.push(...this.slots.video.receiverSelected);\n this.slots.video.receiverSelected.length = 0;\n\n this.releaseUnusedVideoSlots();\n\n this.currentLayout = undefined;\n this.currentLayoutId = undefined;\n this.started = false;\n }\n\n /**\n * Returns the total number of main video panes required for a given layout\n *\n * @param {VideoLayout} layout\n * @returns {number}\n */\n private getRequiredNumVideoSlotsForLayout(layout?: VideoLayout) {\n if (!layout) {\n return 0;\n }\n\n const activeSpeakerCount =\n layout.activeSpeakerVideoPaneGroups?.reduce(\n (sum, paneGroup) => sum + paneGroup.numPanes,\n 0\n ) || 0;\n\n const receiverSelectedCount = layout.memberVideoPanes?.length || 0;\n\n return activeSpeakerCount + receiverSelectedCount;\n }\n\n /**\n * Allocates the maximum number of panes that any of the configured layouts will require.\n * We do this at the beginning, because it's more efficient (much faster) then allocating receive slots\n * later, after the SDP exchange was done.\n */\n private async preallocateVideoReceiveSlots() {\n const maxNumVideoPanesRequired = Object.values(this.config.video.layouts).reduce(\n (maxValue, layout) => Math.max(maxValue, this.getRequiredNumVideoSlotsForLayout(layout)),\n 0\n );\n\n while (this.slots.video.unused.length < maxNumVideoPanesRequired) {\n // eslint-disable-next-line no-await-in-loop\n this.slots.video.unused.push(\n // eslint-disable-next-line no-await-in-loop\n await this.receiveSlotManager.allocateSlot(MediaType.VideoMain)\n );\n }\n }\n\n /**\n * Changes the layout (triggers Event.VideoLayoutChanged)\n *\n * @param {LayoutId} layoutId new layout id\n * @returns {Promise}\n */\n public async setLayout(layoutId: LayoutId) {\n if (!(layoutId in this.config.video.layouts)) {\n throw new Error(\n `invalid layoutId: \"${layoutId}\" doesn't match any of the configured layouts`\n );\n }\n if (!this.started) {\n throw new Error('setLayout() called before start()');\n }\n this.currentLayoutId = layoutId;\n this.currentLayout = cloneDeep(this.config.video.layouts[this.currentLayoutId]);\n\n await this.updateVideoReceiveSlots();\n this.updateVideoRemoteMediaObjects();\n this.updateScreenShareVideoRemoteMediaObject();\n this.emitVideoLayoutChangedEvent();\n }\n\n /**\n * Returns the currently selected layout id\n *\n * @returns {LayoutId}\n */\n public getLayoutId(): LayoutId | undefined {\n return this.currentLayoutId;\n }\n\n /**\n * Creates the audio slots\n */\n private async createAudioMedia() {\n // create the audio receive slots\n for (let i = 0; i < this.config.audio.numOfActiveSpeakerStreams; i += 1) {\n // eslint-disable-next-line no-await-in-loop\n const slot = await this.receiveSlotManager.allocateSlot(MediaType.AudioMain);\n\n this.slots.audio.push(slot);\n }\n\n // create a remote media group\n this.media.audio = new RemoteMediaGroup(\n this.mediaRequestManagers.audio,\n this.slots.audio,\n 255,\n true\n );\n\n this.emit(\n {file: 'multistream/remoteMediaManager', function: 'createAudioMedia'},\n Event.AudioCreated,\n this.media.audio\n );\n }\n\n /**\n * Creates receive slots required for receiving screen share audio and video\n */\n private async createScreenShareReceiveSlots() {\n // audio\n for (let i = 0; i < this.config.audio.numOfScreenShareStreams; i += 1) {\n // eslint-disable-next-line no-await-in-loop\n const slot = await this.receiveSlotManager.allocateSlot(MediaType.AudioSlides);\n\n this.slots.screenShare.audio.push(slot);\n }\n\n // video\n const isAnyLayoutContainingScreenShareVideo = Object.values(this.config.video.layouts).some(\n (layout) => !!layout.screenShareVideo\n );\n\n if (isAnyLayoutContainingScreenShareVideo) {\n this.slots.screenShare.video = await this.receiveSlotManager.allocateSlot(\n MediaType.VideoSlides\n );\n }\n }\n\n /**\n * Creates RemoteMedia objects for screen share\n */\n private createScreenShareAudioMedia() {\n if (this.slots.screenShare.audio.length > 0) {\n this.media.screenShare.audio = new RemoteMediaGroup(\n this.mediaRequestManagers.screenShareAudio,\n this.slots.screenShare.audio,\n 255,\n true\n );\n\n this.emit(\n {file: 'multistream/remoteMediaManager', function: 'createScreenShareAudioMedia'},\n Event.ScreenShareAudioCreated,\n this.media.screenShare.audio\n );\n }\n }\n\n /**\n * Goes over all receiver-selected slots and keeps only the ones that are required by a given layout,\n * the rest are all moved to the \"unused\" list\n */\n private trimReceiverSelectedSlots() {\n const requiredCsis = {};\n\n // fill requiredCsis with all the CSIs that the given layout requires\n this.currentLayout?.memberVideoPanes?.forEach((memberVideoPane) => {\n if (memberVideoPane.csi !== undefined) {\n requiredCsis[memberVideoPane.csi] = true;\n }\n });\n\n const isCsiNeededByCurrentLayout = (csi?: CSI): boolean => {\n if (csi === undefined) {\n return false;\n }\n\n return !!requiredCsis[csi];\n };\n\n // keep receiverSelected slots that match our new requiredCsis, move the rest of receiverSelected slots to unused\n const notNeededReceiverSelectedSlots = remove(\n this.slots.video.receiverSelected,\n (slot) => isCsiNeededByCurrentLayout(slot.csi) === false\n );\n\n this.slots.video.unused.push(...notNeededReceiverSelectedSlots);\n }\n\n /**\n * Releases all the \"unused\" video slots.\n */\n private releaseUnusedVideoSlots() {\n this.slots.video.unused.forEach((slot) => this.receiveSlotManager.releaseSlot(slot));\n this.slots.video.unused.length = 0;\n }\n\n /**\n * Allocates receive slots to all active speaker video panes\n * in the current selected layout.\n *\n * Allocation tries to keep the same order of the slots between the previous\n * layout and the new one. Sorting helps making sure that highest priority slots\n * go in the same order in the new layout.\n */\n private allocateSlotsToActiveSpeakerPaneGroups() {\n this.currentLayout?.activeSpeakerVideoPaneGroups\n // sorting in descending order based on group priority\n ?.sort((a, b) => (a.priority < b.priority ? 1 : -1))\n ?.forEach((group) => {\n this.receiveSlotAllocations.activeSpeaker[group.id] = {slots: []};\n\n for (let paneIndex = 0; paneIndex < group.numPanes; paneIndex += 1) {\n // allocate a slot from the \"unused\" list, by grabbing in same order (shift) as previous layout\n const freeSlot = this.slots.video.unused.shift();\n\n if (freeSlot) {\n this.slots.video.activeSpeaker.push(freeSlot);\n this.receiveSlotAllocations.activeSpeaker[group.id].slots.push(freeSlot);\n }\n }\n });\n }\n\n /**\n * Allocates receive slots to all receiver selected video panes\n * in the current selected layout\n */\n private allocateSlotsToReceiverSelectedVideoPaneGroups() {\n this.currentLayout?.memberVideoPanes?.forEach((memberPane) => {\n // check if there is existing slot for this csi\n const existingSlot = this.slots.video.receiverSelected.find(\n (slot) => slot.csi === memberPane.csi\n );\n\n const isExistingSlotAlreadyAllocated = Object.values(\n this.receiveSlotAllocations.receiverSelected\n ).includes(existingSlot);\n\n if (memberPane.csi !== undefined && existingSlot && !isExistingSlotAlreadyAllocated) {\n // found it, so use it\n this.receiveSlotAllocations.receiverSelected[memberPane.id] = existingSlot;\n } else {\n // allocate a slot from the \"unused\" list\n const freeSlot = this.slots.video.unused.pop();\n\n if (freeSlot) {\n this.slots.video.receiverSelected.push(freeSlot);\n this.receiveSlotAllocations.receiverSelected[memberPane.id] = freeSlot;\n }\n }\n });\n }\n\n /**\n * Ensures that we have enough slots for the current layout.\n */\n private async refillRequiredSlotsIfNeeded() {\n const requiredNumSlots = this.getRequiredNumVideoSlotsForLayout(this.currentLayout);\n const totalNumSlots =\n this.slots.video.unused.length +\n this.slots.video.activeSpeaker.length +\n this.slots.video.receiverSelected.length;\n\n if (totalNumSlots < requiredNumSlots) {\n let numSlotsToCreate = requiredNumSlots - totalNumSlots;\n\n while (numSlotsToCreate > 0) {\n // eslint-disable-next-line no-await-in-loop\n this.slots.video.unused.push(\n // eslint-disable-next-line no-await-in-loop\n await this.receiveSlotManager.allocateSlot(MediaType.VideoMain)\n );\n numSlotsToCreate -= 1;\n }\n }\n }\n\n /**\n * Move all active speaker slots to \"unused\"\n */\n private trimActiveSpeakerSlots() {\n this.slots.video.unused.push(...this.slots.video.activeSpeaker);\n this.slots.video.activeSpeaker.length = 0;\n }\n\n /**\n * Logs the state of the receive slots\n */\n private logReceieveSlots() {\n let logMessage = '';\n forEach(this.receiveSlotAllocations.activeSpeaker, (group, groupName) => {\n logMessage += `group: ${groupName}\\n${group.slots.map((slot) => slot.logString).join(' ')}`;\n });\n\n logMessage += '\\nreceiverSelected:\\n';\n forEach(this.receiveSlotAllocations.receiverSelected, (slot, key) => {\n logMessage += ` ${key}: ${slot.logString}\\n`;\n });\n\n LoggerProxy.logger.log(\n `RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=${this.slots.video.unused.length}, activeSpeaker=${this.slots.video.activeSpeaker.length}, receiverSelected=${this.slots.video.receiverSelected.length}\\n${logMessage}`\n );\n }\n\n /**\n * Makes sure we have the right number of receive slots created for the current layout\n * and allocates them to the right video panes / pane groups\n *\n * @returns {Promise}\n */\n private async updateVideoReceiveSlots() {\n // move all active speaker slots to \"unused\"\n this.trimActiveSpeakerSlots();\n\n // move all no longer needed receiver-selected slots to \"unused\"\n this.trimReceiverSelectedSlots();\n\n // ensure we have enough total slots for current layout\n await this.refillRequiredSlotsIfNeeded();\n\n // allocate the slots to the right panes / pane groups\n // reset allocations\n this.receiveSlotAllocations = {activeSpeaker: {}, receiverSelected: {}};\n // allocate active speaker\n this.allocateSlotsToActiveSpeakerPaneGroups();\n // allocate receiver selected\n this.allocateSlotsToReceiverSelectedVideoPaneGroups();\n\n this.logReceieveSlots();\n\n // If this is the initial layout, there may be some \"unused\" slots left because of the preallocation\n // done in this.preallocateVideoReceiveSlots(), so release them now\n this.releaseUnusedVideoSlots();\n }\n\n /**\n * Creates new RemoteMedia and RemoteMediaGroup objects for the current layout\n * and sends the media requests for all of them.\n */\n private updateVideoRemoteMediaObjects() {\n // invalidate all the previous remote media objects and cancel their media requests\n this.invalidateCurrentRemoteMedia({\n audio: false,\n video: true,\n screenShareAudio: false,\n screenShareVideo: false,\n commit: false,\n });\n\n // create new remoteMediaGroup objects\n this.media.video.activeSpeakerGroups = {};\n this.media.video.memberPanes = {};\n\n for (const [groupId, group] of Object.entries(this.receiveSlotAllocations.activeSpeaker)) {\n const paneGroupInCurrentLayout = this.currentLayout?.activeSpeakerVideoPaneGroups?.find(\n (groupInLayout) => groupInLayout.id === groupId\n );\n\n if (paneGroupInCurrentLayout) {\n const mediaGroup = new RemoteMediaGroup(\n this.mediaRequestManagers.video,\n group.slots,\n paneGroupInCurrentLayout.priority,\n false,\n {\n preferLiveVideo: this.config.video.preferLiveVideo,\n resolution: paneGroupInCurrentLayout.size,\n }\n );\n\n this.media.video.activeSpeakerGroups[groupId] = mediaGroup;\n } else {\n // this should never happen, because this.receiveSlotAllocations are created based on current layout configuration\n LoggerProxy.logger.warn(\n `a group id ${groupId} from this.receiveSlotAllocations.activeSpeaker cannot be found in the current layout configuration`\n );\n }\n }\n\n // create new remoteMedia objects\n for (const [paneId, slot] of Object.entries(this.receiveSlotAllocations.receiverSelected)) {\n const paneInCurrentLayout = this.currentLayout?.memberVideoPanes?.find(\n (paneInLayout) => paneInLayout.id === paneId\n );\n\n if (paneInCurrentLayout) {\n const remoteMedia = new RemoteMedia(slot, this.mediaRequestManagers.video, {\n resolution: paneInCurrentLayout.size,\n });\n\n if (paneInCurrentLayout.csi) {\n remoteMedia.sendMediaRequest(paneInCurrentLayout.csi, false);\n }\n\n this.media.video.memberPanes[paneId] = remoteMedia;\n } else {\n // this should never happen, because this.receiveSlotAllocations are created based on current layout configuration\n LoggerProxy.logger.warn(\n `a pane id ${paneId} from this.receiveSlotAllocations.receiverSelected cannot be found in the current layout configuration`\n );\n }\n }\n\n this.mediaRequestManagers.video.commit();\n }\n\n /**\n * Checks if current layout requires a screen share.\n * If it does, it creates new RemoteMediaGroup object for screen share\n * and sends the media requests for it.\n * If it doesn't, it makes sure we clean up any RemoteMediaGroup objects\n * created earlier for screen share (for previous layout).\n */\n private updateScreenShareVideoRemoteMediaObject() {\n this.invalidateCurrentRemoteMedia({\n audio: false,\n video: false,\n screenShareAudio: false,\n screenShareVideo: true,\n commit: false,\n });\n\n this.media.screenShare.video = undefined;\n\n if (this.currentLayout?.screenShareVideo) {\n // we create a group of 1, because for screen share we need to use the \"active speaker\" policy\n this.media.screenShare.video = new RemoteMediaGroup(\n this.mediaRequestManagers.screenShareVideo,\n [this.slots.screenShare.video],\n 255,\n false,\n {resolution: this.currentLayout.screenShareVideo.size}\n );\n }\n\n this.mediaRequestManagers.screenShareVideo.commit();\n }\n\n /**\n * Invalidates all remote media objects belonging to currently selected layout\n */\n private invalidateCurrentRemoteMedia(options: {\n audio: boolean;\n video: boolean;\n screenShareAudio: boolean;\n screenShareVideo: boolean;\n commit: boolean;\n }) {\n const {audio, video, screenShareAudio, screenShareVideo, commit} = options;\n\n if (audio && this.media.audio) {\n this.media.audio.stop(commit);\n }\n if (video) {\n Object.values(this.media.video.activeSpeakerGroups).forEach((remoteMediaGroup) => {\n remoteMediaGroup.stop(false);\n });\n Object.values(this.media.video.memberPanes).forEach((remoteMedia) => {\n remoteMedia.stop(false);\n });\n if (commit) {\n this.mediaRequestManagers.video.commit();\n }\n }\n\n if (screenShareAudio && this.media.screenShare.audio) {\n this.media.screenShare.audio.stop(commit);\n }\n if (screenShareVideo && this.media.screenShare.video) {\n this.media.screenShare.video.stop(commit);\n }\n }\n\n /** emits Event.VideoLayoutChanged */\n private emitVideoLayoutChangedEvent() {\n // todo: at this point the receive slots might still be showing a participant from previous layout, we should\n // wait for our media requests to be fulfilled, but there is no API for that right now (we could wait for source updates\n // but in some cases they might never come, or would need to always make sure to use a new set of receiver slots)\n // for now it's fine to have it like this, we will re-evaluate if it needs improving after more testing\n\n this.emit(\n {\n file: 'multistream/remoteMediaManager',\n function: 'emitVideoLayoutChangedEvent',\n },\n Event.VideoLayoutChanged,\n {\n layoutId: this.currentLayoutId,\n activeSpeakerVideoPanes: this.media.video.activeSpeakerGroups,\n memberVideoPanes: this.media.video.memberPanes,\n screenShareVideo: this.media.screenShare.video?.getRemoteMedia()[0],\n }\n );\n }\n\n /**\n * Sets a new CSI on a given remote media object\n *\n * @param {RemoteMedia} remoteMedia remote Media object to modify\n * @param {CSI} csi new CSI value, can be null if we want to stop receiving media\n */\n public setRemoteVideoCsi(remoteMedia: RemoteMedia, csi: CSI | null) {\n if (!Object.values(this.media.video.memberPanes).includes(remoteMedia)) {\n throw new Error('remoteMedia not found');\n }\n\n if (csi) {\n remoteMedia.sendMediaRequest(csi, true);\n } else {\n remoteMedia.cancelMediaRequest(true);\n }\n }\n\n /**\n * Adds a new member video pane to the currently selected layout.\n *\n * Changes to the layout are lost after a layout change.\n *\n * @param {MemberVideoPane} newPane\n * @returns {Promise<RemoteMedia>}\n */\n public async addMemberVideoPane(newPane: MemberVideoPane): Promise<RemoteMedia> {\n if (!this.currentLayout) {\n throw new Error('There is no current layout selected, call start() first');\n }\n\n if (!this.currentLayout?.memberVideoPanes) {\n this.currentLayout.memberVideoPanes = [];\n }\n\n if (newPane.id in this.currentLayout.memberVideoPanes) {\n throw new Error(\n `duplicate pane id ${newPane.id} - this pane already exists in current layout's memberVideoPanes`\n );\n }\n\n this.currentLayout.memberVideoPanes.push(newPane);\n\n const receiveSlot = await this.receiveSlotManager.allocateSlot(MediaType.VideoMain);\n\n this.slots.video.receiverSelected.push(receiveSlot);\n\n const remoteMedia = new RemoteMedia(receiveSlot, this.mediaRequestManagers.video, {\n resolution: newPane.size,\n });\n\n if (newPane.csi) {\n remoteMedia.sendMediaRequest(newPane.csi, true);\n }\n\n this.media.video.memberPanes[newPane.id] = remoteMedia;\n\n return remoteMedia;\n }\n\n /**\n * Removes a member video pane from the currently selected layout.\n *\n * Changes to the layout are lost after a layout change.\n *\n * @param {PaneId} paneId pane id of the pane to remove\n * @returns {Promise<void>}\n */\n public removeMemberVideoPane(paneId: PaneId): Promise<void> {\n if (!this.currentLayout) {\n return Promise.reject(new Error('There is no current layout selected, call start() first'));\n }\n\n if (!this.currentLayout.memberVideoPanes?.find((pane) => pane.id === paneId)) {\n // pane id doesn't exist, so nothing to do\n LoggerProxy.logger.log(\n `RemoteMediaManager#removeMemberVideoPane --> removeMemberVideoPane() called for a non-existent paneId: ${paneId} (pane not found in currentLayout.memberVideoPanes)`\n );\n\n return Promise.resolve();\n }\n\n if (!this.media.video.memberPanes[paneId]) {\n // pane id doesn't exist, so nothing to do\n LoggerProxy.logger.log(\n `RemoteMediaManager#removeMemberVideoPane --> removeMemberVideoPane() called for a non-existent paneId: ${paneId} (pane not found in this.media.video.memberPanes)`\n );\n\n return Promise.resolve();\n }\n\n const remoteMedia = this.media.video.memberPanes[paneId];\n\n const receiveSlot = remoteMedia.getUnderlyingReceiveSlot();\n\n if (receiveSlot) {\n this.receiveSlotManager.releaseSlot(receiveSlot);\n\n const index = this.slots.video.receiverSelected.indexOf(receiveSlot);\n\n if (index >= 0) {\n this.slots.video.receiverSelected.splice(index, 1);\n }\n }\n remoteMedia.stop();\n\n delete this.media.video.memberPanes[paneId];\n delete this.currentLayout.memberVideoPanes?.[paneId];\n\n return Promise.resolve();\n }\n\n /**\n * Pins an active speaker remote media object to the given CSI value. From that moment\n * onwards the remote media will only play audio/video from that specific CSI until\n * unpinActiveSpeakerVideoPane() is called or current layout is changed.\n *\n * @param {RemoteMedia} remoteMedia remote media object reference\n * @param {CSI} csi CSI value to pin to, if undefined, then current CSI value is used\n */\n public pinActiveSpeakerVideoPane(remoteMedia: RemoteMedia, csi?: CSI): void {\n const remoteMediaGroup = Object.values(this.media.video.activeSpeakerGroups).find((group) =>\n group.includes(remoteMedia, 'unpinned')\n );\n\n if (!remoteMediaGroup) {\n throw new Error(\n 'remoteMedia not found among the unpinned remote media from any active speaker group'\n );\n }\n\n remoteMediaGroup.pin(remoteMedia, csi);\n }\n\n /**\n * Unpins a remote media object from the fixed CSI value it was pinned to.\n *\n * @param {RemoteMedia} remoteMedia remote media object reference\n */\n public unpinActiveSpeakerVideoPane(remoteMedia: RemoteMedia) {\n const remoteMediaGroup = Object.values(this.media.video.activeSpeakerGroups).find((group) =>\n group.includes(remoteMedia, 'pinned')\n );\n\n if (!remoteMediaGroup) {\n throw new Error(\n 'remoteMedia not found among the pinned remote media from any active speaker group'\n );\n }\n\n remoteMediaGroup.unpin(remoteMedia);\n }\n\n /**\n * Returns true if a given remote media object belongs to an active speaker group and has been pinned.\n * Throws an error if the remote media object doesn't belong to any active speaker remote media group.\n *\n * @param {RemoteMedia} remoteMedia remote media object\n * @returns {boolean}\n */\n public isPinned(remoteMedia: RemoteMedia) {\n const remoteMediaGroup = Object.values(this.media.video.activeSpeakerGroups).find((group) =>\n group.includes(remoteMedia)\n );\n\n if (!remoteMediaGroup) {\n throw new Error(\n 'remoteMedia not found among any remote media (pinned or unpinned) from any active speaker group'\n );\n }\n\n return remoteMediaGroup.isPinned(remoteMedia);\n }\n}\n"],"mappings":"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"}
@@ -51,6 +51,10 @@ export declare class ReceiveSlot extends EventsScope {
51
51
  private setupEventListeners;
52
52
  /** Tries to find the member id for this receive slot if it hasn't got one */
53
53
  findMemberId(): void;
54
+ /**
55
+ * @returns {string} a log message used to identify the receive slot
56
+ */
57
+ get logString(): string;
54
58
  /**
55
59
  * The MediaStream object associated with this slot.
56
60
  *
@@ -182,6 +182,10 @@ export declare class RemoteMediaManager extends EventsScope {
182
182
  * Move all active speaker slots to "unused"
183
183
  */
184
184
  private trimActiveSpeakerSlots;
185
+ /**
186
+ * Logs the state of the receive slots
187
+ */
188
+ private logReceieveSlots;
185
189
  /**
186
190
  * Makes sure we have the right number of receive slots created for the current layout
187
191
  * and allocates them to the right video panes / pane groups
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.60",
3
+ "version": "3.0.0-beta.61",
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.60",
36
- "@webex/test-helper-chai": "3.0.0-beta.60",
37
- "@webex/test-helper-mocha": "3.0.0-beta.60",
38
- "@webex/test-helper-mock-webex": "3.0.0-beta.60",
39
- "@webex/test-helper-retry": "3.0.0-beta.60",
40
- "@webex/test-helper-test-users": "3.0.0-beta.60",
35
+ "@webex/plugin-meetings": "3.0.0-beta.61",
36
+ "@webex/test-helper-chai": "3.0.0-beta.61",
37
+ "@webex/test-helper-mocha": "3.0.0-beta.61",
38
+ "@webex/test-helper-mock-webex": "3.0.0-beta.61",
39
+ "@webex/test-helper-retry": "3.0.0-beta.61",
40
+ "@webex/test-helper-test-users": "3.0.0-beta.61",
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.60",
49
+ "@webex/common": "3.0.0-beta.61",
50
50
  "@webex/internal-media-core": "1.35.7",
51
- "@webex/internal-plugin-conversation": "3.0.0-beta.60",
52
- "@webex/internal-plugin-device": "3.0.0-beta.60",
53
- "@webex/internal-plugin-llm": "3.0.0-beta.60",
54
- "@webex/internal-plugin-mercury": "3.0.0-beta.60",
55
- "@webex/internal-plugin-metrics": "3.0.0-beta.60",
56
- "@webex/internal-plugin-support": "3.0.0-beta.60",
57
- "@webex/internal-plugin-user": "3.0.0-beta.60",
58
- "@webex/plugin-people": "3.0.0-beta.60",
59
- "@webex/plugin-rooms": "3.0.0-beta.60",
60
- "@webex/webex-core": "3.0.0-beta.60",
51
+ "@webex/internal-plugin-conversation": "3.0.0-beta.61",
52
+ "@webex/internal-plugin-device": "3.0.0-beta.61",
53
+ "@webex/internal-plugin-llm": "3.0.0-beta.61",
54
+ "@webex/internal-plugin-mercury": "3.0.0-beta.61",
55
+ "@webex/internal-plugin-metrics": "3.0.0-beta.61",
56
+ "@webex/internal-plugin-support": "3.0.0-beta.61",
57
+ "@webex/internal-plugin-user": "3.0.0-beta.61",
58
+ "@webex/plugin-people": "3.0.0-beta.61",
59
+ "@webex/plugin-rooms": "3.0.0-beta.61",
60
+ "@webex/webex-core": "3.0.0-beta.61",
61
61
  "ampersand-collection": "^2.0.2",
62
62
  "bowser": "^2.11.0",
63
63
  "btoa": "^1.2.1",
@@ -159,6 +159,13 @@ export class ReceiveSlot extends EventsScope {
159
159
  }
160
160
  }
161
161
 
162
+ /**
163
+ * @returns {string} a log message used to identify the receive slot
164
+ */
165
+ public get logString() {
166
+ return `ReceiveSlot - ${this.id}: ${JSON.stringify(this.mcReceiveSlot.id)}`;
167
+ }
168
+
162
169
  /**
163
170
  * The MediaStream object associated with this slot.
164
171
  *
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable valid-jsdoc */
2
- import {cloneDeep, remove} from 'lodash';
2
+ import {cloneDeep, forEach, remove} from 'lodash';
3
3
  import {EventMap} from 'typed-emitter';
4
4
  import {MediaType} from '@webex/internal-media-core';
5
5
 
@@ -689,6 +689,25 @@ export class RemoteMediaManager extends EventsScope {
689
689
  this.slots.video.activeSpeaker.length = 0;
690
690
  }
691
691
 
692
+ /**
693
+ * Logs the state of the receive slots
694
+ */
695
+ private logReceieveSlots() {
696
+ let logMessage = '';
697
+ forEach(this.receiveSlotAllocations.activeSpeaker, (group, groupName) => {
698
+ logMessage += `group: ${groupName}\n${group.slots.map((slot) => slot.logString).join(' ')}`;
699
+ });
700
+
701
+ logMessage += '\nreceiverSelected:\n';
702
+ forEach(this.receiveSlotAllocations.receiverSelected, (slot, key) => {
703
+ logMessage += ` ${key}: ${slot.logString}\n`;
704
+ });
705
+
706
+ LoggerProxy.logger.log(
707
+ `RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=${this.slots.video.unused.length}, activeSpeaker=${this.slots.video.activeSpeaker.length}, receiverSelected=${this.slots.video.receiverSelected.length}\n${logMessage}`
708
+ );
709
+ }
710
+
692
711
  /**
693
712
  * Makes sure we have the right number of receive slots created for the current layout
694
713
  * and allocates them to the right video panes / pane groups
@@ -713,9 +732,7 @@ export class RemoteMediaManager extends EventsScope {
713
732
  // allocate receiver selected
714
733
  this.allocateSlotsToReceiverSelectedVideoPaneGroups();
715
734
 
716
- LoggerProxy.logger.log(
717
- `RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=${this.slots.video.unused.length}, activeSpeaker=${this.slots.video.activeSpeaker.length}, receiverSelected=${this.slots.video.receiverSelected.length}`
718
- );
735
+ this.logReceieveSlots();
719
736
 
720
737
  // If this is the initial layout, there may be some "unused" slots left because of the preallocation
721
738
  // done in this.preallocateVideoReceiveSlots(), so release them now
@@ -9,6 +9,8 @@ import {assert} from '@webex/test-helper-chai';
9
9
  class FakeWcmeSlot extends EventEmitter {
10
10
  public stream;
11
11
 
12
+ public id = 'fake id';
13
+
12
14
  constructor(stream) {
13
15
  super();
14
16
  this.stream = stream;
@@ -28,6 +30,12 @@ describe('ReceiveSlot', () => {
28
30
  receiveSlot = new ReceiveSlot(MediaType.VideoMain, fakeWcmeSlot, findMemberIdCallbackStub);
29
31
  });
30
32
 
33
+ describe('logString', () => {
34
+ it('has a log string', () => {
35
+ assert.equal(receiveSlot.logString, `ReceiveSlot - ${receiveSlot.id}: "fake id"`);
36
+ });
37
+ })
38
+
31
39
  describe('forwards events from underlying wcme receive slot', () => {
32
40
  it('forwards SourceUpdate', () => {
33
41
  let eventEmitted = false;
@@ -15,6 +15,9 @@ import {cloneDeep} from 'lodash';
15
15
  import {MediaRequest} from '@webex/plugin-meetings/src/multistream/mediaRequestManager';
16
16
  import {CSI, ReceiveSlotId} from '@webex/plugin-meetings/src/multistream/receiveSlot';
17
17
  import testUtils from '../../../utils/testUtils';
18
+ import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
19
+ import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
20
+ import { expect } from 'chai';
18
21
 
19
22
  class FakeSlot extends EventEmitter {
20
23
  public mediaType: MediaType;
@@ -32,6 +35,10 @@ class FakeSlot extends EventEmitter {
32
35
  // Calling setMaxListeners() fixes the warning.
33
36
  this.setMaxListeners(50);
34
37
  }
38
+
39
+ public get logString() {
40
+ return this.id;
41
+ }
35
42
  }
36
43
 
37
44
  const DefaultTestConfiguration: Configuration = {
@@ -120,7 +127,23 @@ describe('RemoteMediaManager', () => {
120
127
  let fakeScreenShareAudioSlot;
121
128
  let fakeScreenShareVideoSlot;
122
129
 
130
+ const logger = {
131
+ log: sinon.fake(),
132
+ error: () => {},
133
+ warn: () => {},
134
+ trace: () => {},
135
+ debug: () => {},
136
+ };
137
+
138
+ afterEach(() => {
139
+ LoggerConfig.set({enable: false});
140
+ LoggerProxy.set();
141
+ });
142
+
123
143
  beforeEach(() => {
144
+ LoggerConfig.set({enable: true});
145
+ LoggerProxy.set(logger);
146
+
124
147
  fakeAudioSlot = new FakeSlot(MediaType.AudioMain, 'fake audio slot');
125
148
  fakeVideoSlot = new FakeSlot(MediaType.VideoMain, 'fake video slot');
126
149
  fakeScreenShareAudioSlot = new FakeSlot(
@@ -191,6 +214,7 @@ describe('RemoteMediaManager', () => {
191
214
  fakeMediaRequestManagers.video.commit.resetHistory();
192
215
  fakeMediaRequestManagers.screenShareVideo.commit.resetHistory();
193
216
  fakeMediaRequestManagers.screenShareAudio.commit.resetHistory();
217
+ logger.log.resetHistory();
194
218
  };
195
219
 
196
220
  describe('start', () => {
@@ -671,6 +695,50 @@ describe('RemoteMediaManager', () => {
671
695
  assert.alwaysCalledWith(fakeReceiveSlotManager.allocateSlot, MediaType.VideoMain);
672
696
  });
673
697
 
698
+ it('logs layout changes - receiver selected', async () => {
699
+ const config = cloneDeep(DefaultTestConfiguration);
700
+
701
+ remoteMediaManager = new RemoteMediaManager(
702
+ fakeReceiveSlotManager,
703
+ fakeMediaRequestManagers,
704
+ config
705
+ );
706
+
707
+ await remoteMediaManager.start();
708
+
709
+ resetHistory();
710
+
711
+ await remoteMediaManager.setLayout('Stage');
712
+
713
+ assert.calledWith(
714
+ logger.log,
715
+ 'RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=0, activeSpeaker=6, receiverSelected=4\ngroup: thumbnails\nfake video slot fake video slot fake video slot fake video slot fake video slot fake video slot\nreceiverSelected:\n stage-1: fake video slot\n stage-2: fake video slot\n stage-3: fake video slot\n stage-4: fake video slot\n'
716
+ );
717
+ });
718
+
719
+ it('logs layout changes - active speaker', async () => {
720
+ const config = cloneDeep(DefaultTestConfiguration);
721
+ config.video.initialLayoutId = 'OnePlusFive'
722
+
723
+ remoteMediaManager = new RemoteMediaManager(
724
+ fakeReceiveSlotManager,
725
+ fakeMediaRequestManagers,
726
+ config
727
+ );
728
+
729
+ await remoteMediaManager.start();
730
+
731
+ resetHistory();
732
+
733
+ await remoteMediaManager.setLayout('AllEqual');
734
+
735
+ assert.calledWith(
736
+ logger.log,
737
+ 'RemoteMediaManager#updateVideoReceiveSlots --> receive slots updated: unused=0, activeSpeaker=9, receiverSelected=0\ngroup: main\nfake video slot fake video slot fake video slot fake video slot fake video slot fake video slot fake video slot fake video slot fake video slot\nreceiverSelected:\n'
738
+ );
739
+ });
740
+
741
+
674
742
  it('releases slots when switching to layout that requires less active speaker slots', async () => {
675
743
  // start with "AllEqual" layout that needs just 9 video slots
676
744
  const config = cloneDeep(DefaultTestConfiguration);