@webex/plugin-meetings 3.8.0-next.3 → 3.8.0-next.31

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.
Files changed (98) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/config.js +1 -0
  4. package/dist/config.js.map +1 -1
  5. package/dist/constants.js +1 -0
  6. package/dist/constants.js.map +1 -1
  7. package/dist/interpretation/index.js +4 -4
  8. package/dist/interpretation/index.js.map +1 -1
  9. package/dist/interpretation/siLanguage.js +1 -1
  10. package/dist/locus-info/controlsUtils.js +1 -1
  11. package/dist/locus-info/controlsUtils.js.map +1 -1
  12. package/dist/media/index.js +3 -15
  13. package/dist/media/index.js.map +1 -1
  14. package/dist/meeting/index.js +89 -5
  15. package/dist/meeting/index.js.map +1 -1
  16. package/dist/meeting/locusMediaRequest.js +21 -5
  17. package/dist/meeting/locusMediaRequest.js.map +1 -1
  18. package/dist/meeting/util.js +4 -1
  19. package/dist/meeting/util.js.map +1 -1
  20. package/dist/meeting-info/meeting-info-v2.js +359 -60
  21. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  22. package/dist/meetings/index.js +60 -1
  23. package/dist/meetings/index.js.map +1 -1
  24. package/dist/member/index.js +10 -0
  25. package/dist/member/index.js.map +1 -1
  26. package/dist/member/util.js +3 -0
  27. package/dist/member/util.js.map +1 -1
  28. package/dist/metrics/constants.js +9 -0
  29. package/dist/metrics/constants.js.map +1 -1
  30. package/dist/reachability/clusterReachability.js +52 -8
  31. package/dist/reachability/clusterReachability.js.map +1 -1
  32. package/dist/reachability/index.js +70 -45
  33. package/dist/reachability/index.js.map +1 -1
  34. package/dist/reachability/reachability.types.js +14 -0
  35. package/dist/reachability/reachability.types.js.map +1 -1
  36. package/dist/reachability/request.js +19 -3
  37. package/dist/reachability/request.js.map +1 -1
  38. package/dist/reconnection-manager/index.js +2 -2
  39. package/dist/reconnection-manager/index.js.map +1 -1
  40. package/dist/recording-controller/util.js +5 -5
  41. package/dist/recording-controller/util.js.map +1 -1
  42. package/dist/roap/index.js.map +1 -1
  43. package/dist/roap/turnDiscovery.js +31 -23
  44. package/dist/roap/turnDiscovery.js.map +1 -1
  45. package/dist/roap/types.js +17 -0
  46. package/dist/roap/types.js.map +1 -0
  47. package/dist/types/config.d.ts +1 -0
  48. package/dist/types/constants.d.ts +1 -0
  49. package/dist/types/meeting/index.d.ts +32 -1
  50. package/dist/types/meeting-info/meeting-info-v2.d.ts +80 -0
  51. package/dist/types/meetings/index.d.ts +29 -0
  52. package/dist/types/member/index.d.ts +1 -0
  53. package/dist/types/metrics/constants.d.ts +9 -0
  54. package/dist/types/reachability/clusterReachability.d.ts +13 -1
  55. package/dist/types/reachability/index.d.ts +2 -1
  56. package/dist/types/reachability/reachability.types.d.ts +5 -0
  57. package/dist/types/roap/index.d.ts +3 -2
  58. package/dist/types/roap/turnDiscovery.d.ts +1 -17
  59. package/dist/types/roap/types.d.ts +16 -0
  60. package/dist/webinar/index.js +1 -1
  61. package/package.json +22 -22
  62. package/src/config.ts +1 -0
  63. package/src/constants.ts +1 -0
  64. package/src/interpretation/index.ts +3 -3
  65. package/src/locus-info/controlsUtils.ts +2 -2
  66. package/src/media/index.ts +5 -21
  67. package/src/meeting/index.ts +91 -13
  68. package/src/meeting/locusMediaRequest.ts +27 -4
  69. package/src/meeting/util.ts +2 -1
  70. package/src/meeting-info/meeting-info-v2.ts +247 -6
  71. package/src/meetings/index.ts +72 -1
  72. package/src/member/index.ts +11 -0
  73. package/src/member/util.ts +3 -0
  74. package/src/metrics/constants.ts +9 -0
  75. package/src/reachability/clusterReachability.ts +47 -1
  76. package/src/reachability/index.ts +15 -0
  77. package/src/reachability/reachability.types.ts +6 -0
  78. package/src/reachability/request.ts +7 -0
  79. package/src/reconnection-manager/index.ts +2 -2
  80. package/src/recording-controller/util.ts +17 -13
  81. package/src/roap/index.ts +3 -7
  82. package/src/roap/turnDiscovery.ts +21 -35
  83. package/src/roap/types.ts +23 -0
  84. package/test/unit/spec/interpretation/index.ts +39 -1
  85. package/test/unit/spec/locus-info/controlsUtils.js +8 -0
  86. package/test/unit/spec/media/index.ts +6 -16
  87. package/test/unit/spec/meeting/index.js +212 -125
  88. package/test/unit/spec/meeting/locusMediaRequest.ts +96 -58
  89. package/test/unit/spec/meeting/utils.js +55 -0
  90. package/test/unit/spec/meeting-info/meetinginfov2.js +443 -114
  91. package/test/unit/spec/meetings/index.js +78 -1
  92. package/test/unit/spec/member/index.js +7 -0
  93. package/test/unit/spec/member/util.js +24 -0
  94. package/test/unit/spec/reachability/clusterReachability.ts +47 -1
  95. package/test/unit/spec/reachability/index.ts +12 -0
  96. package/test/unit/spec/reachability/request.js +47 -2
  97. package/test/unit/spec/reconnection-manager/index.js +4 -4
  98. package/test/unit/spec/roap/turnDiscovery.ts +72 -28
