livekit-client 1.6.0 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. package/dist/livekit-client.esm.mjs +245 -109
  2. package/dist/livekit-client.esm.mjs.map +1 -1
  3. package/dist/livekit-client.umd.js +1 -1
  4. package/dist/livekit-client.umd.js.map +1 -1
  5. package/dist/src/room/PCTransport.d.ts +7 -1
  6. package/dist/src/room/PCTransport.d.ts.map +1 -1
  7. package/dist/src/room/RTCEngine.d.ts +6 -1
  8. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  9. package/dist/src/room/Room.d.ts +1 -1
  10. package/dist/src/room/Room.d.ts.map +1 -1
  11. package/dist/src/room/events.d.ts +1 -0
  12. package/dist/src/room/events.d.ts.map +1 -1
  13. package/dist/src/room/participant/LocalParticipant.d.ts +3 -2
  14. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  15. package/dist/src/room/track/LocalTrack.d.ts +1 -0
  16. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  17. package/dist/src/room/track/Track.d.ts.map +1 -1
  18. package/dist/src/room/types.d.ts +1 -0
  19. package/dist/src/room/types.d.ts.map +1 -1
  20. package/dist/ts4.2/src/room/PCTransport.d.ts +7 -1
  21. package/dist/ts4.2/src/room/RTCEngine.d.ts +6 -1
  22. package/dist/ts4.2/src/room/Room.d.ts +1 -1
  23. package/dist/ts4.2/src/room/events.d.ts +1 -0
  24. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +3 -2
  25. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +1 -0
  26. package/dist/ts4.2/src/room/types.d.ts +1 -0
  27. package/package.json +15 -15
  28. package/src/room/PCTransport.ts +11 -1
  29. package/src/room/RTCEngine.ts +76 -23
  30. package/src/room/Room.ts +42 -12
  31. package/src/room/events.ts +1 -0
  32. package/src/room/participant/LocalParticipant.ts +43 -19
  33. package/src/room/participant/RemoteParticipant.ts +5 -5
  34. package/src/room/track/LocalTrack.ts +19 -1
  35. package/src/room/track/Track.ts +21 -5
  36. package/src/room/types.ts +1 -0
@@ -19,7 +19,11 @@ function getDefaultExportFromCjs (x) {
19
19
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
20
20
  }
21
21
 
22
- var loglevel = {exports: {}};
22
+ var loglevelExports = {};
23
+ var loglevel = {
24
+ get exports(){ return loglevelExports; },
25
+ set exports(v){ loglevelExports = v; },
26
+ };
23
27
 
24
28
  /*
25
29
  * loglevel - https://github.com/pimterry/loglevel
@@ -294,7 +298,7 @@ var LogLevel;
294
298
  LogLevel[LogLevel["error"] = 4] = "error";
295
299
  LogLevel[LogLevel["silent"] = 5] = "silent";
296
300
  })(LogLevel || (LogLevel = {}));
297
- const livekitLogger = loglevel.exports.getLogger('livekit');
301
+ const livekitLogger = loglevelExports.getLogger('livekit');
298
302
  livekitLogger.setLevel(LogLevel.info);
299
303
  function setLogLevel(level) {
300
304
  livekitLogger.setLevel(level);
@@ -1501,7 +1505,11 @@ Long.fromBytesBE = function fromBytesBE(bytes, unsigned) {
1501
1505
  return new Long(bytes[4] << 24 | bytes[5] << 16 | bytes[6] << 8 | bytes[7], bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3], unsigned);
1502
1506
  };
1503
1507
 
1504
- var minimal$1 = {exports: {}};
1508
+ var minimalExports = {};
1509
+ var minimal$1 = {
1510
+ get exports(){ return minimalExports; },
1511
+ set exports(v){ minimalExports = v; },
1512
+ };
1505
1513
 
1506
1514
  var indexMinimal = {};
1507
1515
 
@@ -3986,7 +3994,7 @@ var roots = {};
3986
3994
 
3987
3995
  module.exports = indexMinimal;
3988
3996
  })(minimal$1);
3989
- var _m0 = /*@__PURE__*/getDefaultExportFromCjs(minimal$1.exports);
3997
+ var _m0 = /*@__PURE__*/getDefaultExportFromCjs(minimalExports);
3990
3998
 
3991
3999
  /* eslint-disable */
