livekit-client 1.6.0 → 1.6.1

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.
@@ -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.1";
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;
@@ -21055,8 +21184,10 @@ class Room extends events.exports.EventEmitter {
21055
21184
  }, options.participants);
21056
21185
  this.handleDisconnect();
21057
21186
  this.name = 'simulated-room';
21058
- this.localParticipant.identity = 'simulated-local';
21059
- this.localParticipant.name = 'simulated-local';
21187
+ this.localParticipant.updateInfo(ParticipantInfo.fromPartial({
21188
+ identity: 'simulated-local',
21189
+ name: 'local-name'
21190
+ }));
21060
21191
  this.setupLocalParticipantEvents();
21061
21192
  this.emit(RoomEvent.SignalConnected);
21062
21193
  this.emit(RoomEvent.Connected);
@@ -21241,7 +21372,7 @@ var CheckStatus;
21241
21372
  CheckStatus[CheckStatus["SUCCESS"] = 3] = "SUCCESS";
21242
21373
  CheckStatus[CheckStatus["FAILED"] = 4] = "FAILED";
21243
21374
  })(CheckStatus || (CheckStatus = {}));
21244
- class Checker extends events.exports.EventEmitter {
21375
+ class Checker extends eventsExports.EventEmitter {
21245
21376
  constructor(url, token) {
21246
21377
  let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
21247
21378
  super();
@@ -21521,7 +21652,7 @@ class WebSocketCheck extends Checker {
21521
21652
  }
21522
21653
  }
21523
21654
 
21524
- class ConnectionCheck extends events.exports {
21655
+ class ConnectionCheck extends eventsExports {
21525
21656
  constructor(url, token) {
21526
21657
  super();
21527
21658
  this.checkResults = new Map();