livekit-client 1.1.2 → 1.1.5

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.
@@ -10070,7 +10070,7 @@ function computeBitrate(currentStats, prevStats) {
10070
10070
  return (bytesNow - bytesPrev) * 8 * 1000 / (currentStats.timestamp - prevStats.timestamp);
10071
10071
  }
10072
10072
 
10073
- var version$1 = "1.1.2";
10073
+ var version$1 = "1.1.5";
10074
10074
 
10075
10075
  const version = version$1;
10076
10076
  const protocolVersion = 8;
@@ -10180,6 +10180,15 @@ function getEmptyAudioStreamTrack() {
10180
10180
 
10181
10181
  return emptyAudioStreamTrack;
10182
10182
  }
10183
+ class Future {
10184
+ constructor() {
10185
+ this.promise = new Promise((resolve, reject) => {
10186
+ this.resolve = resolve;
10187
+ this.reject = reject;
10188
+ });
10189
+ }
10190
+
10191
+ }
10183
10192
 
10184
10193
  const defaultId = 'default';
10185
10194
  class DeviceManager {
@@ -11060,6 +11069,7 @@ function detachTrack(track, element) {
11060
11069
 
11061
11070
  class LocalTrack extends Track {
11062
11071
  constructor(mediaTrack, kind, constraints) {
11072
+ let userProvidedTrack = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
11063
11073
  super(mediaTrack, kind);
11064
11074
  this._isUpstreamPaused = false;
11065
11075
 
@@ -11076,6 +11086,7 @@ class LocalTrack extends Track {
11076
11086
  this.constraints = constraints !== null && constraints !== void 0 ? constraints : mediaTrack.getConstraints();
11077
11087
  this.reacquireTrack = false;
11078
11088
  this.wasMuted = false;
11089
+ this.providedByUser = userProvidedTrack;
11079
11090
  }
11080
11091
 
11081
11092
  get id() {
@@ -11105,6 +11116,10 @@ class LocalTrack extends Track {
11105
11116
  get isUpstreamPaused() {
11106
11117
  return this._isUpstreamPaused;
11107
11118
  }
11119
+
11120
+ get isUserProvided() {
11121
+ return this.providedByUser;
11122
+ }
11108
11123
  /**
11109
11124
  * @returns DeviceID of the device that is currently being used for this track
11110
11125
  */
@@ -11136,6 +11151,8 @@ class LocalTrack extends Track {
11136
11151
  }
11137
11152
 
11138
11153
  async replaceTrack(track) {
11154
+ let userProvidedTrack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
11155
+
11139
11156
  if (!this.sender) {
11140
11157
  throw new TrackInvalidError('unable to replace an unpublished track');
11141
11158
  } // detach
@@ -11164,6 +11181,7 @@ class LocalTrack extends Track {
11164
11181
  attachToElement(track, el);
11165
11182
  });
11166
11183
  this.mediaStream = new MediaStream([track]);
11184
+ this.providedByUser = userProvidedTrack;
11167
11185
  return this;
11168
11186
  }
11169
11187
 
@@ -11235,7 +11253,7 @@ class LocalTrack extends Track {
11235
11253
  if (!isMobile()) return;
11236
11254
  livekitLogger.debug("visibility changed, is in Background: ".concat(this.isInBackground));
11237
11255
 
11238
- if (!this.isInBackground && this.needsReAcquisition) {
11256
+ if (!this.isInBackground && this.needsReAcquisition && !this.isUserProvided) {
11239
11257
  livekitLogger.debug("track needs to be reaquired, restarting ".concat(this.source));
11240
11258
  await this.restart();
11241
11259
  this.reacquireTrack = false; // Restore muted state if had to be restarted
@@ -11386,7 +11404,8 @@ function getNewAudioContext() {
11386
11404
 
11387
11405
  class LocalAudioTrack extends LocalTrack {
11388
11406
  constructor(mediaTrack, constraints) {
11389
- super(mediaTrack, Track.Kind.Audio, constraints);
11407
+ let userProvidedTrack = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
11408
+ super(mediaTrack, Track.Kind.Audio, constraints, userProvidedTrack);
11390
11409
  /** @internal */
11391
11410
 
11392
11411
  this.stopOnMute = false;
@@ -11446,7 +11465,7 @@ class LocalAudioTrack extends LocalTrack {
11446
11465
  }
11447
11466
 
11448
11467
  async unmute() {
11449
- if (this.source === Track.Source.Microphone && this.stopOnMute) {
11468
+ if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) {
11450
11469
  livekitLogger.debug('reacquiring mic track');
11451
11470
  await this.restartTrack();
11452
11471
  }
@@ -11530,7 +11549,8 @@ class LocalAudioTrack extends LocalTrack {
11530
11549
  const refreshSubscribedCodecAfterNewCodec = 5000;
11531
11550
  class LocalVideoTrack extends LocalTrack {
11532
11551
  constructor(mediaTrack, constraints) {
11533
- super(mediaTrack, Track.Kind.Video, constraints);
11552
+ let userProvidedTrack = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
11553
+ super(mediaTrack, Track.Kind.Video, constraints, userProvidedTrack);
11534
11554
  this.simulcastCodecs = new Map();
11535
11555
 
11536
11556
  this.monitorSender = async () => {
@@ -11627,7 +11647,7 @@ class LocalVideoTrack extends LocalTrack {
11627
11647
  }
11628
11648
 
11629
11649
  async unmute() {
11630
- if (this.source === Track.Source.Camera) {
11650
+ if (this.source === Track.Source.Camera && !this.isUserProvided) {
11631
11651
  livekitLogger.debug('reacquiring camera track');
11632
11652
  await this.restartTrack();
11633
11653
  }
@@ -12225,6 +12245,8 @@ class RemoteVideoTrack extends RemoteTrack {
12225
12245
 
12226
12246
  this.debouncedHandleResize();
12227
12247
  this.updateVisibility();
12248
+ } else {
12249
+ livekitLogger.warn('visibility resize observer not triggered');
12228
12250
  }
12229
12251
  }
12230
12252
  /**
@@ -12373,9 +12395,7 @@ class RemoteVideoTrack extends RemoteTrack {
12373
12395
  }
12374
12396
 
12375
12397
  class HTMLElementInfo {
12376
- constructor(element) {
12377
- let visible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
12378
-
12398
+ constructor(element, visible) {
12379
12399
  this.onVisibilityChanged = entry => {
12380
12400
  var _a;
12381
12401
 
@@ -12392,7 +12412,7 @@ class HTMLElementInfo {
12392
12412
  };
12393
12413
 
12394
12414
  this.element = element;
12395
- this.visible = visible;
12415
+ this.visible = visible !== null && visible !== void 0 ? visible : isElementInViewport(element);
12396
12416
  this.visibilityChangedAt = 0;
12397
12417
  }
12398
12418
 
@@ -12423,6 +12443,29 @@ class HTMLElementInfo {
12423
12443
  (_b = getResizeObserver()) === null || _b === void 0 ? void 0 : _b.unobserve(this.element);
12424
12444
  }
12425
12445
 
12446
+ } // does not account for occlusion by other elements
12447
+
12448
+
12449
+ function isElementInViewport(el) {
12450
+ let top = el.offsetTop;
12451
+ let left = el.offsetLeft;
12452
+ const width = el.offsetWidth;
12453
+ const height = el.offsetHeight;
12454
+ const {
12455
+ hidden
12456
+ } = el;
12457
+ const {
12458
+ opacity,
12459
+ display
12460
+ } = getComputedStyle(el);
12461
+
12462
+ while (el.offsetParent) {
12463
+ el = el.offsetParent;
12464
+ top += el.offsetTop;
12465
+ left += el.offsetLeft;
12466
+ }
12467
+
12468
+ 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';
12426
12469
  }
12427
12470
 
12428
12471
  class TrackPublication extends events.exports.EventEmitter {
@@ -12932,10 +12975,10 @@ function trackPermissionToProto(perms) {
12932
12975
  function mediaTrackToLocalTrack(mediaStreamTrack, constraints) {
12933
12976
  switch (mediaStreamTrack.kind) {
12934
12977
  case 'audio':
12935
- return new LocalAudioTrack(mediaStreamTrack, constraints);
12978
+ return new LocalAudioTrack(mediaStreamTrack, constraints, false);
12936
12979
 
12937
12980
  case 'video':
12938
- return new LocalVideoTrack(mediaStreamTrack, constraints);
12981
+ return new LocalVideoTrack(mediaStreamTrack, constraints, false);
12939
12982
 
12940
12983
  default:
12941
12984
  throw new TrackInvalidError("unsupported track type: ".concat(mediaStreamTrack.kind));
@@ -13395,9 +13438,7 @@ class RemoteParticipant extends Participant {
13395
13438
 
13396
13439
 
13397
13440
  static fromParticipantInfo(signalClient, pi) {
13398
- const rp = new RemoteParticipant(signalClient, pi.sid, pi.identity);
13399
- rp.updateInfo(pi);
13400
- return rp;
13441
+ return new RemoteParticipant(signalClient, pi.sid, pi.identity);
13401
13442
  }
13402
13443
 
13403
13444
  addTrackPublication(publication) {
@@ -13538,7 +13579,6 @@ class RemoteParticipant extends Participant {
13538
13579
 
13539
13580
 
13540
13581
  updateInfo(info) {
13541
- const alreadyHasMetadata = this.hasMetadata;
13542
13582
  super.updateInfo(info); // we are getting a list of all available tracks, reconcile in here
13543
13583
  // and send out events for changes
13544
13584
  // reconcile track publications, publish events only if metadata is already there
@@ -13566,14 +13606,11 @@ class RemoteParticipant extends Participant {
13566
13606
  }
13567
13607
 
13568
13608
  validTracks.set(ti.sid, publication);
13569
- }); // send new tracks
13570
-
13571
- if (alreadyHasMetadata) {
13572
- newTracks.forEach(publication => {
13573
- this.emit(ParticipantEvent.TrackPublished, publication);
13574
- });
13575
- } // detect removed tracks
13609
+ }); // always emit events for new publications, Room will not forward them unless it's ready
13576
13610
 
13611
+ newTracks.forEach(publication => {
13612
+ this.emit(ParticipantEvent.TrackPublished, publication);
13613
+ }); // detect removed tracks
13577
13614
 
13578
13615
  this.tracks.forEach(publication => {
13579
13616
  if (!validTracks.has(publication.trackSid)) {
@@ -14048,12 +14085,12 @@ class LocalParticipant extends Participant {
14048
14085
  throw new TrackInvalidError('no video track found');
14049
14086
  }
14050
14087
 
14051
- const screenVideo = new LocalVideoTrack(tracks[0]);
14088
+ const screenVideo = new LocalVideoTrack(tracks[0], undefined, false);
14052
14089
  screenVideo.source = Track.Source.ScreenShare;
14053
14090
  const localTracks = [screenVideo];
14054
14091
 
14055
14092
  if (stream.getAudioTracks().length > 0) {
14056
- const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0]);
14093
+ const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false);
14057
14094
  screenAudio.source = Track.Source.ScreenShareAudio;
14058
14095
  localTracks.push(screenAudio);
14059
14096
  }
@@ -14076,11 +14113,11 @@ class LocalParticipant extends Participant {
14076
14113
  if (track instanceof MediaStreamTrack) {
14077
14114
  switch (track.kind) {
14078
14115
  case 'audio':
14079
- track = new LocalAudioTrack(track);
14116
+ track = new LocalAudioTrack(track, undefined, true);
14080
14117
  break;
14081
14118
 
14082
14119
  case 'video':
14083
- track = new LocalVideoTrack(track);
14120
+ track = new LocalVideoTrack(track, undefined, true);
14084
14121
  break;
14085
14122
 
14086
14123
  default:
@@ -19399,14 +19436,18 @@ class Room extends events.exports.EventEmitter {
19399
19436
  this.audioEnabled = true;
19400
19437
 
19401
19438
  this.connect = async (url, token, opts) => {
19402
- var _a, _b; // guard against calling connect
19403
-
19439
+ var _a, _b, _c, _d;
19404
19440
 
19405
- if (this.state !== ConnectionState.Disconnected) {
19441
+ if (this.state === ConnectionState.Connected) {
19442
+ // when the state is reconnecting or connected, this function returns immediately
19406
19443
  livekitLogger.warn("already connected to room ".concat(this.name));
19407
19444
  return;
19408
19445
  }
19409
19446
 
19447
+ if (this.connectFuture) {
19448
+ return this.connectFuture.promise;
19449
+ }
19450
+
19410
19451
  this.setAndEmitConnectionState(ConnectionState.Connecting);
19411
19452
 
19412
19453
  if (!this.abortController || this.abortController.signal.aborted) {
@@ -19472,50 +19513,48 @@ class Room extends events.exports.EventEmitter {
19472
19513
  this.metadata = joinResponse.room.metadata;
19473
19514
  this.emit(RoomEvent.SignalConnected);
19474
19515
  } catch (err) {
19475
- this.engine.close();
19476
- this.setAndEmitConnectionState(ConnectionState.Disconnected);
19516
+ this.recreateEngine();
19517
+ this.setAndEmitConnectionState(ConnectionState.Disconnected, new ConnectionError('could not establish signal connection'));
19477
19518
  throw err;
19478
19519
  } // don't return until ICE connected
19479
19520
 
19480
19521
 
19481
- return new Promise((resolve, reject) => {
19482
- var _a, _b;
19522
+ const connectTimeout = setTimeout(() => {
19523
+ // timeout
19524
+ this.recreateEngine();
19525
+ this.setAndEmitConnectionState(ConnectionState.Disconnected, new ConnectionError('could not connect PeerConnection after timeout'));
19526
+ }, maxICEConnectTimeout);
19483
19527
 
19484
- const connectTimeout = setTimeout(() => {
19485
- // timeout
19486
- this.engine.close();
19487
- this.setAndEmitConnectionState(ConnectionState.Disconnected);
19488
- reject(new ConnectionError('could not connect after timeout'));
19489
- }, maxICEConnectTimeout);
19490
-
19491
- const abortHandler = () => {
19492
- livekitLogger.warn('closing engine');
19493
- clearTimeout(connectTimeout);
19494
- this.engine.close();
19495
- this.setAndEmitConnectionState(ConnectionState.Disconnected);
19496
- reject(new ConnectionError('room connection has been cancelled'));
19497
- };
19528
+ const abortHandler = () => {
19529
+ livekitLogger.warn('closing engine');
19530
+ clearTimeout(connectTimeout);
19531
+ this.recreateEngine();
19532
+ this.setAndEmitConnectionState(ConnectionState.Disconnected, new ConnectionError('room connection has been cancelled'));
19533
+ };
19498
19534
 
19499
- if ((_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal.aborted) {
19500
- abortHandler();
19501
- }
19535
+ if ((_c = this.abortController) === null || _c === void 0 ? void 0 : _c.signal.aborted) {
19536
+ abortHandler();
19537
+ }
19502
19538
 
19503
- (_b = this.abortController) === null || _b === void 0 ? void 0 : _b.signal.addEventListener('abort', abortHandler);
19504
- this.engine.once(EngineEvent.Connected, () => {
19505
- var _a, _b;
19539
+ (_d = this.abortController) === null || _d === void 0 ? void 0 : _d.signal.addEventListener('abort', abortHandler);
19540
+ this.engine.once(EngineEvent.Connected, () => {
19541
+ var _a, _b;
19506
19542
 
19507
- clearTimeout(connectTimeout);
19508
- (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal.removeEventListener('abort', abortHandler); // also hook unload event
19543
+ clearTimeout(connectTimeout);
19544
+ (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal.removeEventListener('abort', abortHandler); // also hook unload event
19509
19545
 
19510
- if (isWeb()) {
19511
- window.addEventListener('beforeunload', this.onBeforeUnload);
19512
- (_b = navigator.mediaDevices) === null || _b === void 0 ? void 0 : _b.addEventListener('devicechange', this.handleDeviceChange);
19513
- }
19546
+ if (isWeb()) {
19547
+ window.addEventListener('beforeunload', this.onBeforeUnload);
19548
+ (_b = navigator.mediaDevices) === null || _b === void 0 ? void 0 : _b.addEventListener('devicechange', this.handleDeviceChange);
19549
+ }
19514
19550
 
19515
- this.setAndEmitConnectionState(ConnectionState.Connected);
19516
- resolve(this);
19517
- });
19551
+ this.setAndEmitConnectionState(ConnectionState.Connected);
19518
19552
  });
19553
+
19554
+ if (this.connectFuture) {
19555
+ /** @ts-ignore */
19556
+ return this.connectFuture.promise;
19557
+ }
19519
19558
  };
19520
19559
  /**
19521
19560
  * disconnects the room, emits [[RoomEvent.Disconnected]]
@@ -19556,14 +19595,14 @@ class Room extends events.exports.EventEmitter {
19556
19595
  };
19557
19596
 
19558
19597
  this.handleRestarting = () => {
19559
- if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
19560
- this.emit(RoomEvent.Reconnecting);
19561
- } // also unwind existing participants & existing subscriptions
19562
-
19563
-
19598
+ // also unwind existing participants & existing subscriptions
19564
19599
  for (const p of this.participants.values()) {
19565
19600
  this.handleParticipantDisconnected(p.sid, p);
19566
19601
  }
19602
+
19603
+ if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
19604
+ this.emit(RoomEvent.Reconnecting);
19605
+ }
19567
19606
  };
19568
19607
 
19569
19608
  this.handleRestarted = async joinResponse => {
@@ -19592,7 +19631,7 @@ class Room extends events.exports.EventEmitter {
19592
19631
  this.localParticipant.unpublishTrack(track, false);
19593
19632
 
19594
19633
  if (!track.isMuted) {
19595
- if (track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) {
19634
+ if ((track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) && !track.isUserProvided) {
19596
19635
  // we need to restart the track before publishing, often a full reconnect
19597
19636
  // is necessary because computer had gone to sleep.
19598
19637
  livekitLogger.debug('restarting existing track', {
@@ -19631,7 +19670,7 @@ class Room extends events.exports.EventEmitter {
19631
19670
  this.handleParticipantDisconnected(info.sid, remoteParticipant);
19632
19671
  } else if (isNewParticipant) {
19633
19672
  // fire connected event
19634
- this.emit(RoomEvent.ParticipantConnected, remoteParticipant);
19673
+ this.emitWhenConnected(RoomEvent.ParticipantConnected, remoteParticipant);
19635
19674
  } else {
19636
19675
  // just update, no events
19637
19676
  remoteParticipant.updateInfo(info);
@@ -19673,7 +19712,7 @@ class Room extends events.exports.EventEmitter {
19673
19712
  }
19674
19713
  });
19675
19714
  this.activeSpeakers = activeSpeakers;
19676
- this.emit(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
19715
+ this.emitWhenConnected(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
19677
19716
  }; // process list of changed speakers
19678
19717
 
19679
19718
 
@@ -19705,7 +19744,7 @@ class Room extends events.exports.EventEmitter {
19705
19744
  const activeSpeakers = Array.from(lastSpeakers.values());
19706
19745
  activeSpeakers.sort((a, b) => b.audioLevel - a.audioLevel);
19707
19746
  this.activeSpeakers = activeSpeakers;
19708
- this.emit(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
19747
+ this.emitWhenConnected(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
19709
19748
  };
19710
19749
 
19711
19750
  this.handleStreamStateUpdate = streamStateUpdate => {
@@ -19724,7 +19763,7 @@ class Room extends events.exports.EventEmitter {
19724
19763
 
19725
19764
  pub.track.streamState = Track.streamStateFromProto(streamState.state);
19726
19765
  participant.emit(ParticipantEvent.TrackStreamStateChanged, pub, pub.track.streamState);
19727
- this.emit(ParticipantEvent.TrackStreamStateChanged, pub, pub.track.streamState, participant);
19766
+ this.emitWhenConnected(ParticipantEvent.TrackStreamStateChanged, pub, pub.track.streamState, participant);
19728
19767
  });
19729
19768
  };
19730
19769
 
@@ -19743,7 +19782,7 @@ class Room extends events.exports.EventEmitter {
19743
19782
 
19744
19783
  pub._allowed = update.allowed;
19745
19784
  participant.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus);
19746
- this.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus, participant);
19785
+ this.emitWhenConnected(ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus, participant);
19747
19786
  };
19748
19787
 
19749
19788
  this.handleDataPacket = (userPacket, kind) => {
@@ -19780,7 +19819,7 @@ class Room extends events.exports.EventEmitter {
19780
19819
 
19781
19820
  this.handleRoomUpdate = r => {
19782
19821
  this.metadata = r.metadata;
19783
- this.emit(RoomEvent.RoomMetadataChanged, r.metadata);
19822
+ this.emitWhenConnected(RoomEvent.RoomMetadataChanged, r.metadata);
19784
19823
  };
19785
19824
 
19786
19825
  this.handleConnectionQualityUpdate = update => {
@@ -19838,6 +19877,10 @@ class Room extends events.exports.EventEmitter {
19838
19877
  this.sendSyncState();
19839
19878
  }
19840
19879
  }).on(EngineEvent.Restarting, this.handleRestarting).on(EngineEvent.Restarted, this.handleRestarted);
19880
+
19881
+ if (this.localParticipant) {
19882
+ this.localParticipant.engine = this.engine;
19883
+ }
19841
19884
  }
19842
19885
  /**
19843
19886
  * getLocalDevices abstracts navigator.mediaDevices.enumerateDevices.
@@ -20014,7 +20057,34 @@ class Room extends events.exports.EventEmitter {
20014
20057
  }
20015
20058
  }
20016
20059
 
20060
+ recreateEngine() {
20061
+ this.engine.close();
20062
+ /* @ts-ignore */
20063
+
20064
+ this.engine = undefined; // clear out existing remote participants, since they may have attached
20065
+ // the old engine
20066
+
20067
+ this.participants.clear();
20068
+ this.createEngine();
20069
+ }
20070
+
20017
20071
  onTrackAdded(mediaTrack, stream, receiver) {
20072
+ // don't fire onSubscribed when connecting
20073
+ // WebRTC fires onTrack as soon as setRemoteDescription is called on the offer
20074
+ // at that time, ICE connectivity has not been established so the track is not
20075
+ // technically subscribed.
20076
+ // We'll defer these events until when the room is connected or eventually disconnected.
20077
+ if (this.state === ConnectionState.Connecting || this.state === ConnectionState.Reconnecting) {
20078
+ setTimeout(() => {
20079
+ this.onTrackAdded(mediaTrack, stream, receiver);
20080
+ }, 50);
20081
+ return;
20082
+ }
20083
+
20084
+ if (this.state === ConnectionState.Disconnected) {
20085
+ livekitLogger.warn('skipping incoming track after Room disconnected');
20086
+ }
20087
+
20018
20088
  const parts = unpackStreamId(stream.id);
20019
20089
  const participantId = parts[0];
20020
20090
  let trackId = parts[1];
@@ -20084,7 +20154,7 @@ class Room extends events.exports.EventEmitter {
20084
20154
  participant.tracks.forEach(publication => {
20085
20155
  participant.unpublishTrack(publication.trackSid, true);
20086
20156
  });
20087
- this.emit(RoomEvent.ParticipantDisconnected, participant);
20157
+ this.emitWhenConnected(RoomEvent.ParticipantDisconnected, participant);
20088
20158
  }
20089
20159
 
20090
20160
  acquireAudioContext() {
@@ -20131,7 +20201,7 @@ class Room extends events.exports.EventEmitter {
20131
20201
 
20132
20202
 
20133
20203
  participant.on(ParticipantEvent.TrackPublished, trackPublication => {
20134
- this.emit(RoomEvent.TrackPublished, trackPublication, participant);
20204
+ this.emitWhenConnected(RoomEvent.TrackPublished, trackPublication, participant);
20135
20205
  }).on(ParticipantEvent.TrackSubscribed, (track, publication) => {
20136
20206
  // monitor playback status
20137
20207
  if (track.kind === Track.Kind.Audio) {
@@ -20141,22 +20211,27 @@ class Room extends events.exports.EventEmitter {
20141
20211
 
20142
20212
  this.emit(RoomEvent.TrackSubscribed, track, publication, participant);
20143
20213
  }).on(ParticipantEvent.TrackUnpublished, publication => {
20144
- this.emit(RoomEvent.TrackUnpublished, publication, participant);
20214
+ this.emitWhenConnected(RoomEvent.TrackUnpublished, publication, participant);
20145
20215
  }).on(ParticipantEvent.TrackUnsubscribed, (track, publication) => {
20146
20216
  this.emit(RoomEvent.TrackUnsubscribed, track, publication, participant);
20147
20217
  }).on(ParticipantEvent.TrackSubscriptionFailed, sid => {
20148
20218
  this.emit(RoomEvent.TrackSubscriptionFailed, sid, participant);
20149
20219
  }).on(ParticipantEvent.TrackMuted, pub => {
20150
- this.emit(RoomEvent.TrackMuted, pub, participant);
20220
+ this.emitWhenConnected(RoomEvent.TrackMuted, pub, participant);
20151
20221
  }).on(ParticipantEvent.TrackUnmuted, pub => {
20152
- this.emit(RoomEvent.TrackUnmuted, pub, participant);
20222
+ this.emitWhenConnected(RoomEvent.TrackUnmuted, pub, participant);
20153
20223
  }).on(ParticipantEvent.ParticipantMetadataChanged, metadata => {
20154
- this.emit(RoomEvent.ParticipantMetadataChanged, metadata, participant);
20224
+ this.emitWhenConnected(RoomEvent.ParticipantMetadataChanged, metadata, participant);
20155
20225
  }).on(ParticipantEvent.ConnectionQualityChanged, quality => {
20156
- this.emit(RoomEvent.ConnectionQualityChanged, quality, participant);
20226
+ this.emitWhenConnected(RoomEvent.ConnectionQualityChanged, quality, participant);
20157
20227
  }).on(ParticipantEvent.ParticipantPermissionsChanged, prevPermissions => {
20158
- this.emit(RoomEvent.ParticipantPermissionsChanged, prevPermissions, participant);
20159
- });
20228
+ this.emitWhenConnected(RoomEvent.ParticipantPermissionsChanged, prevPermissions, participant);
20229
+ }); // update info at the end after callbacks have been set up
20230
+
20231
+ if (info) {
20232
+ participant.updateInfo(info);
20233
+ }
20234
+
20160
20235
  return participant;
20161
20236
  }
20162
20237
 
@@ -20213,21 +20288,62 @@ class Room extends events.exports.EventEmitter {
20213
20288
  }
20214
20289
  }
20215
20290
 
20216
- setAndEmitConnectionState(state) {
20291
+ setAndEmitConnectionState(state, error) {
20217
20292
  if (state === this.state) {
20218
20293
  // unchanged
20219
20294
  return false;
20220
20295
  }
20221
20296
 
20297
+ switch (state) {
20298
+ case ConnectionState.Connecting:
20299
+ case ConnectionState.Reconnecting:
20300
+ if (!this.connectFuture) {
20301
+ // reuse existing connect future if possible
20302
+ this.connectFuture = new Future();
20303
+ }
20304
+
20305
+ break;
20306
+
20307
+ case ConnectionState.Connected:
20308
+ if (this.connectFuture) {
20309
+ this.connectFuture.resolve();
20310
+ this.connectFuture = undefined;
20311
+ }
20312
+
20313
+ break;
20314
+
20315
+ case ConnectionState.Disconnected:
20316
+ if (this.connectFuture) {
20317
+ error !== null && error !== void 0 ? error : error = new Error('disconnected from Room');
20318
+ this.connectFuture.reject(error);
20319
+ this.connectFuture = undefined;
20320
+ }
20321
+
20322
+ break;
20323
+
20324
+ }
20325
+
20222
20326
  this.state = state;
20223
20327
  this.emit(RoomEvent.ConnectionStateChanged, this.state);
20224
20328
  return true;
20329
+ }
20330
+
20331
+ emitWhenConnected(event) {
20332
+ if (this.state === ConnectionState.Connected) {
20333
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
20334
+ args[_key - 1] = arguments[_key];
20335
+ }
20336
+
20337
+ return this.emit(event, ...args);
20338
+ }
20339
+
20340
+ return false;
20225
20341
  } // /** @internal */
20226
20342
 
20227
20343
 
20228
20344
  emit(event) {
20229
- for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
20230
- args[_key - 1] = arguments[_key];
20345
+ for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
20346
+ args[_key2 - 1] = arguments[_key2];
20231
20347
  }
20232
20348
 
20233
20349
  livekitLogger.debug('room event', {
@@ -20336,12 +20452,12 @@ async function createLocalScreenTracks(options) {
20336
20452
  throw new TrackInvalidError('no video track found');
20337
20453
  }
20338
20454
 
20339
- const screenVideo = new LocalVideoTrack(tracks[0]);
20455
+ const screenVideo = new LocalVideoTrack(tracks[0], undefined, false);
20340
20456
  screenVideo.source = Track.Source.ScreenShare;
20341
20457
  const localTracks = [screenVideo];
20342
20458
 
20343
20459
  if (stream.getAudioTracks().length > 0) {
20344
- const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0]);
20460
+ const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false);
20345
20461
  screenAudio.source = Track.Source.ScreenShareAudio;
20346
20462
  localTracks.push(screenAudio);
20347
20463
  }