3992
4000
  var globalThis$3 = (() => {
@@ -7228,17 +7236,17 @@ function fixNegotiationNeeded(window, browserDetails) {
7228
7236
 
7229
7237
  var chromeShim = /*#__PURE__*/Object.freeze({
7230
7238
  __proto__: null,
7231
- shimMediaStream: shimMediaStream,
7232
- shimOnTrack: shimOnTrack$1,
7239
+ fixNegotiationNeeded: fixNegotiationNeeded,
7240
+ shimAddTrackRemoveTrack: shimAddTrackRemoveTrack,
7241
+ shimAddTrackRemoveTrackWithNative: shimAddTrackRemoveTrackWithNative,
7242
+ shimGetDisplayMedia: shimGetDisplayMedia$1,
7233
7243
  shimGetSendersWithDtmf: shimGetSendersWithDtmf,
7234
7244
  shimGetStats: shimGetStats,
7235
- shimSenderReceiverGetStats: shimSenderReceiverGetStats,
7236
- shimAddTrackRemoveTrackWithNative: shimAddTrackRemoveTrackWithNative,
7237
- shimAddTrackRemoveTrack: shimAddTrackRemoveTrack,
7238
- shimPeerConnection: shimPeerConnection$1,
7239
- fixNegotiationNeeded: fixNegotiationNeeded,
7240
7245
  shimGetUserMedia: shimGetUserMedia$2,
7241
- shimGetDisplayMedia: shimGetDisplayMedia$1
7246
+ shimMediaStream: shimMediaStream,
7247
+ shimOnTrack: shimOnTrack$1,
7248
+ shimPeerConnection: shimPeerConnection$1,
7249
+ shimSenderReceiverGetStats: shimSenderReceiverGetStats
7242
7250
  });
7243
7251
 
7244
7252
  /*
@@ -7592,18 +7600,18 @@ function shimCreateAnswer(window) {
7592
7600
 
7593
7601
  var firefoxShim = /*#__PURE__*/Object.freeze({
7594
7602
  __proto__: null,
7603
+ shimAddTransceiver: shimAddTransceiver,
7604
+ shimCreateAnswer: shimCreateAnswer,
7605
+ shimCreateOffer: shimCreateOffer,
7606
+ shimGetDisplayMedia: shimGetDisplayMedia,
7607
+ shimGetParameters: shimGetParameters,
7608
+ shimGetUserMedia: shimGetUserMedia$1,
7595
7609
  shimOnTrack: shimOnTrack,
7596
7610
  shimPeerConnection: shimPeerConnection,
7597
- shimSenderGetStats: shimSenderGetStats,
7611
+ shimRTCDataChannel: shimRTCDataChannel,
7598
7612
  shimReceiverGetStats: shimReceiverGetStats,
7599
7613
  shimRemoveStream: shimRemoveStream,
7600
- shimRTCDataChannel: shimRTCDataChannel,
7601
- shimAddTransceiver: shimAddTransceiver,
7602
- shimGetParameters: shimGetParameters,
7603
- shimCreateOffer: shimCreateOffer,
7604
- shimCreateAnswer: shimCreateAnswer,
7605
- shimGetUserMedia: shimGetUserMedia$1,
7606
- shimGetDisplayMedia: shimGetDisplayMedia
7614
+ shimSenderGetStats: shimSenderGetStats
7607
7615
  });
7608
7616
 
7609
7617
  /*
@@ -7925,18 +7933,22 @@ function shimAudioContext(window) {
7925
7933
 
7926
7934
  var safariShim = /*#__PURE__*/Object.freeze({
7927
7935
  __proto__: null,
7928
- shimLocalStreamsAPI: shimLocalStreamsAPI,
7929
- shimRemoteStreamsAPI: shimRemoteStreamsAPI,
7936
+ shimAudioContext: shimAudioContext,
7930
7937
  shimCallbacksAPI: shimCallbacksAPI,
7931
- shimGetUserMedia: shimGetUserMedia,
7932
7938
  shimConstraints: shimConstraints,
7933
- shimRTCIceServerUrls: shimRTCIceServerUrls,
7934
- shimTrackEventTransceiver: shimTrackEventTransceiver,
7935
7939
  shimCreateOfferLegacy: shimCreateOfferLegacy,
7936
- shimAudioContext: shimAudioContext
7940
+ shimGetUserMedia: shimGetUserMedia,
7941
+ shimLocalStreamsAPI: shimLocalStreamsAPI,
7942
+ shimRTCIceServerUrls: shimRTCIceServerUrls,
7943
+ shimRemoteStreamsAPI: shimRemoteStreamsAPI,
7944
+ shimTrackEventTransceiver: shimTrackEventTransceiver
7937
7945
  });
7938
7946
 
7939
- var sdp$1 = {exports: {}};
7947
+ var sdpExports = {};
7948
+ var sdp$1 = {
7949
+ get exports(){ return sdpExports; },
7950
+ set exports(v){ sdpExports = v; },
7951
+ };
7940
7952
 
7941
7953
  /* eslint-env node */
7942
7954
  (function (module) {
@@ -8668,12 +8680,12 @@ var sdp$1 = {exports: {}};
8668
8680
  module.exports = SDPUtils;
8669
8681
  }
8670
8682
  })(sdp$1);
8671
- var SDPUtils = sdp$1.exports;
8683
+ var SDPUtils = sdpExports;
8672
8684
 
8673
8685
  var sdp = /*#__PURE__*/_mergeNamespaces({
8674
8686
  __proto__: null,
8675
8687
  default: SDPUtils
8676
- }, [sdp$1.exports]);
8688
+ }, [sdpExports]);
8677
8689
 
8678
8690
  /*
8679
8691
  * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
@@ -9063,13 +9075,13 @@ function shimParameterlessSetLocalDescription(window, browserDetails) {
9063
9075
 
9064
9076
  var commonShim = /*#__PURE__*/Object.freeze({
9065
9077
  __proto__: null,
9066
- shimRTCIceCandidate: shimRTCIceCandidate,
9067
- shimMaxMessageSize: shimMaxMessageSize,
9068
- shimSendThrowTypeError: shimSendThrowTypeError,
9069
- shimConnectionState: shimConnectionState,
9070
9078
  removeExtmapAllowMixed: removeExtmapAllowMixed,
9071
9079
  shimAddIceCandidateNullOrEmpty: shimAddIceCandidateNullOrEmpty,
9072
- shimParameterlessSetLocalDescription: shimParameterlessSetLocalDescription
9080
+ shimConnectionState: shimConnectionState,
9081
+ shimMaxMessageSize: shimMaxMessageSize,
9082
+ shimParameterlessSetLocalDescription: shimParameterlessSetLocalDescription,
9083
+ shimRTCIceCandidate: shimRTCIceCandidate,
9084
+ shimSendThrowTypeError: shimSendThrowTypeError
9073
9085
  });
