@webex/plugin-meetings 3.0.0-beta.5 → 3.0.0-beta.7

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.
@@ -38,7 +38,8 @@ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflec
38
38
  function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !_Reflect$construct) return false; if (_Reflect$construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
39
39
 
40
40
  var RemoteMediaEvents = {
41
- SourceUpdate: _receiveSlot.ReceiveSlotEvents.SourceUpdate
41
+ SourceUpdate: _receiveSlot.ReceiveSlotEvents.SourceUpdate,
42
+ Stopped: 'stopped'
42
43
  };
43
44
  exports.RemoteMediaEvents = RemoteMediaEvents;
44
45
 
@@ -146,6 +147,10 @@ var RemoteMedia = /*#__PURE__*/function (_EventsScope) {
146
147
  this.cancelMediaRequest(commit);
147
148
  (_this$receiveSlot = this.receiveSlot) === null || _this$receiveSlot === void 0 ? void 0 : _this$receiveSlot.removeAllListeners();
148
149
  this.receiveSlot = undefined;
150
+ this.emit({
151
+ file: 'multistream/remoteMedia',
152
+ function: 'stop'
153
+ }, RemoteMediaEvents.Stopped, {});
149
154
  }
150
155
  /**
151
156
  * Sends a new media request. This method can only be used for receiver-selected policy,
@@ -203,7 +208,7 @@ var RemoteMedia = /*#__PURE__*/function (_EventsScope) {
203
208
 
204
209
  if (this.receiveSlot) {
205
210
  var scope = {
206
- file: 'meeting/remoteMedia',
211
+ file: 'multistream/remoteMedia',
207
212
  function: 'setupEventListeners'
208
213
  };
209
214
  this.receiveSlot.on(_receiveSlot.ReceiveSlotEvents.SourceUpdate, function (data) {
@@ -1 +1 @@
1
- {"version":3,"names":["RemoteMediaEvents","SourceUpdate","ReceiveSlotEvents","getMaxFs","paneSize","maxFs","LoggerProxy","logger","warn","remoteMediaCounter","RemoteMedia","receiveSlot","mediaRequestManager","options","setupEventListeners","id","commit","cancelMediaRequest","removeAllListeners","undefined","csi","mediaRequestId","Error","addRequest","policyInfo","policy","receiveSlots","codecInfo","resolution","codec","cancelRequest","scope","file","function","on","data","emit","mediaType","memberId","sourceState","stream","EventsScope"],"sources":["remoteMedia.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport EventsScope from '../common/events/events-scope';\n\nimport {MediaRequestId, MediaRequestManager} from './mediaRequestManager';\nimport {CSI, ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';\n\nexport const RemoteMediaEvents = {\n SourceUpdate: ReceiveSlotEvents.SourceUpdate,\n};\n\nexport type RemoteVideoResolution =\n | 'thumbnail' // the smallest possible resolution, 90p or less\n | 'very small' // 180p or less\n | 'small' // 360p or less\n | 'medium' // 720p or less\n | 'large' // 1080p or less\n | 'best'; // highest possible resolution\n\n/**\n * Converts pane size into h264 maxFs\n * @param {PaneSize} paneSize\n * @returns {number}\n */\nexport function getMaxFs(paneSize: RemoteVideoResolution): number {\n let maxFs;\n\n switch (paneSize) {\n case 'thumbnail':\n maxFs = 60;\n break;\n case 'very small':\n maxFs = 240;\n break;\n case 'small':\n maxFs = 920;\n break;\n case 'medium':\n maxFs = 3600;\n break;\n case 'large':\n maxFs = 8192;\n break;\n case 'best':\n maxFs = 8192; // for now 'best' is 1080p, so same as 'large'\n break;\n default:\n LoggerProxy.logger.warn(\n `RemoteMedia#getMaxFs --> unsupported paneSize: ${paneSize}, using \"medium\" instead`\n );\n maxFs = 3600;\n }\n\n return maxFs;\n}\n\ntype Options = {\n resolution?: RemoteVideoResolution; // applies only to groups of type MC.MediaType.VideoMain and MC.MediaType.VideoSlides\n};\n\nexport type RemoteMediaId = string;\n\nlet remoteMediaCounter = 0;\n\n/**\n * Class representing a remote audio/video stream.\n *\n * Internally it is associated with a specific receive slot\n * and a media request for it.\n */\nexport class RemoteMedia extends EventsScope {\n private receiveSlot?: ReceiveSlot;\n\n private readonly mediaRequestManager: MediaRequestManager;\n\n private readonly options: Options;\n\n private mediaRequestId?: MediaRequestId;\n\n public readonly id: RemoteMediaId;\n\n /**\n * Constructs RemoteMedia instance\n *\n * @param receiveSlot\n * @param mediaRequestManager\n * @param options\n */\n constructor(\n receiveSlot: ReceiveSlot,\n mediaRequestManager: MediaRequestManager,\n options?: Options\n ) {\n super();\n remoteMediaCounter += 1;\n this.receiveSlot = receiveSlot;\n this.mediaRequestManager = mediaRequestManager;\n this.options = options || {};\n this.setupEventListeners();\n this.id = `RM${remoteMediaCounter}-${this.receiveSlot.id}`;\n }\n\n /**\n * Invalidates the remote media by clearing the reference to a receive slot and\n * cancelling the media request.\n * After this call the remote media is unusable.\n *\n * @param {boolean} commit - whether to commit the cancellation of the media request\n * @internal\n */\n public stop(commit: boolean = true) {\n this.cancelMediaRequest(commit);\n this.receiveSlot?.removeAllListeners();\n this.receiveSlot = undefined;\n }\n\n /**\n * Sends a new media request. This method can only be used for receiver-selected policy,\n * because only in that policy we have a 1-1 relationship between RemoteMedia and MediaRequest\n * and the request id is then stored in this RemoteMedia instance.\n * For active-speaker policy, the same request is shared among many RemoteMedia instances,\n * so it's managed through RemoteMediaGroup\n *\n * @internal\n */\n public sendMediaRequest(csi: CSI, commit: boolean) {\n if (this.mediaRequestId) {\n this.cancelMediaRequest(false);\n }\n\n if (!this.receiveSlot) {\n throw new Error('sendMediaRequest() called on an invalidated RemoteMedia instance');\n }\n\n this.mediaRequestId = this.mediaRequestManager.addRequest(\n {\n policyInfo: {\n policy: 'receiver-selected',\n csi,\n },\n receiveSlots: [this.receiveSlot],\n codecInfo: this.options.resolution && {\n codec: 'h264',\n maxFs: getMaxFs(this.options.resolution),\n },\n },\n commit\n );\n }\n\n /**\n * @internal\n */\n public cancelMediaRequest(commit: boolean) {\n if (this.mediaRequestId) {\n this.mediaRequestManager.cancelRequest(this.mediaRequestId, commit);\n this.mediaRequestId = undefined;\n }\n }\n\n /**\n * registers event listeners on the receive slot and forwards all the events\n */\n private setupEventListeners() {\n if (this.receiveSlot) {\n const scope = {\n file: 'meeting/remoteMedia',\n function: 'setupEventListeners',\n };\n\n this.receiveSlot.on(ReceiveSlotEvents.SourceUpdate, (data) => {\n this.emit(scope, RemoteMediaEvents.SourceUpdate, data);\n });\n }\n }\n\n /**\n * Getter for mediaType\n */\n public get mediaType() {\n return this.receiveSlot?.mediaType;\n }\n\n /**\n * Getter for memberId\n */\n public get memberId() {\n return this.receiveSlot?.memberId;\n }\n\n /**\n * Getter for csi\n */\n public get csi() {\n return this.receiveSlot?.csi;\n }\n\n /**\n * Getter for source state\n */\n public get sourceState() {\n return this.receiveSlot?.sourceState;\n }\n\n /**\n * Getter for remote media stream\n */\n public get stream() {\n return this.receiveSlot?.stream;\n }\n\n /**\n * @internal\n * @returns {ReceiveSlot}\n */\n public getUnderlyingReceiveSlot() {\n return this.receiveSlot;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["RemoteMediaEvents","SourceUpdate","ReceiveSlotEvents","Stopped","getMaxFs","paneSize","maxFs","LoggerProxy","logger","warn","remoteMediaCounter","RemoteMedia","receiveSlot","mediaRequestManager","options","setupEventListeners","id","commit","cancelMediaRequest","removeAllListeners","undefined","emit","file","function","csi","mediaRequestId","Error","addRequest","policyInfo","policy","receiveSlots","codecInfo","resolution","codec","cancelRequest","scope","on","data","mediaType","memberId","sourceState","stream","EventsScope"],"sources":["remoteMedia.ts"],"sourcesContent":["/* eslint-disable valid-jsdoc */\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport EventsScope from '../common/events/events-scope';\n\nimport {MediaRequestId, MediaRequestManager} from './mediaRequestManager';\nimport {CSI, ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';\n\nexport const RemoteMediaEvents = {\n SourceUpdate: ReceiveSlotEvents.SourceUpdate,\n Stopped: 'stopped',\n};\n\nexport type RemoteVideoResolution =\n | 'thumbnail' // the smallest possible resolution, 90p or less\n | 'very small' // 180p or less\n | 'small' // 360p or less\n | 'medium' // 720p or less\n | 'large' // 1080p or less\n | 'best'; // highest possible resolution\n\n/**\n * Converts pane size into h264 maxFs\n * @param {PaneSize} paneSize\n * @returns {number}\n */\nexport function getMaxFs(paneSize: RemoteVideoResolution): number {\n let maxFs;\n\n switch (paneSize) {\n case 'thumbnail':\n maxFs = 60;\n break;\n case 'very small':\n maxFs = 240;\n break;\n case 'small':\n maxFs = 920;\n break;\n case 'medium':\n maxFs = 3600;\n break;\n case 'large':\n maxFs = 8192;\n break;\n case 'best':\n maxFs = 8192; // for now 'best' is 1080p, so same as 'large'\n break;\n default:\n LoggerProxy.logger.warn(\n `RemoteMedia#getMaxFs --> unsupported paneSize: ${paneSize}, using \"medium\" instead`\n );\n maxFs = 3600;\n }\n\n return maxFs;\n}\n\ntype Options = {\n resolution?: RemoteVideoResolution; // applies only to groups of type MC.MediaType.VideoMain and MC.MediaType.VideoSlides\n};\n\nexport type RemoteMediaId = string;\n\nlet remoteMediaCounter = 0;\n\n/**\n * Class representing a remote audio/video stream.\n *\n * Internally it is associated with a specific receive slot\n * and a media request for it.\n */\nexport class RemoteMedia extends EventsScope {\n private receiveSlot?: ReceiveSlot;\n\n private readonly mediaRequestManager: MediaRequestManager;\n\n private readonly options: Options;\n\n private mediaRequestId?: MediaRequestId;\n\n public readonly id: RemoteMediaId;\n\n /**\n * Constructs RemoteMedia instance\n *\n * @param receiveSlot\n * @param mediaRequestManager\n * @param options\n */\n constructor(\n receiveSlot: ReceiveSlot,\n mediaRequestManager: MediaRequestManager,\n options?: Options\n ) {\n super();\n remoteMediaCounter += 1;\n this.receiveSlot = receiveSlot;\n this.mediaRequestManager = mediaRequestManager;\n this.options = options || {};\n this.setupEventListeners();\n this.id = `RM${remoteMediaCounter}-${this.receiveSlot.id}`;\n }\n\n /**\n * Invalidates the remote media by clearing the reference to a receive slot and\n * cancelling the media request.\n * After this call the remote media is unusable.\n *\n * @param {boolean} commit - whether to commit the cancellation of the media request\n * @internal\n */\n public stop(commit: boolean = true) {\n this.cancelMediaRequest(commit);\n this.receiveSlot?.removeAllListeners();\n this.receiveSlot = undefined;\n this.emit(\n {\n file: 'multistream/remoteMedia',\n function: 'stop',\n },\n RemoteMediaEvents.Stopped,\n {}\n );\n }\n\n /**\n * Sends a new media request. This method can only be used for receiver-selected policy,\n * because only in that policy we have a 1-1 relationship between RemoteMedia and MediaRequest\n * and the request id is then stored in this RemoteMedia instance.\n * For active-speaker policy, the same request is shared among many RemoteMedia instances,\n * so it's managed through RemoteMediaGroup\n *\n * @internal\n */\n public sendMediaRequest(csi: CSI, commit: boolean) {\n if (this.mediaRequestId) {\n this.cancelMediaRequest(false);\n }\n\n if (!this.receiveSlot) {\n throw new Error('sendMediaRequest() called on an invalidated RemoteMedia instance');\n }\n\n this.mediaRequestId = this.mediaRequestManager.addRequest(\n {\n policyInfo: {\n policy: 'receiver-selected',\n csi,\n },\n receiveSlots: [this.receiveSlot],\n codecInfo: this.options.resolution && {\n codec: 'h264',\n maxFs: getMaxFs(this.options.resolution),\n },\n },\n commit\n );\n }\n\n /**\n * @internal\n */\n public cancelMediaRequest(commit: boolean) {\n if (this.mediaRequestId) {\n this.mediaRequestManager.cancelRequest(this.mediaRequestId, commit);\n this.mediaRequestId = undefined;\n }\n }\n\n /**\n * registers event listeners on the receive slot and forwards all the events\n */\n private setupEventListeners() {\n if (this.receiveSlot) {\n const scope = {\n file: 'multistream/remoteMedia',\n function: 'setupEventListeners',\n };\n\n this.receiveSlot.on(ReceiveSlotEvents.SourceUpdate, (data) => {\n this.emit(scope, RemoteMediaEvents.SourceUpdate, data);\n });\n }\n }\n\n /**\n * Getter for mediaType\n */\n public get mediaType() {\n return this.receiveSlot?.mediaType;\n }\n\n /**\n * Getter for memberId\n */\n public get memberId() {\n return this.receiveSlot?.memberId;\n }\n\n /**\n * Getter for csi\n */\n public get csi() {\n return this.receiveSlot?.csi;\n }\n\n /**\n * Getter for source state\n */\n public get sourceState() {\n return this.receiveSlot?.sourceState;\n }\n\n /**\n * Getter for remote media stream\n */\n public get stream() {\n return this.receiveSlot?.stream;\n }\n\n /**\n * @internal\n * @returns {ReceiveSlot}\n */\n public getUnderlyingReceiveSlot() {\n return this.receiveSlot;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.5",
3
+ "version": "3.0.0-beta.7",
4
4
  "description": "",
5
5
  "license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
6
6
  "contributors": [
@@ -28,12 +28,12 @@
28
28
  ]
29
29
  },
30
30
  "devDependencies": {
31
- "@webex/plugin-meetings": "3.0.0-beta.5",
32
- "@webex/test-helper-chai": "3.0.0-beta.5",
33
- "@webex/test-helper-mocha": "3.0.0-beta.5",
34
- "@webex/test-helper-mock-webex": "3.0.0-beta.5",
35
- "@webex/test-helper-retry": "3.0.0-beta.5",
36
- "@webex/test-helper-test-users": "3.0.0-beta.5",
31
+ "@webex/plugin-meetings": "3.0.0-beta.7",
32
+ "@webex/test-helper-chai": "3.0.0-beta.7",
33
+ "@webex/test-helper-mocha": "3.0.0-beta.7",
34
+ "@webex/test-helper-mock-webex": "3.0.0-beta.7",
35
+ "@webex/test-helper-retry": "3.0.0-beta.7",
36
+ "@webex/test-helper-test-users": "3.0.0-beta.7",
37
37
  "chai": "^4.3.4",
38
38
  "chai-as-promised": "^7.1.1",
39
39
  "jsdom-global": "3.0.2",
@@ -41,18 +41,18 @@
41
41
  "typed-emitter": "^2.1.0"
42
42
  },
43
43
  "dependencies": {
44
- "@webex/common": "3.0.0-beta.5",
44
+ "@webex/common": "3.0.0-beta.7",
45
45
  "@webex/internal-media-core": "^0.0.17-beta",
46
- "@webex/internal-plugin-conversation": "3.0.0-beta.5",
47
- "@webex/internal-plugin-device": "3.0.0-beta.5",
48
- "@webex/internal-plugin-mercury": "3.0.0-beta.5",
49
- "@webex/internal-plugin-metrics": "3.0.0-beta.5",
50
- "@webex/internal-plugin-support": "3.0.0-beta.5",
51
- "@webex/internal-plugin-user": "3.0.0-beta.5",
52
- "@webex/plugin-people": "3.0.0-beta.5",
53
- "@webex/plugin-rooms": "3.0.0-beta.5",
46
+ "@webex/internal-plugin-conversation": "3.0.0-beta.7",
47
+ "@webex/internal-plugin-device": "3.0.0-beta.7",
48
+ "@webex/internal-plugin-mercury": "3.0.0-beta.7",
49
+ "@webex/internal-plugin-metrics": "3.0.0-beta.7",
50
+ "@webex/internal-plugin-support": "3.0.0-beta.7",
51
+ "@webex/internal-plugin-user": "3.0.0-beta.7",
52
+ "@webex/plugin-people": "3.0.0-beta.7",
53
+ "@webex/plugin-rooms": "3.0.0-beta.7",
54
54
  "@webex/ts-sdp": "^1.0.1",
55
- "@webex/webex-core": "3.0.0-beta.5",
55
+ "@webex/webex-core": "3.0.0-beta.7",
56
56
  "bowser": "^2.11.0",
57
57
  "btoa": "^1.2.1",
58
58
  "dotenv": "^4.0.0",
@@ -7,6 +7,7 @@ import {CSI, ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';
7
7
 
8
8
  export const RemoteMediaEvents = {
9
9
  SourceUpdate: ReceiveSlotEvents.SourceUpdate,
10
+ Stopped: 'stopped',
10
11
  };
11
12
 
12
13
  export type RemoteVideoResolution =
@@ -112,6 +113,14 @@ export class RemoteMedia extends EventsScope {
112
113
  this.cancelMediaRequest(commit);
113
114
  this.receiveSlot?.removeAllListeners();
114
115
  this.receiveSlot = undefined;
116
+ this.emit(
117
+ {
118
+ file: 'multistream/remoteMedia',
119
+ function: 'stop',
120
+ },
121
+ RemoteMediaEvents.Stopped,
122
+ {}
123
+ );
115
124
  }
116
125
 
117
126
  /**
@@ -164,7 +173,7 @@ export class RemoteMedia extends EventsScope {
164
173
  private setupEventListeners() {
165
174
  if (this.receiveSlot) {
166
175
  const scope = {
167
- file: 'meeting/remoteMedia',
176
+ file: 'multistream/remoteMedia',
168
177
  function: 'setupEventListeners',
169
178
  };
170
179
 
@@ -184,8 +184,16 @@ describe('RemoteMedia', () => {
184
184
  it('cancels media request, unsets the receive slot and removes all the listeners from it', () => {
185
185
  const cancelMediaRequestSpy = sinon.spy(remoteMedia, 'cancelMediaRequest');
186
186
 
187
+ let stoppedListenerCalled = false;
188
+
189
+ remoteMedia.on(RemoteMediaEvents.Stopped, () => {
190
+ stoppedListenerCalled = true;
191
+ });
192
+
187
193
  remoteMedia.stop(true);
188
194
 
195
+ assert.isTrue(stoppedListenerCalled);
196
+
189
197
  assert.calledOnce(cancelMediaRequestSpy);
190
198
  assert.calledWith(cancelMediaRequestSpy, true);
191
199
 
@@ -542,6 +542,64 @@ describe('RemoteMediaManager', () => {
542
542
  });
543
543
  });
544
544
 
545
+ it('stops all current video remoteMedia instances when switching to new layout', async () => {
546
+ const audioStopStubs = [];
547
+ const videoStopStubs = [];
548
+
549
+ const config = cloneDeep(DefaultTestConfiguration);
550
+
551
+ // start with the stage layout because it has both active speaker and receiver selected panes
552
+ config.video.initialLayoutId = 'Stage';
553
+
554
+ remoteMediaManager = new RemoteMediaManager(
555
+ fakeReceiveSlotManager,
556
+ fakeMediaRequestManagers,
557
+ config
558
+ );
559
+
560
+ // mock all stop() methods for all remote audio objects we get with AudioCreated event
561
+ remoteMediaManager.on(Event.AudioCreated, (audio: RemoteMediaGroup) => {
562
+ audio
563
+ .getRemoteMedia()
564
+ .forEach((remoteAudio) => audioStopStubs.push(sinon.stub(remoteAudio, 'stop')));
565
+ });
566
+
567
+ // mock all stop() methods for all remote video objects we get with VideoLayoutChanged event
568
+ remoteMediaManager.on(Event.VideoLayoutChanged, (layoutInfo: VideoLayoutChangedEventData) => {
569
+ Object.values(layoutInfo.activeSpeakerVideoPanes).forEach((group) =>
570
+ group
571
+ .getRemoteMedia()
572
+ .forEach((remoteMedia) => videoStopStubs.push(sinon.stub(remoteMedia, 'stop')))
573
+ );
574
+
575
+ Object.values(layoutInfo.memberVideoPanes).forEach((pane) => {
576
+ videoStopStubs.push(sinon.stub(pane, 'stop'));
577
+ });
578
+ });
579
+
580
+ await remoteMediaManager.start();
581
+
582
+ // sanity check that we've got all our stop() mocks setup correctly
583
+ assert.strictEqual(audioStopStubs.length, 3);
584
+ assert.strictEqual(videoStopStubs.length, 10); // 10 = 6 thumbnail panes + 4 stage panes
585
+
586
+ // next, we'll change the layout, we don't care about the new video panes from the new layout, so unregister the event listeners
587
+ remoteMediaManager.removeAllListeners();
588
+
589
+ await remoteMediaManager.setLayout('AllEqual');
590
+
591
+ // check that NONE of the audio RemoteMedia instances were stopped
592
+ audioStopStubs.forEach((audioStopStub) => {
593
+ assert.notCalled(audioStopStub);
594
+ });
595
+
596
+ // check that ALL of the video RemoteMedia instances were stopped
597
+ videoStopStubs.forEach((videoStopStub) => {
598
+ assert.calledOnce(videoStopStub);
599
+ assert.calledWith(videoStopStub, false);
600
+ });
601
+ });
602
+
545
603
  describe('switching between different receiver selected layouts', () => {
546
604
  let fakeSlots: {[key: ReceiveSlotId]: FakeSlot};
547
605
  let slotCounter: number;