@@ -6,33 +6,37 @@ const canUserStart = (
6
6
  displayHints: Array<string>,
7
7
  userPolicies: Record<SELF_POLICY, boolean>
8
8
  ): boolean =>
9
- (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_START) ||
10
- displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_START)) &&
11
- MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
9
+ (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_START) &&
10
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies)) ||
11
+ (displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_START) &&
12
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_PREMISE_RECORD, userPolicies));
12
13
 
13
14
  const canUserPause = (
14
15
  displayHints: Array<string>,
15
16
  userPolicies: Record<SELF_POLICY, boolean>
16
17
  ): boolean =>
17
- (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_PAUSE) ||
18
- displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_PAUSE)) &&
19
- MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
18
+ (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_PAUSE) &&
19
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies)) ||
20
+ (displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_PAUSE) &&
21
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_PREMISE_RECORD, userPolicies));
20
22
 
21
23
  const canUserResume = (
22
24
  displayHints: Array<string>,
23
25
  userPolicies: Record<SELF_POLICY, boolean>
24
26
  ): boolean =>
25
- (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_RESUME) ||
26
- displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_RESUME)) &&
27
- MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
27
+ (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_RESUME) &&
28
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies)) ||
29
+ (displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_RESUME) &&
30
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_PREMISE_RECORD, userPolicies));
28
31
 
29
32
  const canUserStop = (
30
33
  displayHints: Array<string>,
31
34
  userPolicies: Record<SELF_POLICY, boolean>
32
35
  ): boolean =>
33
- (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_STOP) ||
34
- displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_STOP)) &&
35
- MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
36
+ (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_STOP) &&
37
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies)) ||
38
+ (displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_STOP) &&
39
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_PREMISE_RECORD, userPolicies));
36
40
 
37
41
  const isPremiseRecordingEnabled = (
38
42
  displayHints: Array<string>,
@@ -42,7 +46,7 @@ const isPremiseRecordingEnabled = (
42
46
  displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_PAUSE) ||
43
47
  displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_STOP) ||
44
48
  displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_RESUME)) &&
45
- MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
49
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_PREMISE_RECORD, userPolicies);
46
50
 
