@webex/plugin-meetings 3.0.0-beta.262 → 3.0.0-beta.264

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.
@@ -2254,6 +2254,7 @@ export default class Meeting extends StatelessWebexPlugin {
2254
2254
  if (
2255
2255
  contentShare.beneficiaryId === previousContentShare?.beneficiaryId &&
2256
2256
  contentShare.disposition === previousContentShare?.disposition &&
2257
+ contentShare.deviceUrlSharing === previousContentShare.deviceUrlSharing &&
2257
2258
  whiteboardShare.beneficiaryId === previousWhiteboardShare?.beneficiaryId &&
2258
2259
  whiteboardShare.disposition === previousWhiteboardShare?.disposition &&
2259
2260
  whiteboardShare.resourceUrl === previousWhiteboardShare?.resourceUrl
@@ -2276,11 +2277,21 @@ export default class Meeting extends StatelessWebexPlugin {
2276
2277
  // LOCAL - check if we started sharing content
2277
2278
  else if (
2278
2279
  this.selfId === contentShare.beneficiaryId &&
2279
- contentShare.disposition === FLOOR_ACTION.GRANTED
2280
+ contentShare.disposition === FLOOR_ACTION.GRANTED &&
2281
+ contentShare.deviceUrlSharing === this.deviceUrl
2280
2282
  ) {
2281
2283
  // CONTENT - sharing content local
2282
2284
  newShareStatus = SHARE_STATUS.LOCAL_SHARE_ACTIVE;
2283
2285
  }
2286
+ // SAME USER REMOTE - check if same user started sharing content from another client
2287
+ else if (
2288
+ this.selfId === contentShare.beneficiaryId &&
2289
+ contentShare.disposition === FLOOR_ACTION.GRANTED &&
2290
+ contentShare.deviceUrlSharing !== this.deviceUrl
2291
+ ) {
2292
+ // CONTENT - same user sharing content remote
2293
+ newShareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
2294
+ }
2284
2295
  // If we did not hit the cases above, no one is sharng content, so we check if we are sharing whiteboard
2285
2296
  // There is no concept of local/remote share for whiteboard
2286
2297
  // It does not matter who requested to share the whiteboard, everyone gets the same view
@@ -5817,12 +5828,16 @@ export default class Meeting extends StatelessWebexPlugin {
5817
5828
  return Promise.resolve();
5818
5829
  })
5819
5830
  .then(() => this.mediaProperties.getCurrentConnectionType())
5820
- .then((connectionType) => {
5831
+ .then(async (connectionType) => {
5832
+ // @ts-ignore
5833
+ const reachabilityStats = await this.webex.meetings.reachability.getReachabilityMetrics();
5834
+
5821
5835
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS, {
5822
5836
  correlation_id: this.correlationId,
5823
5837
  locus_id: this.locusUrl.split('/').pop(),
5824
5838
  connectionType,
5825
5839
  isMultistream: this.isMultistream,
5840
+ ...reachabilityStats,
5826
5841
  });
5827
5842
  // @ts-ignore
5828
5843
  this.webex.internal.newMetrics.submitClientEvent({
@@ -5838,9 +5853,12 @@ export default class Meeting extends StatelessWebexPlugin {
5838
5853
  // We can log ReceiveSlot SSRCs only after the SDP exchange, so doing it here:
5839
5854
  this.remoteMediaManager?.logAllReceiveSlots();
5840
5855
  })
5841
- .catch((error) => {
5856
+ .catch(async (error) => {
5842
5857
  LoggerProxy.logger.error(`${LOG_HEADER} failed to establish media connection: `, error);
5843
5858
 
5859
+ // @ts-ignore
5860
+ const reachabilityMetrics = await this.webex.meetings.reachability.getReachabilityMetrics();
5861
+
5844
5862
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
5845
5863
  correlation_id: this.correlationId,
5846
5864
  locus_id: this.locusUrl.split('/').pop(),
@@ -5865,38 +5883,37 @@ export default class Meeting extends StatelessWebexPlugin {
5865
5883
  ?.iceConnectionState ||
5866
5884
  this.mediaProperties.webrtcMediaConnection?.mediaConnection?.pc?.iceConnectionState ||
5867
5885
  'unknown',
5886
+ ...reachabilityMetrics,
5868
5887
  });
5869
5888
 
5870
5889
  // Clean up stats analyzer, peer connection, and turn off listeners
5871
- const stopStatsAnalyzer = this.statsAnalyzer
5872
- ? this.statsAnalyzer.stopAnalyzer()
5873
- : Promise.resolve();
5890
+ if (this.statsAnalyzer) {
5891
+ await this.statsAnalyzer.stopAnalyzer();
5892
+ }
5874
5893
 
5875
- return stopStatsAnalyzer.then(() => {
5876
- this.statsAnalyzer = null;
5894
+ this.statsAnalyzer = null;
5877
5895
 
5878
- if (this.mediaProperties.webrtcMediaConnection) {
5879
- this.closePeerConnections();
5880
- this.unsetPeerConnections();
5881
- }
5896
+ if (this.mediaProperties.webrtcMediaConnection) {
5897
+ this.closePeerConnections();
5898
+ this.unsetPeerConnections();
5899
+ }
5882
5900
 
5883
- // Upload logs on error while adding media
5884
- Trigger.trigger(
5885
- this,
5886
- {
5887
- file: 'meeting/index',
5888
- function: 'addMedia',
5889
- },
5890
- EVENTS.REQUEST_UPLOAD_LOGS,
5891
- this
5892
- );
5901
+ // Upload logs on error while adding media
5902
+ Trigger.trigger(
5903
+ this,
5904
+ {
5905
+ file: 'meeting/index',
5906
+ function: 'addMedia',
5907
+ },
5908
+ EVENTS.REQUEST_UPLOAD_LOGS,
5909
+ this
5910
+ );
5893
5911
 
5894
- if (error instanceof Errors.SdpError) {
5895
- this.leave({reason: MEETING_REMOVED_REASON.MEETING_CONNECTION_FAILED});
5896
- }
5912
+ if (error instanceof Errors.SdpError) {
5913
+ this.leave({reason: MEETING_REMOVED_REASON.MEETING_CONNECTION_FAILED});
5914
+ }
5897
5915
 
5898
- throw error;
5899
- });
5916
+ throw error;
5900
5917
  });
5901
5918
  }
5902
5919
 
@@ -16,9 +16,20 @@ import ReachabilityRequest from './request';
16
16
  const DEFAULT_TIMEOUT = 3000;
17
17
  const VIDEO_MESH_TIMEOUT = 1000;
18
18
 
19
+ export type ReachabilityMetrics = {
20
+ reachability_public_udp_success: number;
21
+ reachability_public_udp_failed: number;
22
+ reachability_public_tcp_success: number;
23
+ reachability_public_tcp_failed: number;
24
+ reachability_vmn_udp_success: number;
25
+ reachability_vmn_udp_failed: number;
26
+ reachability_vmn_tcp_success: number;
27
+ reachability_vmn_tcp_failed: number;
28
+ };
29
+
19
30
  // result for a specific transport protocol (like udp or tcp)
20
31
  export type TransportResult = {
21
- reachable: 'true' | 'false';
32
+ reachable?: 'true' | 'false';
22
33
  latencyInMilliseconds?: string;
23
34
  clientMediaIPs?: string[];
24
35
  untested?: 'true';
@@ -138,6 +149,58 @@ export default class Reachability {
138
149
  }
139
150
  }
140
151
 
152
+ /**
153
+ * Returns statistics about last reachability results. The returned value is an object
154
+ * with a flat list of properties so that it can be easily sent with metrics
155
+ *
156
+ * @returns {Promise} Promise with metrics values, it never rejects/throws.
157
+ */
158
+ async getReachabilityMetrics(): Promise<ReachabilityMetrics> {
159
+ const stats: ReachabilityMetrics = {
160
+ reachability_public_udp_success: 0,
161
+ reachability_public_udp_failed: 0,
162
+ reachability_public_tcp_success: 0,
163
+ reachability_public_tcp_failed: 0,
164
+ reachability_vmn_udp_success: 0,
165
+ reachability_vmn_udp_failed: 0,
166
+ reachability_vmn_tcp_success: 0,
167
+ reachability_vmn_tcp_failed: 0,
168
+ };
169
+
170
+ const updateStats = (clusterType: 'public' | 'vmn', result: ReachabilityResult) => {
171
+ if (result.udp?.reachable) {
172
+ const outcome = result.udp.reachable === 'true' ? 'success' : 'failed';
173
+ stats[`reachability_${clusterType}_udp_${outcome}`] += 1;
174
+ }
175
+ if (result.tcp?.reachable) {
176
+ const outcome = result.tcp.reachable === 'true' ? 'success' : 'failed';
177
+ stats[`reachability_${clusterType}_tcp_${outcome}`] += 1;
178
+ }
179
+ };
180
+
181
+ try {
182
+ // @ts-ignore
183
+ const resultsJson = await this.webex.boundedStorage.get(
184
+ REACHABILITY.namespace,
185
+ REACHABILITY.localStorageResult
186
+ );
187
+
188
+ const internalResults: InternalReachabilityResults = JSON.parse(resultsJson);
189
+
190
+ Object.values(internalResults).forEach((result) => {
191
+ updateStats(result.isVideoMesh ? 'vmn' : 'public', result);
192
+ });
193
+ } catch (e) {
194
+ // empty storage, that's ok
195
+ LoggerProxy.logger.warn(
196
+ 'Roap:request#getReachabilityMetrics --> Error parsing reachability data: ',
197
+ e
198
+ );
199
+ }
200
+
201
+ return stats;
202
+ }
203
+
141
204
  /**
142
205
  * Reachability results as an object in the format that backend expects
143
206
  *
@@ -20,3 +20,13 @@ describe('getContentUrl', () => {
20
20
  });
21
21
  });
22
22
 
23
+ describe('getContentBeneficiaryDeviceUrl', () => {
24
+ it('getContentBeneficiaryDeviceUrl return correct deviceUrl value', () => {
25
+ const mockContentBeneficiaryDeviceUrl = "https://wdm-a.wbx2.com/wdm/api/v1/devices/e9ffd8a1-1fae-42d1-afbe-013e951f93ab"
26
+ const stub = Sinon.stub(MediaSharesUtils, 'extractContentFloor').returns({ beneficiary: {deviceUrl : mockContentBeneficiaryDeviceUrl}});
27
+ const contentBeneficiaryDeviceUrl = MediaSharesUtils.getContentBeneficiaryDeviceUrl();
28
+ assert.equal(contentBeneficiaryDeviceUrl, mockContentBeneficiaryDeviceUrl);
29
+ stub.restore();
30
+ });
31
+ });
32
+
@@ -44,14 +44,12 @@ import {
44
44
  StreamEventNames,
45
45
  } from '@webex/media-helpers';
46
46
  import * as StatsAnalyzerModule from '@webex/plugin-meetings/src/statsAnalyzer';
47
- import * as MuteStateModule from '@webex/plugin-meetings/src/meeting/muteState';
48
47
  import EventsScope from '@webex/plugin-meetings/src/common/events/events-scope';
49
48
  import Meetings, {CONSTANTS} from '@webex/plugin-meetings';
50
49
  import Meeting from '@webex/plugin-meetings/src/meeting';
51
50
  import Members from '@webex/plugin-meetings/src/members';
52
51
  import * as MembersImport from '@webex/plugin-meetings/src/members';
53
52
  import Roap from '@webex/plugin-meetings/src/roap';
54
- import RoapRequest from '@webex/plugin-meetings/src/roap/request';
55
53
  import MeetingRequest from '@webex/plugin-meetings/src/meeting/request';
56
54
  import * as MeetingRequestImport from '@webex/plugin-meetings/src/meeting/request';
57
55
  import LocusInfo from '@webex/plugin-meetings/src/locus-info';
@@ -81,7 +79,6 @@ import {
81
79
  UserNotJoinedError,
82
80
  MeetingNotActiveError,
83
81
  UserInLobbyError,
84
- NoMediaEstablishedYetError,
85
82
  } from '../../../../src/common/errors/webex-errors';
86
83
  import WebExMeetingsErrors from '../../../../src/common/errors/webex-meetings-error';
87
84
  import ParameterError from '../../../../src/common/errors/parameter';
@@ -89,19 +86,14 @@ import PasswordError from '../../../../src/common/errors/password-error';
89
86
  import CaptchaError from '../../../../src/common/errors/captcha-error';
90
87
  import PermissionError from '../../../../src/common/errors/permission';
91
88
  import IntentToJoinError from '../../../../src/common/errors/intent-to-join';
92
- import DefaultSDKConfig from '../../../../src/config';
93
89
  import testUtils from '../../../utils/testUtils';
94
90
  import {
95
91
  MeetingInfoV2CaptchaError,
96
92
  MeetingInfoV2PasswordError,
97
93
  MeetingInfoV2PolicyError,
98
94
  } from '../../../../src/meeting-info/meeting-info-v2';
99
- import {ANNOTATION_POLICY} from '../../../../src/annotation/constants';
100
95
 
101
96
 
102
- // Non-stubbed function
103
- const {getDisplayMedia} = Media;
104
-
105
97
  describe('plugin-meetings', () => {
106
98
  const logger = {
107
99
  info: () => {},
@@ -228,6 +220,11 @@ describe('plugin-meetings', () => {
228
220
  webex.credentials.getOrgId = sinon.stub().returns('fake-org-id');
229
221
  webex.internal.metrics.submitClientMetrics = sinon.stub().returns(Promise.resolve());
230
222
  webex.meetings.uploadLogs = sinon.stub().returns(Promise.resolve());
223
+ webex.meetings.reachability = {
224
+ isAnyPublicClusterReachable: sinon.stub().resolves(true),
225
+ getReachabilityResults: sinon.stub().resolves(undefined),
226
+ getReachabilityMetrics: sinon.stub().resolves({}),
227
+ };
231
228
  webex.internal.llm.on = sinon.stub();
232
229
  membersSpy = sinon.spy(MembersImport, 'default');
233
230
  meetingRequestSpy = sinon.spy(MeetingRequestImport, 'default');
@@ -1170,8 +1167,15 @@ describe('plugin-meetings', () => {
1170
1167
  }
1171
1168
  });
1172
1169
 
1173
- it('should reset the statsAnalyzer to null if addMedia throws an error', async () => {
1170
+ it('should send metrics and reset the statsAnalyzer to null if addMedia throws an error', async () => {
1174
1171
  meeting.meetingState = 'ACTIVE';
1172
+ meeting.webex.meetings.reachability = {
1173
+ getReachabilityMetrics: sinon.stub().resolves({
1174
+ someReachabilityMetric1: 'some value1',
1175
+ someReachabilityMetric2: 'some value2'
1176
+ }),
1177
+ };
1178
+
1175
1179
  // setup the mock to return an incomplete object - this will cause addMedia to fail
1176
1180
  // because some methods (like on() or initiateOffer()) are missing
1177
1181
  Media.createMediaConnection = sinon.stub().returns({
@@ -1195,6 +1199,8 @@ describe('plugin-meetings', () => {
1195
1199
  signalingState: 'unknown',
1196
1200
  connectionState: 'unknown',
1197
1201
  iceConnectionState: 'unknown',
1202
+ someReachabilityMetric1: 'some value1',
1203
+ someReachabilityMetric2: 'some value2',
1198
1204
  });
1199
1205
  });
1200
1206
 
@@ -1546,6 +1552,12 @@ describe('plugin-meetings', () => {
1546
1552
 
1547
1553
  it('should send ADD_MEDIA_SUCCESS metrics', async () => {
1548
1554
  meeting.meetingState = 'ACTIVE';
1555
+ meeting.webex.meetings.reachability = {
1556
+ getReachabilityMetrics: sinon.stub().resolves({
1557
+ someReachabilityMetric1: 'some value1',
1558
+ someReachabilityMetric2: 'some value2'
1559
+ }),
1560
+ };
1549
1561
  await meeting.addMedia({
1550
1562
  mediaSettings: {},
1551
1563
  });
@@ -1556,6 +1568,8 @@ describe('plugin-meetings', () => {
1556
1568
  locus_id: meeting.locusUrl.split('/').pop(),
1557
1569
  connectionType: 'udp',
1558
1570
  isMultistream: false,
1571
+ someReachabilityMetric1: 'some value1',
1572
+ someReachabilityMetric2: 'some value2'
1559
1573
  });
1560
1574
 
1561
1575
  assert.called(webex.internal.newMetrics.submitClientEvent);
@@ -1792,10 +1806,6 @@ describe('plugin-meetings', () => {
1792
1806
  meeting.setMercuryListener = sinon.stub();
1793
1807
  meeting.locusInfo.onFullLocus = sinon.stub();
1794
1808
  meeting.webex.meetings.geoHintInfo = {regionCode: 'EU', countryCode: 'UK'};
1795
- meeting.webex.meetings.reachability = {
1796
- isAnyPublicClusterReachable: sinon.stub().resolves(true),
1797
- getReachabilityResults: sinon.stub().resolves(undefined),
1798
- };
1799
1809
  meeting.roap.doTurnDiscovery = sinon
1800
1810
  .stub()
1801
1811
  .resolves({turnServerInfo: {}, turnDiscoverySkippedReason: 'reachability'});
@@ -7203,6 +7213,7 @@ describe('plugin-meetings', () => {
7203
7213
  describe('setUpLocusMediaSharesListener', () => {
7204
7214
  beforeEach(() => {
7205
7215
  meeting.selfId = '9528d952-e4de-46cf-8157-fd4823b98377';
7216
+ meeting.deviceUrl = 'my-web-url';
7206
7217
  });
7207
7218
 
7208
7219
  const USER_IDS = {
@@ -7218,13 +7229,23 @@ describe('plugin-meetings', () => {
7218
7229
  'https://board-a.wbx2.com/board/api/v1/channels/977a7330-54f4-11eb-b1ef-91f5eefc7bf3',
7219
7230
  };
7220
7231
 
7232
+ const DEVICE_URL = {
7233
+ LOCAL_WEB: 'my-web-url',
7234
+ LOCAL_MAC: 'my-mac-url',
7235
+ REMOTE_A: 'remote-user-A-url',
7236
+ REMOTE_B: 'remote-user-B-url',
7237
+ };
7238
+
7239
+
7221
7240
  const generateContent = (
7222
7241
  beneficiaryId = null,
7223
7242
  disposition = null,
7243
+ deviceUrlSharing = null,
7224
7244
  annotation = undefined
7225
7245
  ) => ({
7226
7246
  beneficiaryId,
7227
7247
  disposition,
7248
+ deviceUrlSharing
7228
7249
  });
7229
7250
  const generateWhiteboard = (
7230
7251
  beneficiaryId = null,
@@ -7242,7 +7263,8 @@ describe('plugin-meetings', () => {
7242
7263
  otherBeneficiaryId,
7243
7264
  annotation,
7244
7265
  url,
7245
- shareInstanceId
7266
+ shareInstanceId,
7267
+ deviceUrlSharing,
7246
7268
  ) => {
7247
7269
  const newPayload = cloneDeep(payload);
7248
7270
 
@@ -7275,6 +7297,7 @@ describe('plugin-meetings', () => {
7275
7297
  newPayload.current.content = generateContent(
7276
7298
  beneficiaryId,
7277
7299
  FLOOR_ACTION.GRANTED,
7300
+ deviceUrlSharing,
7278
7301
  annotation
7279
7302
  );
7280
7303
 
@@ -7320,8 +7343,9 @@ describe('plugin-meetings', () => {
7320
7343
  functionName: 'stopWhiteboardShare',
7321
7344
  });
7322
7345
  }
7323
-
7324
- if (beneficiaryId === USER_IDS.ME) {
7346
+
7347
+ // Web client is sharing locally
7348
+ if (beneficiaryId === USER_IDS.ME && deviceUrlSharing === DEVICE_URL.LOCAL_WEB) {
7325
7349
  eventTrigger.share.push({
7326
7350
  eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_LOCAL,
7327
7351
  functionName: 'share',
@@ -7340,7 +7364,7 @@ describe('plugin-meetings', () => {
7340
7364
  }
7341
7365
  }
7342
7366
 
7343
- if (beneficiaryId === USER_IDS.ME) {
7367
+ if (beneficiaryId === USER_IDS.ME && deviceUrlSharing === DEVICE_URL.LOCAL_WEB) {
7344
7368
  shareStatus = SHARE_STATUS.LOCAL_SHARE_ACTIVE;
7345
7369
  } else {
7346
7370
  shareStatus = SHARE_STATUS.REMOTE_SHARE_ACTIVE;
@@ -7423,7 +7447,7 @@ describe('plugin-meetings', () => {
7423
7447
  if (isContent) {
7424
7448
  newPayload.current.content.disposition = FLOOR_ACTION.RELEASED;
7425
7449
 
7426
- if (beneficiaryId === USER_IDS.ME) {
7450
+ if (beneficiaryId === USER_IDS.ME && deviceUrlSharing === DEVICE_URL.LOCAL_WEB) {
7427
7451
  eventTrigger.share.push({
7428
7452
  eventName: EVENT_TRIGGERS.MEETING_STOPPED_SHARING_LOCAL,
7429
7453
  functionName: 'localShare',
@@ -7527,7 +7551,6 @@ describe('plugin-meetings', () => {
7527
7551
  const {functionName, eventName, eventPayload} = share[idx];
7528
7552
  const fileName =
7529
7553
  functionName === 'remoteShare' ? 'meetings/index' : 'meeting/index';
7530
-
7531
7554
  assert.deepEqual(shareCallArgs[1], {
7532
7555
  file: fileName,
7533
7556
  function: functionName,
@@ -7686,7 +7709,7 @@ describe('plugin-meetings', () => {
7686
7709
  true,
7687
7710
  false,
7688
7711
  USER_IDS.ME,
7689
- RESOURCE_URLS.WHITEBOARD_A
7712
+ RESOURCE_URLS.WHITEBOARD_A,
7690
7713
  );
7691
7714
  const data2 = generateData(
7692
7715
  data1.payload,
@@ -7695,7 +7718,7 @@ describe('plugin-meetings', () => {
7695
7718
  USER_IDS.ME,
7696
7719
  RESOURCE_URLS.WHITEBOARD_A,
7697
7720
  true,
7698
- USER_IDS.ME
7721
+ USER_IDS.ME,
7699
7722
  );
7700
7723
  const data3 = generateData(
7701
7724
  data2.payload,
@@ -7704,9 +7727,13 @@ describe('plugin-meetings', () => {
7704
7727
  USER_IDS.ME,
7705
7728
  undefined,
7706
7729
  true,
7707
- USER_IDS.ME
7730
+ USER_IDS.ME,
7731
+ undefined,
7732
+ undefined,
7733
+ undefined,
7734
+ DEVICE_URL.LOCAL_WEB,
7708
7735
  );
7709
- const data4 = generateData(data3.payload, false, true, USER_IDS.ME);
7736
+ const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
7710
7737
 
7711
7738
  payloadTestHelper([data1, data2, data3, data4]);
7712
7739
  });
@@ -7735,7 +7762,11 @@ describe('plugin-meetings', () => {
7735
7762
  USER_IDS.REMOTE_A,
7736
7763
  undefined,
7737
7764
  true,
7738
- USER_IDS.ME
7765
+ USER_IDS.ME,
7766
+ undefined,
7767
+ undefined,
7768
+ undefined,
7769
+ DEVICE_URL.REMOTE_A,
7739
7770
  );
7740
7771
  const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
7741
7772
 
@@ -7766,9 +7797,13 @@ describe('plugin-meetings', () => {
7766
7797
  USER_IDS.ME,
7767
7798
  undefined,
7768
7799
  true,
7769
- USER_IDS.REMOTE_A
7800
+ USER_IDS.REMOTE_A,
7801
+ undefined,
7802
+ undefined,
7803
+ undefined,
7804
+ DEVICE_URL.LOCAL_WEB,
7770
7805
  );
7771
- const data4 = generateData(data3.payload, false, true, USER_IDS.ME);
7806
+ const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
7772
7807
 
7773
7808
  payloadTestHelper([data1, data2, data3, data4]);
7774
7809
  });
@@ -7797,7 +7832,11 @@ describe('plugin-meetings', () => {
7797
7832
  USER_IDS.REMOTE_A,
7798
7833
  undefined,
7799
7834
  true,
7800
- USER_IDS.REMOTE_A
7835
+ USER_IDS.REMOTE_A,
7836
+ undefined,
7837
+ undefined,
7838
+ undefined,
7839
+ DEVICE_URL.REMOTE_A,
7801
7840
  );
7802
7841
  const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
7803
7842
 
@@ -7828,7 +7867,11 @@ describe('plugin-meetings', () => {
7828
7867
  USER_IDS.REMOTE_B,
7829
7868
  undefined,
7830
7869
  true,
7831
- USER_IDS.REMOTE_A
7870
+ USER_IDS.REMOTE_A,
7871
+ undefined,
7872
+ undefined,
7873
+ undefined,
7874
+ DEVICE_URL.REMOTE_B,
7832
7875
  );
7833
7876
  const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_B);
7834
7877
 
@@ -7838,7 +7881,7 @@ describe('plugin-meetings', () => {
7838
7881
 
7839
7882
  describe('Desktop --> Whiteboard A', () => {
7840
7883
  it('Scenario #1: you share desktop and then share whiteboard', () => {
7841
- const data1 = generateData(blankPayload, true, true, USER_IDS.ME);
7884
+ const data1 = generateData(blankPayload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
7842
7885
  const data2 = generateData(
7843
7886
  data1.payload,
7844
7887
  true,
@@ -7852,7 +7895,7 @@ describe('plugin-meetings', () => {
7852
7895
  });
7853
7896
 
7854
7897
  it('Scenario #2: you share desktop and remote person A shares whiteboard', () => {
7855
- const data1 = generateData(blankPayload, true, true, USER_IDS.ME);
7898
+ const data1 = generateData(blankPayload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
7856
7899
  const data2 = generateData(
7857
7900
  data1.payload,
7858
7901
  true,
@@ -7866,69 +7909,69 @@ describe('plugin-meetings', () => {
7866
7909
  });
7867
7910
 
7868
7911
  it('Scenario #3: remote person A shares desktop and you share whiteboard', () => {
7869
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
7912
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
7870
7913
  const data2 = generateData(
7871
7914
  data1.payload,
7872
7915
  true,
7873
7916
  false,
7874
- USER_IDS.REMOTE_A,
7917
+ USER_IDS.ME,
7875
7918
  RESOURCE_URLS.WHITEBOARD_A
7876
7919
  );
7877
- const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_A);
7920
+ const data3 = generateData(data2.payload, false, false, USER_IDS.ME);
7878
7921
 
7879
7922
  payloadTestHelper([data1, data2, data3]);
7880
7923
  });
7881
7924
 
7882
7925
  it('Scenario #4: remote person A shares desktop and then shares whiteboard', () => {
7883
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
7926
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
7884
7927
  const data2 = generateData(
7885
7928
  data1.payload,
7886
7929
  true,
7887
7930
  false,
7888
- USER_IDS.ME,
7931
+ USER_IDS.REMOTE_A,
7889
7932
  RESOURCE_URLS.WHITEBOARD_A
7890
7933
  );
7891
- const data3 = generateData(data2.payload, false, false, USER_IDS.ME);
7934
+ const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_A);
7892
7935
 
7893
7936
  payloadTestHelper([data1, data2, data3]);
7894
7937
  });
7895
7938
 
7896
7939
  it('Scenario #5: remote person A shares desktop and remote person B shares whiteboard', () => {
7897
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
7940
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
7898
7941
  const data2 = generateData(
7899
7942
  data1.payload,
7900
7943
  true,
7901
7944
  false,
7902
- USER_IDS.REMOTE_A,
7903
- RESOURCE_URLS.WHITEBOARD_A
7945
+ USER_IDS.REMOTE_B,
7946
+ RESOURCE_URLS.WHITEBOARD_B
7904
7947
  );
7905
- const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_A);
7948
+ const data3 = generateData(data2.payload, false, false, USER_IDS.REMOTE_B);
7906
7949
 
7907
7950
  payloadTestHelper([data1, data2, data3]);
7908
7951
  });
7909
7952
  });
7910
7953
  describe('Desktop A --> Desktop B', () => {
7911
- it('Scenario #1: you share desktop A and then share desktop B', () => {
7912
- const data1 = generateData(blankPayload, true, true, USER_IDS.ME);
7913
- const data2 = generateData(data1.payload, false, true, USER_IDS.ME);
7914
- const data3 = generateData(data2.payload, true, true, USER_IDS.ME);
7915
- const data4 = generateData(data3.payload, false, true, USER_IDS.ME);
7954
+ it('Scenario #1: you share desktop using web client and then share using native client', () => {
7955
+ const data1 = generateData(blankPayload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
7956
+ const data2 = generateData(data1.payload, false, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
7957
+ const data3 = generateData(data2.payload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_MAC);
7958
+ const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_MAC);
7916
7959
 
7917
7960
  payloadTestHelper([data1, data2, data3, data4]);
7918
7961
  });
7919
7962
 
7920
- it('Scenario #2: you share desktop A and remote person A shares desktop B', () => {
7921
- const data1 = generateData(blankPayload, true, true, USER_IDS.ME);
7922
- const data2 = generateData(data1.payload, true, true, USER_IDS.REMOTE_A);
7923
- const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_A);
7963
+ it('Scenario #2: you share desktop using web client and remote person A shares desktop', () => {
7964
+ const data1 = generateData(blankPayload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
7965
+ const data2 = generateData(data1.payload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A) ;
7966
+ const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
7924
7967
 
7925
7968
  payloadTestHelper([data1, data2, data3]);
7926
7969
  });
7927
7970
 
7928
- it('Scenario #3: remote person A shares desktop A and you share desktop B', () => {
7929
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
7930
- const data2 = generateData(data1.payload, true, true, USER_IDS.ME);
7931
- const data3 = generateData(data2.payload, false, true, USER_IDS.ME);
7971
+ it('Scenario #3: remote person A shares desktop and then you share desktop using web client', () => {
7972
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
7973
+ const data2 = generateData(data1.payload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
7974
+ const data3 = generateData(data2.payload, false, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
7932
7975
 
7933
7976
  payloadTestHelper([data1, data2, data3]);
7934
7977
  });
@@ -7942,8 +7985,8 @@ describe('plugin-meetings', () => {
7942
7985
  });
7943
7986
 
7944
7987
  it('Scenario #5: remote person A shares desktop A and remote person B shares desktop B', () => {
7945
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A);
7946
- const data2 = generateData(data1.payload, true, true, USER_IDS.REMOTE_B);
7988
+ const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
7989
+ const data2 = generateData(data1.payload, true, true, USER_IDS.REMOTE_B, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_B);
7947
7990
  const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_B);
7948
7991
 
7949
7992
  payloadTestHelper([data1, data2, data3]);