@whereby.com/media 2.8.1 → 2.8.3

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.
package/dist/index.mjs CHANGED
@@ -1406,7 +1406,7 @@ class ReconnectManager extends EventEmitter {
1406
1406
  clearTimeout(client.timeout);
1407
1407
  delete this._clients[clientId];
1408
1408
  }
1409
- (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.disconnect(clientId, null, payload.eventClaim);
1409
+ (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.disconnect(clientId, payload.eventClaim);
1410
1410
  this.emit(PROTOCOL_RESPONSES.CLIENT_LEFT, payload);
1411
1411
  }
1412
1412
  _onPendingClientLeft(payload) {
@@ -2213,7 +2213,7 @@ var _a$4;
2213
2213
  const adapter$4 = (_a$4 = adapterRaw.default) !== null && _a$4 !== void 0 ? _a$4 : adapterRaw;
2214
2214
  const logger$7 = new Logger();
2215
2215
  class Session {
2216
- constructor({ peerConnectionId, clientId, bandwidth, peerConnectionConfig, deprioritizeH264Encoding, shouldAddLocalVideo, incrementAnalyticMetric, }) {
2216
+ constructor({ peerConnectionId, clientId, bandwidth, peerConnectionConfig, deprioritizeH264Encoding, incrementAnalyticMetric, }) {
2217
2217
  this.peerConnectionId = peerConnectionId;
2218
2218
  this.relayCandidateSeen = false;
2219
2219
  this.serverReflexiveCandidateSeen = false;
@@ -2223,7 +2223,6 @@ class Session {
2223
2223
  this.ipv6HostCandidate6to4Seen = false;
2224
2224
  this.mdnsHostCandidateSeen = false;
2225
2225
  this.peerConnectionConfig = peerConnectionConfig;
2226
- this.shouldAddLocalVideo = shouldAddLocalVideo;
2227
2226
  this.clientId = clientId;
2228
2227
  this.pc = new RTCPeerConnection(this.peerConnectionConfig);
2229
2228
  this.signalingState = this.pc.signalingState;
@@ -2291,11 +2290,13 @@ class Session {
2291
2290
  }
2292
2291
  }
2293
2292
  removeStream(stream) {
2294
- for (let i = 0; i < this.streamIds.length; i++) {
2295
- if (this.streamIds[i] === stream.id) {
2296
- this.streamIds.splice(i, 1);
2297
- this.streams.splice(i, 1);
2298
- }
2293
+ const streamIdIndex = this.streamIds.indexOf(stream.id);
2294
+ if (streamIdIndex !== -1) {
2295
+ this.streamIds.splice(streamIdIndex, 1);
2296
+ }
2297
+ const streamIndex = this.streams.indexOf(stream);
2298
+ if (streamIndex !== -1) {
2299
+ this.streams.splice(streamIndex, 1);
2299
2300
  }
2300
2301
  if (this.pc) {
2301
2302
  if (this.pc.removeTrack) {
@@ -2561,57 +2562,6 @@ const TYPES = {
2561
2562
  CONNECTION_DISCONNECTED: "connection_disconnected",
2562
2563
  };
2563
2564
 
2564
- const CAMERA_STREAM_ID$1 = "0";
2565
- const STREAM_TYPES = {
2566
- CAMERA: "camera",
2567
- SCREEN_SHARE: "screen_share",
2568
- };
2569
- class RtcStream {
2570
- constructor(id, type) {
2571
- this.id = "" + id;
2572
- this.type = type;
2573
- this.isEnabled = true;
2574
- this.hasSupportForAutoSuperSize = false;
2575
- this.isAudioEnabled = true;
2576
- this.isVideoEnabled = true;
2577
- this.status = TYPES.CONNECTING;
2578
- this.stream = null;
2579
- this.streamId = null;
2580
- }
2581
- setup(stream) {
2582
- this.stream = stream;
2583
- this.streamId = stream.id;
2584
- this.setVideoEnabled(this.isVideoEnabled && stream.getVideoTracks().length > 0);
2585
- this.setAudioEnabled(this.isAudioEnabled && stream.getAudioTracks().length > 0);
2586
- return this;
2587
- }
2588
- setStatus(status) {
2589
- this.status = status;
2590
- return this;
2591
- }
2592
- setVideoEnabled(isEnabled) {
2593
- this.isVideoEnabled = isEnabled;
2594
- if (!this.stream) {
2595
- return;
2596
- }
2597
- this.stream.getVideoTracks().forEach((track) => {
2598
- track.enabled = isEnabled;
2599
- });
2600
- }
2601
- setAudioEnabled(isEnabled) {
2602
- this.isAudioEnabled = isEnabled;
2603
- if (!this.stream) {
2604
- return;
2605
- }
2606
- this.stream.getAudioTracks().forEach((track) => {
2607
- track.enabled = isEnabled;
2608
- });
2609
- }
2610
- static getCameraId() {
2611
- return CAMERA_STREAM_ID$1;
2612
- }
2613
- }
2614
-
2615
2565
  var rtcManagerEvents = {
2616
2566
  CAMERA_NOT_WORKING: "camera_not_working",
2617
2567
  CONNECTION_BLOCKED_BY_NETWORK: "connection_blocked_by_network",
@@ -2626,11 +2576,16 @@ var rtcManagerEvents = {
2626
2576
  DOMINANT_SPEAKER: "dominant_speaker",
2627
2577
  };
2628
2578
 
2579
+ const CAMERA_STREAM_ID = "0";
2580
+ const STREAM_TYPES = {
2581
+ webcam: "webcam",
2582
+ screenshare: "screenshare",
2583
+ };
2584
+
2629
2585
  var _a$2, _b$1, _c;
2630
2586
  const adapter$2 = (_a$2 = adapterRaw.default) !== null && _a$2 !== void 0 ? _a$2 : adapterRaw;
2631
2587
  const logger$6 = new Logger();
2632
2588
  const ICE_PUBLIC_IP_GATHERING_TIMEOUT = 3 * 1000;
2633
- const CAMERA_STREAM_ID = RtcStream.getCameraId();
2634
2589
  const browserName$1 = (_b$1 = adapter$2.browserDetails) === null || _b$1 === void 0 ? void 0 : _b$1.browser;
2635
2590
  const browserVersion = adapter$2.browserDetails.version;
2636
2591
  if (browserName$1 === "firefox" && adapter$2.browserShim && "shimGetDisplayMedia" in adapter$2.browserShim) {
@@ -2708,6 +2663,7 @@ class P2pRtcManager {
2708
2663
  P2PReplaceTrackWithoutPC: 0,
2709
2664
  P2PReplaceTrackSourceKindNotFound: 0,
2710
2665
  P2PRemoveStreamNoPC: 0,
2666
+ P2POnTrackNoStream: 0,
2711
2667
  };
2712
2668
  }
2713
2669
  numberOfPeerconnections() {
@@ -2854,13 +2810,10 @@ class P2pRtcManager {
2854
2810
  });
2855
2811
  }),
2856
2812
  this._serverSocket.on(PROTOCOL_RESPONSES.ROOM_JOINED, (payload) => {
2857
- var _a, _b;
2858
- if (payload === null || payload === void 0 ? void 0 : payload.error) {
2813
+ const { error } = payload;
2814
+ if (error || !this._wasScreenSharing) {
2859
2815
  return;
2860
2816
  }
2861
- const isSfu = (_b = (_a = payload === null || payload === void 0 ? void 0 : payload.room) === null || _a === void 0 ? void 0 : _a.sfuServer) !== null && _b !== void 0 ? _b : false;
2862
- if (isSfu || !this._wasScreenSharing)
2863
- return;
2864
2817
  const screenShareStreamId = Object.keys(this.localStreams).find((id) => id !== CAMERA_STREAM_ID);
2865
2818
  if (!screenShareStreamId) {
2866
2819
  return;
@@ -2876,6 +2829,15 @@ class P2pRtcManager {
2876
2829
  hasAudioTrack,
2877
2830
  });
2878
2831
  }),
2832
+ this._serverSocket.on(PROTOCOL_RESPONSES.SCREENSHARE_STOPPED, (payload) => {
2833
+ const session = this._getSession(payload.clientId);
2834
+ if (session) {
2835
+ const streamIdIndex = session.streamIds.indexOf(payload.streamId);
2836
+ if (streamIdIndex !== -1) {
2837
+ session.streamIds.splice(streamIdIndex, 1);
2838
+ }
2839
+ }
2840
+ }),
2879
2841
  ];
2880
2842
  }
2881
2843
  sendAudioMutedStats(muted) {
@@ -2987,7 +2949,7 @@ class P2pRtcManager {
2987
2949
  }
2988
2950
  return this.peerConnections[peerConnectionId];
2989
2951
  }
2990
- _getOrCreateSession({ peerConnectionId, clientId, initialBandwidth, peerConnectionConfig, shouldAddLocalVideo, }) {
2952
+ _getOrCreateSession({ peerConnectionId, clientId, initialBandwidth, peerConnectionConfig, }) {
2991
2953
  let session = this.peerConnections[peerConnectionId];
2992
2954
  if (session === undefined) {
2993
2955
  const deprioritizeH264Encoding = browserName$1 === "safari" &&
@@ -3000,7 +2962,6 @@ class P2pRtcManager {
3000
2962
  peerConnectionConfig,
3001
2963
  bandwidth: initialBandwidth,
3002
2964
  deprioritizeH264Encoding,
3003
- shouldAddLocalVideo,
3004
2965
  incrementAnalyticMetric: (metric) => this.analytics[metric]++,
3005
2966
  });
3006
2967
  }
@@ -3033,7 +2994,7 @@ class P2pRtcManager {
3033
2994
  _transformOutgoingSdp(original) {
3034
2995
  return { type: original.type, sdpU: original.sdp, sdp: original.sdp };
3035
2996
  }
3036
- _createSession({ clientId, initialBandwidth, isOfferer, peerConnectionId, shouldAddLocalVideo, }) {
2997
+ _createSession({ clientId, initialBandwidth, isOfferer, peerConnectionId, }) {
3037
2998
  if (!peerConnectionId) {
3038
2999
  throw new Error("peerConnectionId is missing");
3039
3000
  }
@@ -3062,14 +3023,18 @@ class P2pRtcManager {
3062
3023
  clientId,
3063
3024
  initialBandwidth,
3064
3025
  peerConnectionConfig,
3065
- shouldAddLocalVideo,
3066
3026
  });
3067
3027
  setTimeout(() => this._emit(rtcManagerEvents.NEW_PC), 0);
3068
3028
  this.analytics.numNewPc++;
3069
3029
  const { pc } = session;
3070
3030
  pc.ontrack = (event) => {
3071
3031
  const stream = event.streams[0];
3072
- if (stream.id === "default" && stream.getAudioTracks().length === 0) {
3032
+ if (!stream) {
3033
+ this.analytics.P2POnTrackNoStream++;
3034
+ rtcStats.sendEvent("P2POnTrackNoStream", {
3035
+ trackKind: event.track.kind,
3036
+ trackId: event.track.id,
3037
+ });
3073
3038
  return;
3074
3039
  }
3075
3040
  if (session.streamIds.indexOf(stream.id) === -1) {
@@ -3078,16 +3043,6 @@ class P2pRtcManager {
3078
3043
  clientId,
3079
3044
  stream,
3080
3045
  });
3081
- if (session.connectionStatus === TYPES.CONNECTION_SUCCESSFUL) {
3082
- setTimeout(() => {
3083
- this._emit(EVENTS.CLIENT_CONNECTION_STATUS_CHANGED, {
3084
- streamIds: session.streamIds,
3085
- clientId,
3086
- status: session.connectionStatus,
3087
- previous: TYPES.CONNECTING,
3088
- });
3089
- }, 0);
3090
- }
3091
3046
  }
3092
3047
  };
3093
3048
  pc.oniceconnectionstatechange = () => {
@@ -3165,30 +3120,28 @@ class P2pRtcManager {
3165
3120
  }
3166
3121
  };
3167
3122
  const localCameraStream = this.localStreams[CAMERA_STREAM_ID];
3168
- if (shouldAddLocalVideo && localCameraStream) {
3123
+ if (localCameraStream) {
3169
3124
  session.addStream(localCameraStream);
3170
3125
  }
3171
- if (shouldAddLocalVideo) {
3172
- Object.keys(this.localStreams).forEach((id) => {
3173
- if (id === CAMERA_STREAM_ID) {
3174
- return;
3175
- }
3176
- const screenshareStream = this.localStreams[id];
3177
- if (isOfferer) {
3178
- session.addStream(screenshareStream);
3179
- }
3180
- else {
3181
- session.afterConnected.then(() => {
3182
- this._emitServerEvent(PROTOCOL_REQUESTS.START_SCREENSHARE, {
3183
- receiverId: session.clientId,
3184
- streamId: screenshareStream.id,
3185
- hasAudioTrack: !!screenshareStream.getAudioTracks().length,
3186
- });
3187
- this._withForcedRenegotiation(session, () => session.addStream(screenshareStream));
3126
+ Object.keys(this.localStreams).forEach((id) => {
3127
+ if (id === CAMERA_STREAM_ID) {
3128
+ return;
3129
+ }
3130
+ const screenshareStream = this.localStreams[id];
3131
+ if (isOfferer) {
3132
+ session.addStream(screenshareStream);
3133
+ }
3134
+ else {
3135
+ session.afterConnected.then(() => {
3136
+ this._emitServerEvent(PROTOCOL_REQUESTS.START_SCREENSHARE, {
3137
+ receiverId: session.clientId,
3138
+ streamId: screenshareStream.id,
3139
+ hasAudioTrack: !!screenshareStream.getAudioTracks().length,
3188
3140
  });
3189
- }
3190
- });
3191
- }
3141
+ this._withForcedRenegotiation(session, () => session.addStream(screenshareStream));
3142
+ });
3143
+ }
3144
+ });
3192
3145
  return session;
3193
3146
  }
3194
3147
  _cleanup(peerConnectionId) {
@@ -3325,7 +3278,6 @@ class P2pRtcManager {
3325
3278
  session = this._createP2pSession({
3326
3279
  clientId,
3327
3280
  initialBandwidth,
3328
- shouldAddLocalVideo: true,
3329
3281
  isOfferer: true,
3330
3282
  });
3331
3283
  this._negotiatePeerConnection(clientId, session);
@@ -3469,12 +3421,11 @@ class P2pRtcManager {
3469
3421
  });
3470
3422
  return bandwidth;
3471
3423
  }
3472
- _createP2pSession({ clientId, initialBandwidth, shouldAddLocalVideo = false, isOfferer = false, }) {
3424
+ _createP2pSession({ clientId, initialBandwidth, isOfferer = false, }) {
3473
3425
  const session = this._createSession({
3474
3426
  peerConnectionId: clientId,
3475
3427
  clientId,
3476
3428
  initialBandwidth,
3477
- shouldAddLocalVideo,
3478
3429
  isOfferer,
3479
3430
  });
3480
3431
  const pc = session.pc;
@@ -3482,10 +3433,7 @@ class P2pRtcManager {
3482
3433
  this._setJitterBufferTarget(pc);
3483
3434
  }
3484
3435
  const localCameraStream = this.localStreams[CAMERA_STREAM_ID];
3485
- if (shouldAddLocalVideo &&
3486
- localCameraStream &&
3487
- !localCameraStream.getVideoTracks().length &&
3488
- this._stoppedVideoTrack) {
3436
+ if (localCameraStream && !localCameraStream.getVideoTracks().length && this._stoppedVideoTrack) {
3489
3437
  pc.addTrack(this._stoppedVideoTrack, localCameraStream);
3490
3438
  }
3491
3439
  pc.onicegatheringstatechange = (event) => {
@@ -3591,7 +3539,7 @@ class P2pRtcManager {
3591
3539
  };
3592
3540
  return session;
3593
3541
  }
3594
- acceptNewStream({ streamId, clientId, shouldAddLocalVideo, }) {
3542
+ acceptNewStream({ streamId, clientId }) {
3595
3543
  let session = this._getSession(clientId);
3596
3544
  if (session && streamId !== clientId) {
3597
3545
  return session;
@@ -3607,7 +3555,6 @@ class P2pRtcManager {
3607
3555
  session = this._createP2pSession({
3608
3556
  clientId,
3609
3557
  initialBandwidth,
3610
- shouldAddLocalVideo: !!shouldAddLocalVideo,
3611
3558
  isOfferer: false,
3612
3559
  });
3613
3560
  this._emitServerEvent(RELAY_MESSAGES.READY_TO_RECEIVE_OFFER, {
@@ -3714,6 +3661,9 @@ class P2pRtcManager {
3714
3661
  hasClient(clientId) {
3715
3662
  return Object.keys(this.peerConnections).includes(clientId);
3716
3663
  }
3664
+ shouldAcceptStreamsFromBothSides() {
3665
+ return false;
3666
+ }
3717
3667
  }
3718
3668
 
3719
3669
  class KalmanFilter {
@@ -5466,14 +5416,14 @@ class VegaRtcManager {
5466
5416
  setRoomSessionId(roomSessionId) {
5467
5417
  this._roomSessionId = roomSessionId;
5468
5418
  }
5469
- disconnect(clientIdOrStreamId, _activeBreakout, eventClaim) {
5419
+ disconnect(clientId, eventClaim) {
5470
5420
  var _a;
5471
- logger$2.info("disconnect() [clientIdOrStreamId:%s, eventClaim:%s]", clientIdOrStreamId, eventClaim);
5472
- const clientState = this._clientStates.get(clientIdOrStreamId);
5421
+ logger$2.info("disconnect() [clientId:%s, eventClaim:%s]", clientId, eventClaim);
5422
+ const clientState = this._clientStates.get(clientId);
5473
5423
  if (clientState) {
5474
5424
  clientState.hasAcceptedWebcamStream = false;
5475
5425
  clientState.hasAcceptedScreenStream = false;
5476
- this._syncIncomingStreamsWithPWA(clientIdOrStreamId);
5426
+ this._syncIncomingStreamsWithPWA(clientId);
5477
5427
  }
5478
5428
  if (eventClaim) {
5479
5429
  this._eventClaim = eventClaim;
@@ -5515,7 +5465,7 @@ class VegaRtcManager {
5515
5465
  this._sendMicScore(this._micPaused ? 0 : data.out);
5516
5466
  }
5517
5467
  addNewStream(streamId, stream, audioPaused, videoPaused, beforeEffectTracks = []) {
5518
- if (streamId === "0") {
5468
+ if (streamId === CAMERA_STREAM_ID) {
5519
5469
  this._micPaused = audioPaused;
5520
5470
  this._webcamPaused = videoPaused;
5521
5471
  const videoTrack = stream.getVideoTracks()[0];
@@ -5982,7 +5932,7 @@ class VegaRtcManager {
5982
5932
  clientId,
5983
5933
  stream: webcamStream,
5984
5934
  streamId: camStreamId,
5985
- streamType: "webcam",
5935
+ streamType: STREAM_TYPES.webcam,
5986
5936
  });
5987
5937
  clientState.hasEmittedWebcamStream = true;
5988
5938
  }
@@ -5991,7 +5941,7 @@ class VegaRtcManager {
5991
5941
  clientId,
5992
5942
  stream: screenStream,
5993
5943
  streamId: screenShareStreamId,
5994
- streamType: "screenshare",
5944
+ streamType: STREAM_TYPES.screenshare,
5995
5945
  });
5996
5946
  clientState.hasEmittedScreenStream = true;
5997
5947
  }
@@ -7560,4 +7510,4 @@ var RtcEventNames;
7560
7510
  RtcEventNames["stream_added"] = "stream_added";
7561
7511
  })(RtcEventNames || (RtcEventNames = {}));
7562
7512
 
7563
- export { ADDITIONAL_SCREEN_SHARE_SETTINGS, AUDIO_SETTINGS, BandwidthTester, EVENTS, KNOCK_MESSAGES, KalmanFilter, Logger, MEDIA_JITTER_BUFFER_TARGET, NoDevicesError, P2pRtcManager, PROTOCOL_ERRORS, PROTOCOL_EVENTS, PROTOCOL_REQUESTS, PROTOCOL_RESPONSES, RELAY_MESSAGES, ReconnectManager, RtcEventNames, RtcManagerDispatcher, RtcStream, SCREEN_SHARE_SETTINGS, SCREEN_SHARE_SIMULCAST_SETTINGS, STREAM_TYPES, ServerSocket, Session, SfuV2Parser, TYPES, VIDEO_SETTINGS_HD, VIDEO_SETTINGS_SD, VIDEO_SETTINGS_VP9, VIDEO_SETTINGS_VP9_LOW_BANDWIDTH, VegaConnection, VegaMediaQualityMonitor, VegaRtcManager, addAbsCaptureTimeExtMap, addExtMap, assert, buildDeviceList, calculateStd, captureAudioSsrcMetrics, captureCandidatePairInfoMetrics, captureCommonSsrcMetrics, captureSsrcInfo, captureVideoSsrcMetrics, changeMediaDirection, cleanSdp, compareLocalDevices, createACFCalculator, createMicAnalyser, createWorker, deprioritizeH264, detectMicrophoneNotWorking, enumerate, external_stun_servers, filterMidExtension, filterMsidSemantic, fromLocation, generateByteString, getConstraints, getCurrentPeerConnections, getDeviceData, getDisplayMedia, getIssuesAndMetrics, getMediaConstraints, getMediaSettings, getMediasoupDeviceAsync, getNumFailedStatsReports, getNumFailedTrackSsrcLookups, getNumMissingTrackSsrcLookups, getPeerConnectionIndex, getStats, getStream, getUpdatedDevices, getUpdatedStats, getUserMedia, hasGetDisplayMedia, ipRegex, isMobile, issueDetectorOrMetricEnabled, maybeRejectNoH264, maybeTurnOnly, modifyMediaCapabilities, removePeerConnection, replaceTracksInStream, rtcManagerEvents, rtcStats, setClientProvider, setCodecPreferenceSDP, setPeerConnectionsForTests, setVideoBandwidthUsingSetParameters, sortCodecs, standardDeviation, startPerformanceMonitor, stopStreamTracks, subscribeIssues, subscribeStats, trackAnnotations, turnServerOverride, variance };
7513
+ export { ADDITIONAL_SCREEN_SHARE_SETTINGS, AUDIO_SETTINGS, BandwidthTester, CAMERA_STREAM_ID, EVENTS, KNOCK_MESSAGES, KalmanFilter, Logger, MEDIA_JITTER_BUFFER_TARGET, NoDevicesError, P2pRtcManager, PROTOCOL_ERRORS, PROTOCOL_EVENTS, PROTOCOL_REQUESTS, PROTOCOL_RESPONSES, RELAY_MESSAGES, ReconnectManager, RtcEventNames, RtcManagerDispatcher, SCREEN_SHARE_SETTINGS, SCREEN_SHARE_SIMULCAST_SETTINGS, STREAM_TYPES, ServerSocket, Session, SfuV2Parser, TYPES, VIDEO_SETTINGS_HD, VIDEO_SETTINGS_SD, VIDEO_SETTINGS_VP9, VIDEO_SETTINGS_VP9_LOW_BANDWIDTH, VegaConnection, VegaMediaQualityMonitor, VegaRtcManager, addAbsCaptureTimeExtMap, addExtMap, assert, buildDeviceList, calculateStd, captureAudioSsrcMetrics, captureCandidatePairInfoMetrics, captureCommonSsrcMetrics, captureSsrcInfo, captureVideoSsrcMetrics, changeMediaDirection, cleanSdp, compareLocalDevices, createACFCalculator, createMicAnalyser, createWorker, deprioritizeH264, detectMicrophoneNotWorking, enumerate, external_stun_servers, filterMidExtension, filterMsidSemantic, fromLocation, generateByteString, getConstraints, getCurrentPeerConnections, getDeviceData, getDisplayMedia, getIssuesAndMetrics, getMediaConstraints, getMediaSettings, getMediasoupDeviceAsync, getNumFailedStatsReports, getNumFailedTrackSsrcLookups, getNumMissingTrackSsrcLookups, getPeerConnectionIndex, getStats, getStream, getUpdatedDevices, getUpdatedStats, getUserMedia, hasGetDisplayMedia, ipRegex, isMobile, issueDetectorOrMetricEnabled, maybeRejectNoH264, maybeTurnOnly, modifyMediaCapabilities, removePeerConnection, replaceTracksInStream, rtcManagerEvents, rtcStats, setClientProvider, setCodecPreferenceSDP, setPeerConnectionsForTests, setVideoBandwidthUsingSetParameters, sortCodecs, standardDeviation, startPerformanceMonitor, stopStreamTracks, subscribeIssues, subscribeStats, trackAnnotations, turnServerOverride, variance };