9074
9086
 
9075
9087
  /*
@@ -12558,6 +12570,7 @@ var EngineEvent;
12558
12570
  EngineEvent["Restarting"] = "restarting";
12559
12571
  EngineEvent["Restarted"] = "restarted";
12560
12572
  EngineEvent["SignalResumed"] = "signalResumed";
12573
+ EngineEvent["Closing"] = "closing";
12561
12574
  EngineEvent["MediaTrackAdded"] = "mediaTrackAdded";
12562
12575
  EngineEvent["ActiveSpeakersUpdate"] = "activeSpeakersUpdate";
12563
12576
  EngineEvent["DataPacketReceived"] = "dataPacketReceived";
@@ -12636,7 +12649,11 @@ function computeBitrate(currentStats, prevStats) {
12636
12649
  return (bytesNow - bytesPrev) * 8 * 1000 / (currentStats.timestamp - prevStats.timestamp);
12637
12650
  }
12638
12651
 
12639
- var uaParser = {exports: {}};
12652
+ var uaParserExports = {};
12653
+ var uaParser = {
12654
+ get exports(){ return uaParserExports; },
12655
+ set exports(v){ uaParserExports = v; },
12656
+ };
12640
12657
 
12641
12658
  (function (module, exports) {
12642
12659
  /////////////////////////////////////////////////////////////////////////////////
@@ -13316,10 +13333,10 @@ var uaParser = {exports: {}};
13316
13333
  };
13317
13334
  }
13318
13335
  })(typeof window === 'object' ? window : commonjsGlobal);
13319
- })(uaParser, uaParser.exports);
13320
- var UAParser = uaParser.exports;
13336
+ })(uaParser, uaParserExports);
13337
+ var UAParser = uaParserExports;
13321
13338
 
13322
- var version$1 = "1.6.0";
13339
+ var version$1 = "1.6.2";
13323
13340
 
13324
13341
  const version = version$1;
13325
13342
  const protocolVersion = 8;
@@ -13906,7 +13923,11 @@ class DeviceManager {
13906
13923
  DeviceManager.mediaDeviceKinds = ['audioinput', 'audiooutput', 'videoinput'];
13907
13924
  DeviceManager.userMediaPromiseMap = new Map();
13908
13925
 
13909
- var events = {exports: {}};
13926
+ var eventsExports = {};
13927
+ var events = {
13928
+ get exports(){ return eventsExports; },
13929
+ set exports(v){ eventsExports = v; },
13930
+ };
13910
13931
 
13911
13932
  var R = typeof Reflect === 'object' ? Reflect : null;
13912
13933
  var ReflectApply = R && typeof R.apply === 'function' ? R.apply : function ReflectApply(target, receiver, args) {
@@ -13934,7 +13955,7 @@ function EventEmitter() {
13934
13955
  EventEmitter.init.call(this);
13935
13956
  }
13936
13957
  events.exports = EventEmitter;
13937
- events.exports.once = once;
13958
+ eventsExports.once = once;
13938
13959
 
13939
13960
  // Backwards-compat with node 0.10.x
13940
13961
  EventEmitter.EventEmitter = EventEmitter;
@@ -14290,7 +14311,7 @@ const BACKGROUND_REACTION_DELAY = 5000;
14290
14311
  // keep old audio elements when detached, we would re-use them since on iOS
14291
14312
  // Safari tracks which audio elements have been "blessed" by the user.
14292
14313
  const recycledElements = [];
14293
- class Track extends events.exports.EventEmitter {
14314
+ class Track extends eventsExports.EventEmitter {
14294
14315
  constructor(mediaTrack, kind) {
14295
14316
  super();
14296
14317
  this.attachedElements = [];
@@ -14367,12 +14388,21 @@ class Track extends events.exports.EventEmitter {
14367
14388
  // the element's srcObject was set to something else out of band.
14368
14389
  // we'll want to re-attach it in that case
14369
14390
  attachToElement(this._mediaStreamTrack, element);
14370
- if (element instanceof HTMLAudioElement) {
14391
+ // handle auto playback failures
14392
+ const allMediaStreamTracks = element.srcObject.getTracks();
14393
+ if (allMediaStreamTracks.some(tr => tr.kind === 'audio')) {
14371
14394
  // manually play audio to detect audio playback status
14372
14395
  element.play().then(() => {
14373
14396
  this.emit(TrackEvent.AudioPlaybackStarted);
14374
14397
  }).catch(e => {
14375
14398
  this.emit(TrackEvent.AudioPlaybackFailed, e);
14399
+ // If audio playback isn't allowed make sure we still play back the video
14400
+ if (element && allMediaStreamTracks.some(tr => tr.kind === 'video') && e.name === 'NotAllowedError') {
14401
+ element.muted = true;
14402
+ element.play().catch(() => {
14403
+ // catch for Safari, exceeded options at this point to automatically play the media element
14404
+ });
14405
+ }
14376
14406
  });
14377
14407
  }
14378
14408
  this.emit(TrackEvent.ElementAttached, element);
@@ -14460,6 +14490,12 @@ function attachToElement(track, element) {
14460
14490
  });
14461
14491
  mediaStream.addTrack(track);
14462
14492
  }
14493
+ element.autoplay = true;
14494
+ // In case there are no audio tracks present on the mediastream, we set the element as muted to ensure autoplay works
14495
+ element.muted = mediaStream.getAudioTracks().length === 0;
14496
+ if (element instanceof HTMLVideoElement) {
14497
+ element.playsInline = true;
14498
+ }
14463
14499
  // avoid flicker
14464
14500
  if (element.srcObject !== mediaStream) {
14465
14501
  element.srcObject = mediaStream;
@@ -14481,10 +14517,6 @@ function attachToElement(track, element) {
14481
14517
  }, 0);
14482
14518
  }
14483
14519
  }
14484
- element.autoplay = true;
14485
- if (element instanceof HTMLVideoElement) {
14486
- element.playsInline = true;
14487
- }
14488
14520
  }
14489
14521
  /** @internal */