47
51
  const extractLocusId = (url: string) => {
48
52
  return url?.split('/').pop();
package/src/roap/index.ts CHANGED
@@ -5,17 +5,13 @@ import {ROAP} from '../constants';
5
5
  import LoggerProxy from '../common/logs/logger-proxy';
6
6
 
7
7
  import RoapRequest from './request';
8
- import TurnDiscovery, {TurnDiscoveryResult} from './turnDiscovery';
8
+ import TurnDiscovery from './turnDiscovery';
9
+ import {TurnDiscoveryResult} from './types';
9
10
  import Meeting from '../meeting';
10
- import MeetingUtil from '../meeting/util';
11
11
  import Metrics from '../metrics';
12
12
  import BEHAVIORAL_METRICS from '../metrics/constants';
13
13
 
14
- export {
15
- type TurnDiscoveryResult,
16
- type TurnServerInfo,
17
- type TurnDiscoverySkipReason,
18
- } from './turnDiscovery';
14
+ export {type TurnDiscoveryResult, type TurnServerInfo, type TurnDiscoverySkipReason} from './types';
19
15
 
20
16
  /**
21
17
  * Roap options
@@ -4,11 +4,11 @@ import {Defer} from '@webex/common';
4
4
  import Metrics from '../metrics';
5
5
  import BEHAVIORAL_METRICS from '../metrics/constants';
6
6
  import LoggerProxy from '../common/logs/logger-proxy';
7
- import {ROAP, Enum} from '../constants';
7
+ import {ROAP} from '../constants';
8
8
 
9
9
  import RoapRequest from './request';
10
10
  import Meeting from '../meeting';
11
- import MeetingUtil from '../meeting/util';
11
+ import {TurnDiscoverySkipReason, TurnServerInfo, TurnDiscoveryResult} from './types';
12
12
 
13
13
  const TURN_DISCOVERY_TIMEOUT = 10; // in seconds
14
14
 
@@ -18,28 +18,6 @@ const TURN_DISCOVERY_TIMEOUT = 10; // in seconds
18
18
  // and do the SDP offer with seq=1
19
19
  const TURN_DISCOVERY_SEQ = 0;
20
20
 
21
- const TurnDiscoverySkipReason = {
22
- missingHttpResponse: 'missing http response', // when we asked for the TURN discovery response to be in the http response, but it wasn't there
23
- reachability: 'reachability', // when udp reachability to public clusters is ok, so we don't need TURN (this doens't apply when joinWithMedia() is used)
24
- alreadyInProgress: 'already in progress', // when we try to start TURN discovery while it's already in progress
25
- } as const;
26
-
27
- export type TurnDiscoverySkipReason =
28
- | Enum<typeof TurnDiscoverySkipReason> // this is a kind of FYI, because in practice typescript will infer the type of TurnDiscoverySkipReason as a string
29
- | string // used in case of errors, contains the error message
30
- | undefined; // used when TURN discovery is not skipped
31
-
32
- export type TurnServerInfo = {
33
- url: string;
34
- username: string;
35
- password: string;
36
- };
37
-
38
- export type TurnDiscoveryResult = {
39
- turnServerInfo?: TurnServerInfo;
40
- turnDiscoverySkippedReason: TurnDiscoverySkipReason;
41
- };
42
-
43
21
  /**
44
22
  * Handles the process of finding out TURN server information from Linus.
45
23
  * This is achieved by sending a TURN_DISCOVERY_REQUEST.
@@ -61,7 +39,7 @@ export default class TurnDiscovery {
61
39
  constructor(roapRequest: RoapRequest) {
62
40
  this.roapRequest = roapRequest;
63
41
  this.turnInfo = {
64
- url: '',
42
+ urls: [],
65
43
  username: '',
66
44
  password: '',
67
45
  };
@@ -134,21 +112,27 @@ export default class TurnDiscovery {
134
112
  }
135
113
 
136
114
  const expectedHeaders = [
137
- {headerName: 'x-cisco-turn-url', field: 'url'},
138
- {headerName: 'x-cisco-turn-username', field: 'username'},
139
- {headerName: 'x-cisco-turn-password', field: 'password'},
115
+ {headerName: 'x-cisco-turn-url', field: 'urls', multipleAllowed: true},
116
+ {headerName: 'x-cisco-turn-username', field: 'username', multipleAllowed: false},
117
+ {headerName: 'x-cisco-turn-password', field: 'password', multipleAllowed: false},
140
118
  ];
141
119
 
142
- let foundHeaders = 0;
120
+ const foundHeaders = {};
143
121
 
144
122
  headers?.forEach((receivedHeader) => {
145
123
  // check if it matches any of our expected headers
146
124
  expectedHeaders.forEach((expectedHeader) => {
147
125
  if (receivedHeader.startsWith(`${expectedHeader.headerName}=`)) {
148
- this.turnInfo[expectedHeader.field] = receivedHeader.substring(
149
- expectedHeader.headerName.length + 1
150
- );
151
- foundHeaders += 1;
126
+ foundHeaders[expectedHeader.headerName] = true;
127
+
128
+ const headerValue = receivedHeader.substring(expectedHeader.headerName.length + 1);
129
+
130
+ if (expectedHeader.multipleAllowed) {
131
+ this.turnInfo[expectedHeader.field].push(headerValue);
132
+ } else {
133
+ // just store the last one we find
134
+ this.turnInfo[expectedHeader.field] = headerValue;
135
+ }
152
136
  }
153
137
  });
154
138
  });
@@ -156,7 +140,7 @@ export default class TurnDiscovery {
156
140
  clearTimeout(this.responseTimer);
157
141
  this.responseTimer = undefined;
158
142
 
159
- if (foundHeaders !== expectedHeaders.length) {
143
+ if (expectedHeaders.some((header) => !foundHeaders[header.headerName])) {
160
144
  LoggerProxy.logger.warn(
161
145
  `Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received ${from}: ${JSON.stringify(
162
146
  headers
@@ -169,9 +153,11 @@ export default class TurnDiscovery {
169
153
  );
170
154
  } else {
171
155
  LoggerProxy.logger.info(
172
- `Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response ${from}, url=${this.turnInfo.url}`
156
+ `Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response ${from}, urls=${this.turnInfo.urls}`
173
157
  );
174
158
 
159
+ this.turnInfo.urls = this.turnInfo.urls.filter((url) => url !== ''); // remove empty urls, we might get them if we land on video-mesh nodes (VMN)
160
+
175
161
  this.defer.resolve({isOkRequired: !headers?.includes('noOkInTransaction')});
176
162
  }
177
163
  }
@@ -0,0 +1,23 @@
1
+ import {Enum} from '../constants';
2
+
3
+ export const TurnDiscoverySkipReason = {
4
+ missingHttpResponse: 'missing http response', // when we asked for the TURN discovery response to be in the http response, but it wasn't there
5
+ reachability: 'reachability', // when udp reachability to public clusters is ok, so we don't need TURN (this doens't apply when joinWithMedia() is used)
6
+ alreadyInProgress: 'already in progress', // when we try to start TURN discovery while it's already in progress
7
+ } as const;
8
+
9
+ export type TurnDiscoverySkipReason =
10
+ | Enum<typeof TurnDiscoverySkipReason> // this is a kind of FYI, because in practice typescript will infer the type of TurnDiscoverySkipReason as a string
11
+ | string // used in case of errors, contains the error message
12
+ | undefined; // used when TURN discovery is not skipped
13
+
14
+ export type TurnServerInfo = {
15
+ urls: string[];
16
+ username: string;
17
+ password: string;
18
+ };
19
+
20
+ export type TurnDiscoveryResult = {
21
+ turnServerInfo?: TurnServerInfo;
22
+ turnDiscoverySkippedReason: TurnDiscoverySkipReason;
23
+ };
@@ -22,16 +22,54 @@ describe('plugin-meetings', () => {
22
22
  });
23
23
 
24
24
  describe('#initialize', () => {
25
+ beforeEach(() => {
26
+ interpretation.querySupportLanguages = sinon.stub();
27
+ interpretation.set({
28
+ canManageInterpreters: undefined,
29
+ hostSIEnabled: undefined,
30
+ locusUrl: undefined
31
+ });
32
+ });
33
+
34
+ afterEach(() => {
35
+ interpretation.querySupportLanguages.reset();
36
+ });
37
+
25
38
  it('creates SimultaneousInterpretation as expected', () => {
26
39
  assert.equal(interpretation.namespace, 'Meetings');
27
40
  });
28
41
  it('call querySupportLanguages correctly when meet the conditions', () => {
29
- interpretation.querySupportLanguages = sinon.stub();
30
42
  interpretation.set({
31
43
  canManageInterpreters: true,
44
+ hostSIEnabled: true,
45
+ locusUrl: "MOCK_LOCUS_URL"
32
46
  });
33
47
  assert.called(interpretation.querySupportLanguages);
34
48
  });
49
+
50
+ it('does not call querySupportLanguages when canManageInterpreters is not set', () => {
51
+ interpretation.set({
52
+ hostSIEnabled: true,
53
+ locusUrl: "MOCK_LOCUS_URL"
54
+ });
55
+ assert.notCalled(interpretation.querySupportLanguages);
56
+ });
57
+
58
+ it('does not call querySupportLanguages when hostSIEnabled is not set', () => {
59
+ interpretation.set({
60
+ canManageInterpreters: true,
61
+ locusUrl: "MOCK_LOCUS_URL"
62
+ });
63
+ assert.notCalled(interpretation.querySupportLanguages);
64
+ });
65
+
66
+ it('does not call querySupportLanguages when locusUrl is not set', () => {
67
+ interpretation.set({
68
+ canManageInterpreters: true,
69
+ hostSIEnabled: true,
70
+ });
71
+ assert.notCalled(interpretation.querySupportLanguages);
72
+ });
35
73
  });
36
74
 
37
75
  describe('#cleanUp', () => {
@@ -269,6 +269,14 @@ describe('plugin-meetings', () => {
269
269
  assert.equal(updates.hasPracticeSessionEnabledChanged, true);
270
270
  });
271
271
 
272
+ it('returns hasPracticeSessionEnabledChanged = false when enabled is false and previous state is false', () => {
273
+ const newControls = {practiceSession: {enabled: false}};
274
+
275
+ const {updates} = ControlsUtils.getControls(defaultControls, newControls);
276
+
277
+ assert.equal(updates.hasPracticeSessionEnabledChanged, false);
278
+ });
279
+
272
280
  it('returns hasEntryExitToneChanged = true when mode changed', () => {
273
281
  const newControls = {
274
282
  entryExitTone: {
@@ -79,7 +79,7 @@ describe('createMediaConnection', () => {
79
79
  enableRtx: ENABLE_RTX,
80
80
  enableExtmap: ENABLE_EXTMAP,
81
81
  turnServerInfo: {
82
- url: 'turns:turn-server-url:443?transport=tcp',
82
+ urls: ['turns:turn-server-url-1:443?transport=tcp', 'turns:turn-server-url-2:443?transport=tcp'],
83
83
  username: 'turn username',
84
84
  password: 'turn password',
85
85
  },
@@ -91,12 +91,7 @@ describe('createMediaConnection', () => {
91
91
  {
92
92
  iceServers: [
93
93
  {
94
- urls: 'turn:turn-server-url:5004?transport=tcp',
95
- username: 'turn username',
96
- credential: 'turn password',
97
- },
98
- {
99
- urls: 'turns:turn-server-url:443?transport=tcp',
94
+ urls: ['turns:turn-server-url-1:443?transport=tcp', 'turns:turn-server-url-2:443?transport=tcp'],
100
95
  username: 'turn username',
101
96
  credential: 'turn password',
102
97
  },
@@ -159,7 +154,7 @@ describe('createMediaConnection', () => {
159
154
  },
160
155
  rtcMetrics,
161
156
  turnServerInfo: {
162
- url: 'turns:turn-server-url:443?transport=tcp',
157
+ urls: ['turns:turn-server-url-1:443?transport=tcp', 'turns:turn-server-url-2:443?transport=tcp'],
163
158
  username: 'turn username',
164
159
  password: 'turn password',
165
160
  },
@@ -171,12 +166,7 @@ describe('createMediaConnection', () => {
171
166
  {
172
167
  iceServers: [
173
168
  {
174
- urls: 'turn:turn-server-url:5004?transport=tcp',
175
- username: 'turn username',
176
- credential: 'turn password',
177
- },
178
- {
179
- urls: 'turns:turn-server-url:443?transport=tcp',
169
+ urls: ['turns:turn-server-url-1:443?transport=tcp', 'turns:turn-server-url-2:443?transport=tcp'],
180
170
  username: 'turn username',
181
171
  credential: 'turn password',
182
172
  },
@@ -212,7 +202,7 @@ describe('createMediaConnection', () => {
212
202
  {testCase: 'turnServerInfo is undefined', turnServerInfo: undefined},
213
203
  {
214
204
  testCase: 'turnServerInfo.url is empty string',
215
- turnServerInfo: {url: '', username: 'turn username', password: 'turn password'},
205
+ turnServerInfo: {urls: [], username: 'turn username', password: 'turn password'},
216
206
  },
217
207
  ].forEach(({testCase, turnServerInfo}) => {
218
208
  it(`passes empty ICE servers array to MultistreamRoapMediaConnection if ${testCase} (multistream enabled)`, () => {
@@ -276,7 +266,7 @@ describe('createMediaConnection', () => {
276
266
  {testCase: 'turnServerInfo is undefined', turnServerInfo: undefined},
277
267
  {
278
268
  testCase: 'turnServerInfo.url is empty string',
279
- turnServerInfo: {url: '', username: 'turn username', password: 'turn password'},
269
+ turnServerInfo: {urls: [], username: 'turn username', password: 'turn password'},
280
270
  },
281
271
  ].forEach(({testCase, turnServerInfo}) => {
282
272
  it(`passes empty ICE servers array to RoapMediaConnection if ${testCase} (multistream disabled)`, () => {