14490
14522
  function detachTrack(track, element) {
@@ -14589,6 +14621,7 @@ function detachTrack(track, element) {
14589
14621
  Track.streamStateFromProto = streamStateFromProto;
14590
14622
  })(Track || (Track = {}));
14591
14623
 
14624
+ const defaultDimensionsTimeout = 2 * 1000;
14592
14625
  class LocalTrack extends Track {
14593
14626
  /**
14594
14627
  *
@@ -14638,6 +14671,21 @@ class LocalTrack extends Track {
14638
14671
  get isUserProvided() {
14639
14672
  return this.providedByUser;
14640
14673
  }
14674
+ async waitForDimensions() {
14675
+ let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultDimensionsTimeout;
14676
+ if (this.kind === Track.Kind.Audio) {
14677
+ throw new Error('cannot get dimensions for audio tracks');
14678
+ }
14679
+ const started = Date.now();
14680
+ while (Date.now() - started < timeout) {
14681
+ const dims = this.dimensions;
14682
+ if (dims) {
14683
+ return dims;
14684
+ }
14685
+ await sleep(50);
14686
+ }
14687
+ throw new TrackInvalidError('unable to get track dimensions after timeout');
14688
+ }
14641
14689
  /**
14642
14690
  * @returns DeviceID of the device that is currently being used for this track
14643
14691
  */
@@ -15818,7 +15866,7 @@ function isElementInViewport(el) {
15818
15866
  return top < window.pageYOffset + window.innerHeight && left < window.pageXOffset + window.innerWidth && top + height > window.pageYOffset && left + width > window.pageXOffset && !hidden && (opacity !== '' ? parseFloat(opacity) > 0 : true) && display !== 'none';
15819
15867
  }
15820
15868
 
15821
- class TrackPublication extends events.exports.EventEmitter {
15869
+ class TrackPublication extends eventsExports.EventEmitter {
15822
15870
  constructor(kind, id, name) {
15823
15871
  super();
15824
15872
  this.metadataMuted = false;
@@ -16069,7 +16117,7 @@ function qualityFromProto(q) {
16069
16117
  return ConnectionQuality.Unknown;
16070
16118
  }
16071
16119
  }
16072
- class Participant extends events.exports.EventEmitter {
16120
+ class Participant extends eventsExports.EventEmitter {
16073
16121
  /** @internal */
16074
16122
  constructor(sid, identity, name, metadata) {
16075
16123
  super();
@@ -16887,10 +16935,6 @@ class RemoteParticipant extends Participant {
16887
16935
  }
16888
16936
  validTracks.set(ti.sid, publication);
16889
16937
  });
16890
- // always emit events for new publications, Room will not forward them unless it's ready
16891
- newTracks.forEach(publication => {
16892
- this.emit(ParticipantEvent.TrackPublished, publication);
16893
- });
16894
16938
  // detect removed tracks
16895
16939
  this.tracks.forEach(publication => {
16896
16940
  if (!validTracks.has(publication.trackSid)) {
@@ -16901,6 +16945,10 @@ class RemoteParticipant extends Participant {
16901
16945
  this.unpublishTrack(publication.trackSid, true);
16902
16946
  }
16903
16947
  });
16948
+ // always emit events for new publications, Room will not forward them unless it's ready
16949
+ newTracks.forEach(publication => {
16950
+ this.emit(ParticipantEvent.TrackPublished, publication);
16951
+ });
16904
16952
  }
16905
16953
  /** @internal */
16906
16954
  unpublishTrack(sid, sendUnpublish) {
@@ -17243,7 +17291,7 @@ class LocalParticipant extends Participant {
17243
17291
  } else if (track && track.track) {
17244
17292
  // screenshare cannot be muted, unpublish instead
17245
17293
  if (source === Track.Source.ScreenShare) {
17246
- track = this.unpublishTrack(track.track);
17294
+ track = await this.unpublishTrack(track.track);
17247
17295
  const screenAudioTrack = this.getTrack(Track.Source.ScreenShareAudio);
17248
17296
  if (screenAudioTrack && screenAudioTrack.track) {
17249
17297
  this.unpublishTrack(screenAudioTrack.track);
@@ -17384,7 +17432,7 @@ class LocalParticipant extends Participant {
17384
17432
  * @param options
17385
17433
  */
17386
17434
  async publishTrack(track, options) {
17387
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
17435
+ var _a, _b, _c, _d, _e;
17388
17436
  // convert raw media track into audio or video track
17389
17437
  if (track instanceof MediaStreamTrack) {
17390
17438
  switch (track.kind) {
@@ -17475,18 +17523,24 @@ class LocalParticipant extends Participant {
17475
17523
  let encodings;
17476
17524
  let simEncodings;
17477
17525
  if (track.kind === Track.Kind.Video) {
17478
- // TODO: support react native, which doesn't expose getSettings
17479
- const settings = track.mediaStreamTrack.getSettings();
17480
- const width = (_d = settings.width) !== null && _d !== void 0 ? _d : (_e = track.dimensions) === null || _e === void 0 ? void 0 : _e.width;
17481
- const height = (_f = settings.height) !== null && _f !== void 0 ? _f : (_g = track.dimensions) === null || _g === void 0 ? void 0 : _g.height;
17526
+ let dims = {
17527
+ width: 0,
17528
+ height: 0
17529
+ };
17530
+ try {
17531
+ dims = await track.waitForDimensions();
17532
+ } catch (e) {
17533
+ // log failure
17534
+ livekitLogger.error('could not determine track dimensions');
17535
+ }
17482
17536
  // width and height should be defined for video
17483
- req.width = width !== null && width !== void 0 ? width : 0;
17484
- req.height = height !== null && height !== void 0 ? height : 0;
17537
+ req.width = dims.width;
17538
+ req.height = dims.height;
17485
17539
  // for svc codecs, disable simulcast and use vp8 for backup codec
17486
17540
  if (track instanceof LocalVideoTrack) {
17487
17541
  if ((opts === null || opts === void 0 ? void 0 : opts.videoCodec) === 'av1') {
17488
17542
  // set scalabilityMode to 'L3T3' by default
17489
- opts.scalabilityMode = (_h = opts.scalabilityMode) !== null && _h !== void 0 ? _h : 'L3T3';
17543
+ opts.scalabilityMode = (_d = opts.scalabilityMode) !== null && _d !== void 0 ? _d : 'L3T3';
17490
17544
  }
17491
17545
  // set up backup
17492
17546
  if (opts.videoCodec && opts.backupCodec && opts.videoCodec !== opts.backupCodec.codec) {
@@ -17504,7 +17558,7 @@ class LocalParticipant extends Participant {
17504
17558
  }];
17505
17559
  }
17506
17560
  }
17507
- encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, width, height, opts);
17561
+ encodings = computeVideoEncodings(track.source === Track.Source.ScreenShare, dims.width, dims.height, opts);
17508
17562
  req.layers = videoLayersFromEncodings(req.width, req.height, simEncodings !== null && simEncodings !== void 0 ? simEncodings : encodings);
17509
17563
  } else if (track.kind === Track.Kind.Audio && opts.audioBitrate) {
17510
17564
  encodings = [{
@@ -17528,7 +17582,7 @@ class LocalParticipant extends Participant {
17528
17582
  });
17529
17583
  // store RTPSender
17530
17584
  track.sender = await this.engine.createSender(track, opts, encodings);
17531
- if (track.codec === 'av1' && encodings && ((_j = encodings[0]) === null || _j === void 0 ? void 0 : _j.maxBitrate)) {
17585
+ if (track.codec === 'av1' && encodings && ((_e = encodings[0]) === null || _e === void 0 ? void 0 : _e.maxBitrate)) {
17532
17586
  this.engine.publisher.setTrackCodecBitrate(req.cid, track.codec, encodings[0].maxBitrate / 1000);
17533
17587
  }
17534
17588
  this.engine.negotiate();
@@ -17597,7 +17651,7 @@ class LocalParticipant extends Participant {
17597
17651
  trackInfo: ti
17598
17652
  });
17599
17653
  }
17600
- unpublishTrack(track, stopOnUnpublish) {
17654
+ async unpublishTrack(track, stopOnUnpublish) {
17601
17655
  var _a, _b;
17602
17656
  // look through all published tracks to find the right ones
17603
17657
  const publication = this.getPublicationForTrack(track);
@@ -17642,7 +17696,7 @@ class LocalParticipant extends Participant {
17642
17696
  method: 'unpublishTrack'
17643
17697
  });
17644
17698
  } finally {
17645
- this.engine.negotiate();
17699
+ await this.engine.negotiate();
17646
17700
  }
17647
17701
  }
17648
17702
  track.sender = undefined;
@@ -17660,15 +17714,25 @@ class LocalParticipant extends Participant {
17660
17714
  publication.setTrack(undefined);
17661
17715
  return publication;
17662
17716
  }
17663
- unpublishTracks(tracks) {
17664
- const publications = [];
17665
- tracks.forEach(track => {
17666
- const pub = this.unpublishTrack(track);
17667
- if (pub) {
17668
- publications.push(pub);
17717
+ async unpublishTracks(tracks) {
17718
+ const results = await Promise.all(tracks.map(track => this.unpublishTrack(track)));
17719
+ return results.filter(track => track instanceof LocalTrackPublication);
17720
+ }
17721
+ async republishAllTracks(options) {
17722
+ const localPubs = [];
17723
+ this.tracks.forEach(pub => {
17724
+ if (pub.track) {
17725
+ if (options) {
17726
+ pub.options = _objectSpread2(_objectSpread2({}, pub.options), options);
17727
+ }
17728
+ localPubs.push(pub);
17669
17729
  }
17670
17730
  });
17671
- return publications;
17731
+ await Promise.all(localPubs.map(async pub => {
17732
+ const track = pub.track;
17733
+ await this.unpublishTrack(track, false);
17734
+ await this.publishTrack(track, pub.options);
17735
+ }));
17672
17736
  }
17673
17737
  /**
17674
17738
  * Publish a new data payload to the room. Data will be forwarded to each
@@ -18334,7 +18398,11 @@ const roomConnectOptionDefaults = {
18334
18398
 
18335
18399
  var parser$1 = {};
18336
18400
 
18337
- var grammar$2 = {exports: {}};
18401
+ var grammarExports = {};
18402
+ var grammar$2 = {
18403
+ get exports(){ return grammarExports; },
18404
+ set exports(v){ grammarExports = v; },
18405
+ };
18338
18406
 
18339
18407
  var grammar$1 = grammar$2.exports = {
18340
18408
  v: [{
@@ -18804,7 +18872,7 @@ Object.keys(grammar$1).forEach(function (key) {
18804
18872
  location[obj.push].push(keyLocation);
18805
18873
  }
18806
18874
  };
18807
- var grammar = grammar$2.exports;
18875
+ var grammar = grammarExports;
18808
18876
  var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
18809
18877
  exports.parse = function (sdp) {
18810
18878
  var session = {},
@@ -18888,7 +18956,7 @@ Object.keys(grammar$1).forEach(function (key) {
18888
18956
  };
18889
18957
  })(parser$1);
18890
18958
 
18891
- var grammar = grammar$2.exports;
18959
+ var grammar = grammarExports;
18892
18960
 
18893
18961
  // customized util.format - discards excess arguments and can void middle ones
18894
18962
  var formatRegExp = /%[sdv%]/g;
@@ -19002,9 +19070,14 @@ parser.parseRemoteCandidates;
19002
19070
  parser.parseImageAttributes;
19003
19071
  parser.parseSimulcastStreamList;
19004
19072
 
19073
+ const PCEvents = {
19074
+ NegotiationStarted: 'negotiationStarted',
19075
+ NegotiationComplete: 'negotiationComplete'
19076
+ };
19005
19077
  /** @internal */
19006
- class PCTransport {
19078
+ class PCTransport extends eventsExports {
19007
19079
  constructor(config) {
19080
+ super();
19008
19081
  this.pendingCandidates = [];
19009
19082
  this.restartingIce = false;
19010
19083
  this.renegotiate = false;
@@ -19012,6 +19085,7 @@ class PCTransport {
19012
19085
  this.remoteStereoMids = [];
19013
19086
  // debounced negotiate interface
19014
19087
  this.negotiate = r(onError => {
19088
+ this.emit(PCEvents.NegotiationStarted);
19015
19089
  try {
19016
19090
  this.createAndSendOffer();
19017
19091
  } catch (e) {
@@ -19046,6 +19120,8 @@ class PCTransport {
19046
19120
  if (this.renegotiate) {
19047
19121
  this.renegotiate = false;
19048
19122
  this.createAndSendOffer();
19123
+ } else if (sd.type === 'answer') {
19124
+ this.emit(PCEvents.NegotiationComplete);
19049
19125
  }
19050
19126
  }
19051
19127
  async createAndSendOffer(options) {
@@ -19244,7 +19320,7 @@ var PCState;
19244
19320
  PCState[PCState["Closed"] = 4] = "Closed";
19245
19321
  })(PCState || (PCState = {}));
19246
19322
  /** @internal */
19247
- class RTCEngine extends events.exports.EventEmitter {
19323
+ class RTCEngine extends eventsExports.EventEmitter {
19248
19324
  get isClosed() {
19249
19325
  return this._isClosed;
19250
19326
  }
@@ -19402,8 +19478,13 @@ class RTCEngine extends events.exports.EventEmitter {
19402
19478
  }
19403
19479
  async close() {
19404
19480
  const unlock = await this.closingLock.lock();
19481
+ if (this.isClosed) {
19482
+ unlock();
19483
+ return;
19484
+ }
19405
19485
  try {
19406
19486
  this._isClosed = true;
19487
+ this.emit(EngineEvent.Closing);
19407
19488
  this.removeAllListeners();
19408
19489
  this.deregisterOnLineListener();
19409
19490
  this.clearPendingReconnect();
@@ -19969,43 +20050,77 @@ class RTCEngine extends events.exports.EventEmitter {
19969
20050
  this.reliableDC.send(msg);
19970
20051
  }
19971
20052
  }
19972
- async ensurePublisherConnected(kind) {
19973
- var _a, _b;
19974
- if (!this.subscriberPrimary) {
19975
- return;
19976
- }
19977
- if (!this.publisher) {
19978
- throw new ConnectionError('publisher connection not set');
20053
+ /**
20054
+ * @internal
20055
+ */
20056
+ async ensureDataTransportConnected(kind) {
20057
+ let subscriber = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.subscriberPrimary;
20058
+ var _a, _b, _c;
20059
+ const transport = subscriber ? this.subscriber : this.publisher;
20060
+ const transportName = subscriber ? 'Subscriber' : 'Publisher';
20061
+ if (!transport) {
20062
+ throw new ConnectionError("".concat(transportName, " connection not set"));
19979
20063
  }
19980
- if (!this.publisher.isICEConnected && this.publisher.pc.iceConnectionState !== 'checking') {
20064
+ if (!subscriber && !((_a = this.publisher) === null || _a === void 0 ? void 0 : _a.isICEConnected) && ((_b = this.publisher) === null || _b === void 0 ? void 0 : _b.pc.iceConnectionState) !== 'checking') {
19981
20065
  // start negotiation
19982
20066
  this.negotiate();
19983
20067
  }
19984
- const targetChannel = this.dataChannelForKind(kind);
20068
+ const targetChannel = this.dataChannelForKind(kind, subscriber);
19985
20069
  if ((targetChannel === null || targetChannel === void 0 ? void 0 : targetChannel.readyState) === 'open') {
19986
20070
  return;
19987
20071
  }
19988
- // wait until publisher ICE connected
20072
+ // wait until ICE connected
19989
20073
  const endTime = new Date().getTime() + this.peerConnectionTimeout;
19990
20074
  while (new Date().getTime() < endTime) {
19991
- if (this.publisher.isICEConnected && ((_a = this.dataChannelForKind(kind)) === null || _a === void 0 ? void 0 : _a.readyState) === 'open') {
20075
+ if (transport.isICEConnected && ((_c = this.dataChannelForKind(kind, subscriber)) === null || _c === void 0 ? void 0 : _c.readyState) === 'open') {
19992
20076
  return;
19993
20077
  }
19994
20078
  await sleep(50);
19995
20079
  }
19996
- throw new ConnectionError("could not establish publisher connection, state ".concat((_b = this.publisher) === null || _b === void 0 ? void 0 : _b.pc.iceConnectionState));
20080
+ throw new ConnectionError("could not establish ".concat(transportName, " connection, state: ").concat(transport.pc.iceConnectionState));
20081
+ }
20082
+ async ensurePublisherConnected(kind) {
20083
+ await this.ensureDataTransportConnected(kind, false);
19997
20084
  }
19998
20085
  /** @internal */
19999
20086
  negotiate() {
20000
- if (!this.publisher) {
20001
- return;
20002
- }
20003
- this.hasPublished = true;
20004
- this.publisher.negotiate(e => {
20005
- if (e instanceof NegotiationError) {
20006
- this.fullReconnectOnNext = true;
20087
+ // observe signal state
20088
+ return new Promise((resolve, reject) => {
20089
+ if (!this.publisher) {
20090
+ reject(new NegotiationError('publisher is not defined'));
20091
+ return;
20007
20092
  }
20008
- this.handleDisconnect('negotiation');
20093
+ this.hasPublished = true;
20094
+ const handleClosed = () => {
20095
+ livekitLogger.debug('engine disconnected while negotiation was ongoing');
20096
+ cleanup();
20097
+ resolve();
20098
+ return;
20099
+ };
20100
+ this.on(EngineEvent.Closing, handleClosed);
20101
+ const negotiationTimeout = setTimeout(() => {
20102
+ reject('negotiation timed out');
20103
+ this.handleDisconnect('negotiation');
20104
+ }, this.peerConnectionTimeout);
20105
+ const cleanup = () => {
20106
+ clearTimeout(negotiationTimeout);
20107
+ this.off(EngineEvent.Closing, handleClosed);
20108
+ };
20109
+ this.publisher.once(PCEvents.NegotiationStarted, () => {
20110
+ var _a;
20111
+ (_a = this.publisher) === null || _a === void 0 ? void 0 : _a.once(PCEvents.NegotiationComplete, () => {
20112
+ cleanup();
20113
+ resolve();
20114
+ });
20115
+ });
20116
+ this.publisher.negotiate(e => {
20117
+ cleanup();
20118
+ reject(e);
20119
+ if (e instanceof NegotiationError) {
20120
+ this.fullReconnectOnNext = true;
20121
+ }
20122
+ this.handleDisconnect('negotiation');
20123
+ });
20009
20124
  });
20010
20125
  }
20011
20126
  dataChannelForKind(kind, sub) {
@@ -20093,7 +20208,7 @@ const RoomState = ConnectionState;
20093
20208
  *
20094
20209
  * @noInheritDoc
20095
20210
  */
20096
- class Room extends events.exports.EventEmitter {
20211
+ class Room extends eventsExports.EventEmitter {
20097
20212
  /**
20098
20213
  * Creates a new Room, the primary construct for a LiveKit session.
20099
20214
  * @param options
@@ -20117,13 +20232,17 @@ class Room extends events.exports.EventEmitter {
20117
20232
  this.metadata = undefined;
20118
20233
  this._isRecording = false;
20119
20234
  this.audioEnabled = true;
20120
- this.connect = (url, token, opts) => {
20235
+ this.connect = async (url, token, opts) => {
20236
+ // In case a disconnect called happened right before the connect call, make sure the disconnect is completed first by awaiting its lock
20237
+ const unlockDisconnect = await this.disconnectLock.lock();
20121
20238
  if (this.state === ConnectionState.Connected) {
20122
20239
  // when the state is reconnecting or connected, this function returns immediately
20123
20240
  livekitLogger.info("already connected to room ".concat(this.name));
20241
+ unlockDisconnect();
20124
20242
  return Promise.resolve();
20125
20243
  }
20126
20244
  if (this.connectFuture) {
20245
+ unlockDisconnect();
20127
20246
  return this.connectFuture.promise;
20128
20247
  }
20129
20248
  this.setAndEmitConnectionState(ConnectionState.Connecting);
@@ -20132,6 +20251,8 @@ class Room extends events.exports.EventEmitter {
20132
20251
  if (!this.abortController || this.abortController.signal.aborted) {
20133
20252
  this.abortController = new AbortController();
20134
20253
  }
20254
+ // at this point the intention to connect has been signalled so we can allow cancelling of the connection via disconnect() again
20255
+ unlockDisconnect();
20135
20256
  if (this.state === ConnectionState.Reconnecting) {
20136
20257
  livekitLogger.info('Reconnection attempt replaced by new connection attempt');
20137
20258
  // make sure we close and recreate the existing engine in order to get rid of any potentially ongoing reconnection attempts
@@ -20697,7 +20818,10 @@ class Room extends events.exports.EventEmitter {
20697
20818
  });
20698
20819
  });
20699
20820
  try {
20700
- await Promise.all(elements.map(e => e.play()));
20821
+ await Promise.all(elements.map(e => {
20822
+ e.muted = false;
20823
+ return e.play();
20824
+ }));
20701
20825
  this.handleAudioPlaybackStarted();
20702
20826
  } catch (err) {
20703
20827
  this.handleAudioPlaybackFailed(err);
@@ -20887,7 +21011,7 @@ class Room extends events.exports.EventEmitter {
20887
21011
  this.emitWhenConnected(RoomEvent.ParticipantDisconnected, participant);
20888
21012
  }
20889
21013
  async acquireAudioContext() {
20890
- var _a;
21014
+ var _a, _b;
20891
21015
  if (typeof this.options.expWebAudioMix !== 'boolean' && this.options.expWebAudioMix.audioContext) {
20892
21016
  // override audio context with custom audio context if supplied by user
20893
21017
  this.audioContext = this.options.expWebAudioMix.audioContext;
@@ -20900,6 +21024,11 @@ class Room extends events.exports.EventEmitter {
20900
21024
  if (this.options.expWebAudioMix) {
20901
21025
  this.participants.forEach(participant => participant.setAudioContext(this.audioContext));
20902
21026
  }
21027
+ const newContextIsRunning = ((_b = this.audioContext) === null || _b === void 0 ? void 0 : _b.state) === 'running';
21028
+ if (newContextIsRunning !== this.canPlaybackAudio) {
21029
+ this.audioEnabled = newContextIsRunning;
21030
+ this.emit(RoomEvent.AudioPlaybackStatusChanged, newContextIsRunning);
21031
+ }
20903
21032
  }
20904
21033
  createParticipant(id, info) {
20905
21034
  let participant;
@@ -21041,11 +21170,12 @@ class Room extends events.exports.EventEmitter {
21041
21170
  * No actual connection to a server will be established, all state is
21042
21171
  * @experimental
21043
21172
  */
21044
- simulateParticipants(options) {
21173
+ async simulateParticipants(options) {
21045
21174
  var _a, _b;
21046
21175
  const publishOptions = _objectSpread2({
21047
21176
  audio: true,
21048
- video: true
21177
+ video: true,
21178
+ useRealTracks: false
21049
21179
  }, options.publish);
21050
21180
  const participantOptions = _objectSpread2({
21051
21181
  count: 9,
@@ -21055,8 +21185,10 @@ class Room extends events.exports.EventEmitter {
21055
21185
  }, options.participants);
21056
21186
  this.handleDisconnect();
21057
21187
  this.name = 'simulated-room';
21058
- this.localParticipant.identity = 'simulated-local';
21059
- this.localParticipant.name = 'simulated-local';
21188
+ this.localParticipant.updateInfo(ParticipantInfo.fromPartial({
21189
+ identity: 'simulated-local',
21190
+ name: 'local-name'
21191
+ }));
21060
21192
  this.setupLocalParticipantEvents();
21061
21193
  this.emit(RoomEvent.SignalConnected);
21062
21194
  this.emit(RoomEvent.Connected);
@@ -21067,7 +21199,9 @@ class Room extends events.exports.EventEmitter {
21067
21199
  sid: Math.floor(Math.random() * 10000).toString(),
21068
21200
  type: TrackType.AUDIO,
21069
21201
  name: 'video-dummy'
21070
- }), new LocalVideoTrack(createDummyVideoStreamTrack((_a = 160 * participantOptions.aspectRatios[0]) !== null && _a !== void 0 ? _a : 1, 160, true, true)));
21202
+ }), new LocalVideoTrack(publishOptions.useRealTracks ? (await navigator.mediaDevices.getUserMedia({
21203
+ video: true
21204
+ })).getVideoTracks()[0] : createDummyVideoStreamTrack((_a = 160 * participantOptions.aspectRatios[0]) !== null && _a !== void 0 ? _a : 1, 160, true, true)));
21071
21205
  // @ts-ignore
21072
21206
  this.localParticipant.addTrackPublication(camPub);
21073
21207
  this.localParticipant.emit(ParticipantEvent.LocalTrackPublished, camPub);
@@ -21077,7 +21211,9 @@ class Room extends events.exports.EventEmitter {
21077
21211
  source: TrackSource.MICROPHONE,
21078
21212
  sid: Math.floor(Math.random() * 10000).toString(),
21079
21213
  type: TrackType.AUDIO
21080
- }), new LocalAudioTrack(getEmptyAudioStreamTrack()));
21214
+ }), new LocalAudioTrack(publishOptions.useRealTracks ? (await navigator.mediaDevices.getUserMedia({
21215
+ audio: true
21216
+ })).getAudioTracks()[0] : getEmptyAudioStreamTrack()));
21081
21217
  // @ts-ignore
21082
21218
  this.localParticipant.addTrackPublication(audioPub);
21083
21219
  this.localParticipant.emit(ParticipantEvent.LocalTrackPublished, audioPub);
@@ -21241,7 +21377,7 @@ var CheckStatus;
21241
21377
  CheckStatus[CheckStatus["SUCCESS"] = 3] = "SUCCESS";
21242
21378
  CheckStatus[CheckStatus["FAILED"] = 4] = "FAILED";
21243
21379
  })(CheckStatus || (CheckStatus = {}));
21244
- class Checker extends events.exports.EventEmitter {
21380
+ class Checker extends eventsExports.EventEmitter {
21245
21381
  constructor(url, token) {
21246
21382
  let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
21247
21383
  super();
@@ -21521,7 +21657,7 @@ class WebSocketCheck extends Checker {
21521
21657
  }
21522
21658
  }
21523
21659
 
21524
- class ConnectionCheck extends events.exports {
21660
+ class ConnectionCheck extends eventsExports {
21525
21661
  constructor(url, token) {
21526
21662
  super();
21527
21663
  this.checkResults = new Map();