livekit-client 1.1.3 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/livekit-client.esm.mjs +188 -117
  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/api/SignalClient.d.ts +1 -1
  6. package/dist/src/api/SignalClient.d.ts.map +1 -1
  7. package/dist/src/room/Room.d.ts +3 -1
  8. package/dist/src/room/Room.d.ts.map +1 -1
  9. package/dist/src/room/participant/LocalParticipant.d.ts +2 -1
  10. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  11. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  12. package/dist/src/room/track/LocalAudioTrack.d.ts +1 -1
  13. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  14. package/dist/src/room/track/LocalTrack.d.ts +4 -2
  15. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  16. package/dist/src/room/track/LocalVideoTrack.d.ts +1 -1
  17. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  18. package/dist/src/room/track/RemoteTrackPublication.d.ts +1 -0
  19. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  20. package/dist/src/room/track/options.d.ts +1 -1
  21. package/dist/src/room/track/options.d.ts.map +1 -1
  22. package/dist/src/room/utils.d.ts +6 -0
  23. package/dist/src/room/utils.d.ts.map +1 -1
  24. package/package.json +1 -1
  25. package/src/api/SignalClient.ts +1 -1
  26. package/src/room/Room.ts +112 -50
  27. package/src/room/participant/LocalParticipant.ts +7 -6
  28. package/src/room/participant/RemoteParticipant.ts +2 -0
  29. package/src/room/participant/publishUtils.ts +2 -2
  30. package/src/room/track/LocalAudioTrack.ts +7 -3
  31. package/src/room/track/LocalTrack.ts +11 -2
  32. package/src/room/track/LocalVideoTrack.ts +7 -3
  33. package/src/room/track/RemoteTrackPublication.ts +2 -0
  34. package/src/room/track/create.ts +2 -2
  35. package/src/room/track/options.ts +1 -1
  36. package/src/room/utils.ts +15 -0
@@ -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.3";
10073
+ var version$1 = "1.1.6";
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
  }
@@ -12955,10 +12975,10 @@ function trackPermissionToProto(perms) {
12955
12975
  function mediaTrackToLocalTrack(mediaStreamTrack, constraints) {
12956
12976
  switch (mediaStreamTrack.kind) {
12957
12977
  case 'audio':
12958
- return new LocalAudioTrack(mediaStreamTrack, constraints);
12978
+ return new LocalAudioTrack(mediaStreamTrack, constraints, false);
12959
12979
 
12960
12980
  case 'video':
12961
- return new LocalVideoTrack(mediaStreamTrack, constraints);
12981
+ return new LocalVideoTrack(mediaStreamTrack, constraints, false);
12962
12982
 
12963
12983
  default:
12964
12984
  throw new TrackInvalidError("unsupported track type: ".concat(mediaStreamTrack.kind));
@@ -13204,6 +13224,7 @@ class RemoteTrackPublication extends TrackPublication {
13204
13224
 
13205
13225
  this.handleEnded = track => {
13206
13226
  this.emit(TrackEvent.Ended, track);
13227
+ this.setTrack(undefined);
13207
13228
  };
13208
13229
 
13209
13230
  this.handleVisibilityChange = visible => {
@@ -13331,6 +13352,8 @@ class RemoteTrackPublication extends TrackPublication {
13331
13352
  get videoQuality() {
13332
13353
  return this.currentVideoQuality;
13333
13354
  }
13355
+ /** @internal */
13356
+
13334
13357
 
13335
13358
  setTrack(track) {
13336
13359
  if (this.track) {
@@ -13536,7 +13559,9 @@ class RemoteParticipant extends Participant {
13536
13559
  track.isMuted = publication.isMuted;
13537
13560
  track.setMediaStream(mediaStream);
13538
13561
  track.start();
13539
- publication.setTrack(track); // set participant volume on new microphone tracks
13562
+ publication.setTrack(track); // subscription means participant has permissions to subscribe
13563
+
13564
+ publication._allowed = true; // set participant volume on new microphone tracks
13540
13565
 
13541
13566
  if (this.volume !== undefined && track instanceof RemoteAudioTrack && track.source === Track.Source.Microphone) {
13542
13567
  track.setVolume(this.volume);
@@ -14065,12 +14090,12 @@ class LocalParticipant extends Participant {
14065
14090
  throw new TrackInvalidError('no video track found');
14066
14091
  }
14067
14092
 
14068
- const screenVideo = new LocalVideoTrack(tracks[0]);
14093
+ const screenVideo = new LocalVideoTrack(tracks[0], undefined, false);
14069
14094
  screenVideo.source = Track.Source.ScreenShare;
14070
14095
  const localTracks = [screenVideo];
14071
14096
 
14072
14097
  if (stream.getAudioTracks().length > 0) {
14073
- const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0]);
14098
+ const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false);
14074
14099
  screenAudio.source = Track.Source.ScreenShareAudio;
14075
14100
  localTracks.push(screenAudio);
14076
14101
  }
@@ -14093,11 +14118,11 @@ class LocalParticipant extends Participant {
14093
14118
  if (track instanceof MediaStreamTrack) {
14094
14119
  switch (track.kind) {
14095
14120
  case 'audio':
14096
- track = new LocalAudioTrack(track);
14121
+ track = new LocalAudioTrack(track, undefined, true);
14097
14122
  break;
14098
14123
 
14099
14124
  case 'video':
14100
- track = new LocalVideoTrack(track);
14125
+ track = new LocalVideoTrack(track, undefined, true);
14101
14126
  break;
14102
14127
 
14103
14128
  default:
@@ -14584,57 +14609,6 @@ class LocalParticipant extends Participant {
14584
14609
 
14585
14610
  }
14586
14611
 
14587
- class Queue {
14588
- constructor() {
14589
- this.queue = [];
14590
- this.running = false;
14591
- }
14592
-
14593
- enqueue(cb) {
14594
- livekitLogger.trace('enqueuing request to fire later');
14595
- this.queue.push(cb);
14596
- }
14597
-
14598
- dequeue() {
14599
- const evt = this.queue.shift();
14600
- if (evt) evt();
14601
- livekitLogger.trace('firing request from queue');
14602
- }
14603
-
14604
- async run() {
14605
- if (this.running) return;
14606
- livekitLogger.trace('start queue');
14607
- this.running = true;
14608
-
14609
- while (this.running && this.queue.length > 0) {
14610
- this.dequeue();
14611
- }
14612
-
14613
- this.running = false;
14614
- livekitLogger.trace('queue finished');
14615
- }
14616
-
14617
- pause() {
14618
- livekitLogger.trace('pausing queue');
14619
- this.running = false;
14620
- }
14621
-
14622
- reset() {
14623
- livekitLogger.trace('resetting queue');
14624
- this.running = false;
14625
- this.queue = [];
14626
- }
14627
-
14628
- isRunning() {
14629
- return this.running;
14630
- }
14631
-
14632
- isEmpty() {
14633
- return this.queue.length === 0;
14634
- }
14635
-
14636
- }
14637
-
14638
14612
  /*
14639
14613
  * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
14640
14614
  *
@@ -18120,6 +18094,57 @@ adapterFactory({
18120
18094
  window: typeof window === 'undefined' ? undefined : window
18121
18095
  });
18122
18096
 
18097
+ class Queue {
18098
+ constructor() {
18099
+ this.queue = [];
18100
+ this.running = false;
18101
+ }
18102
+
18103
+ enqueue(cb) {
18104
+ livekitLogger.trace('enqueuing request to fire later');
18105
+ this.queue.push(cb);
18106
+ }
18107
+
18108
+ dequeue() {
18109
+ const evt = this.queue.shift();
18110
+ if (evt) evt();
18111
+ livekitLogger.trace('firing request from queue');
18112
+ }
18113
+
18114
+ async run() {
18115
+ if (this.running) return;
18116
+ livekitLogger.trace('start queue');
18117
+ this.running = true;
18118
+
18119
+ while (this.running && this.queue.length > 0) {
18120
+ this.dequeue();
18121
+ }
18122
+
18123
+ this.running = false;
18124
+ livekitLogger.trace('queue finished');
18125
+ }
18126
+
18127
+ pause() {
18128
+ livekitLogger.trace('pausing queue');
18129
+ this.running = false;
18130
+ }
18131
+
18132
+ reset() {
18133
+ livekitLogger.trace('resetting queue');
18134
+ this.running = false;
18135
+ this.queue = [];
18136
+ }
18137
+
18138
+ isRunning() {
18139
+ return this.running;
18140
+ }
18141
+
18142
+ isEmpty() {
18143
+ return this.queue.length === 0;
18144
+ }
18145
+
18146
+ }
18147
+
18123
18148
  const passThroughQueueSignals = ['syncState', 'trickle', 'offer', 'answer', 'simulate', 'leave'];
18124
18149
 
18125
18150
  function canPassThroughQueue(req) {
@@ -19416,14 +19441,18 @@ class Room extends events.exports.EventEmitter {
19416
19441
  this.audioEnabled = true;
19417
19442
 
19418
19443
  this.connect = async (url, token, opts) => {
19419
- var _a, _b; // guard against calling connect
19420
-
19444
+ var _a, _b, _c, _d;
19421
19445
 
19422
- if (this.state !== ConnectionState.Disconnected) {
19446
+ if (this.state === ConnectionState.Connected) {
19447
+ // when the state is reconnecting or connected, this function returns immediately
19423
19448
  livekitLogger.warn("already connected to room ".concat(this.name));
19424
19449
  return;
19425
19450
  }
19426
19451
 
19452
+ if (this.connectFuture) {
19453
+ return this.connectFuture.promise;
19454
+ }
19455
+
19427
19456
  this.setAndEmitConnectionState(ConnectionState.Connecting);
19428
19457
 
19429
19458
  if (!this.abortController || this.abortController.signal.aborted) {
@@ -19489,50 +19518,48 @@ class Room extends events.exports.EventEmitter {
19489
19518
  this.metadata = joinResponse.room.metadata;
19490
19519
  this.emit(RoomEvent.SignalConnected);
19491
19520
  } catch (err) {
19492
- this.engine.close();
19493
- this.setAndEmitConnectionState(ConnectionState.Disconnected);
19521
+ this.recreateEngine();
19522
+ this.setAndEmitConnectionState(ConnectionState.Disconnected, new ConnectionError('could not establish signal connection'));
19494
19523
  throw err;
19495
19524
  } // don't return until ICE connected
19496
19525
 
19497
19526
 
19498
- return new Promise((resolve, reject) => {
19499
- var _a, _b;
19527
+ const connectTimeout = setTimeout(() => {
19528
+ // timeout
19529
+ this.recreateEngine();
19530
+ this.setAndEmitConnectionState(ConnectionState.Disconnected, new ConnectionError('could not connect PeerConnection after timeout'));
19531
+ }, maxICEConnectTimeout);
19500
19532
 
19501
- const connectTimeout = setTimeout(() => {
19502
- // timeout
19503
- this.engine.close();
19504
- this.setAndEmitConnectionState(ConnectionState.Disconnected);
19505
- reject(new ConnectionError('could not connect after timeout'));
19506
- }, maxICEConnectTimeout);
19507
-
19508
- const abortHandler = () => {
19509
- livekitLogger.warn('closing engine');
19510
- clearTimeout(connectTimeout);
19511
- this.engine.close();
19512
- this.setAndEmitConnectionState(ConnectionState.Disconnected);
19513
- reject(new ConnectionError('room connection has been cancelled'));
19514
- };
19533
+ const abortHandler = () => {
19534
+ livekitLogger.warn('closing engine');
19535
+ clearTimeout(connectTimeout);
19536
+ this.recreateEngine();
19537
+ this.setAndEmitConnectionState(ConnectionState.Disconnected, new ConnectionError('room connection has been cancelled'));
19538
+ };
19515
19539
 
19516
- if ((_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal.aborted) {
19517
- abortHandler();
19518
- }
19540
+ if ((_c = this.abortController) === null || _c === void 0 ? void 0 : _c.signal.aborted) {
19541
+ abortHandler();
19542
+ }
19519
19543
 
19520
- (_b = this.abortController) === null || _b === void 0 ? void 0 : _b.signal.addEventListener('abort', abortHandler);
19521
- this.engine.once(EngineEvent.Connected, () => {
19522
- var _a, _b;
19544
+ (_d = this.abortController) === null || _d === void 0 ? void 0 : _d.signal.addEventListener('abort', abortHandler);
19545
+ this.engine.once(EngineEvent.Connected, () => {
19546
+ var _a, _b;
19523
19547
 
19524
- clearTimeout(connectTimeout);
19525
- (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal.removeEventListener('abort', abortHandler); // also hook unload event
19548
+ clearTimeout(connectTimeout);
19549
+ (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal.removeEventListener('abort', abortHandler); // also hook unload event
19526
19550
 
19527
- if (isWeb()) {
19528
- window.addEventListener('beforeunload', this.onBeforeUnload);
19529
- (_b = navigator.mediaDevices) === null || _b === void 0 ? void 0 : _b.addEventListener('devicechange', this.handleDeviceChange);
19530
- }
19551
+ if (isWeb()) {
19552
+ window.addEventListener('beforeunload', this.onBeforeUnload);
19553
+ (_b = navigator.mediaDevices) === null || _b === void 0 ? void 0 : _b.addEventListener('devicechange', this.handleDeviceChange);
19554
+ }
19531
19555
 
19532
- this.setAndEmitConnectionState(ConnectionState.Connected);
19533
- resolve(this);
19534
- });
19556
+ this.setAndEmitConnectionState(ConnectionState.Connected);
19535
19557
  });
19558
+
19559
+ if (this.connectFuture) {
19560
+ /** @ts-ignore */
19561
+ return this.connectFuture.promise;
19562
+ }
19536
19563
  };
19537
19564
  /**
19538
19565
  * disconnects the room, emits [[RoomEvent.Disconnected]]
@@ -19573,14 +19600,14 @@ class Room extends events.exports.EventEmitter {
19573
19600
  };
19574
19601
 
19575
19602
  this.handleRestarting = () => {
19576
- if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
19577
- this.emit(RoomEvent.Reconnecting);
19578
- } // also unwind existing participants & existing subscriptions
19579
-
19580
-
19603
+ // also unwind existing participants & existing subscriptions
19581
19604
  for (const p of this.participants.values()) {
19582
19605
  this.handleParticipantDisconnected(p.sid, p);
19583
19606
  }
19607
+
19608
+ if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
19609
+ this.emit(RoomEvent.Reconnecting);
19610
+ }
19584
19611
  };
19585
19612
 
19586
19613
  this.handleRestarted = async joinResponse => {
@@ -19609,7 +19636,7 @@ class Room extends events.exports.EventEmitter {
19609
19636
  this.localParticipant.unpublishTrack(track, false);
19610
19637
 
19611
19638
  if (!track.isMuted) {
19612
- if (track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) {
19639
+ if ((track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) && !track.isUserProvided) {
19613
19640
  // we need to restart the track before publishing, often a full reconnect
19614
19641
  // is necessary because computer had gone to sleep.
19615
19642
  livekitLogger.debug('restarting existing track', {
@@ -19648,7 +19675,7 @@ class Room extends events.exports.EventEmitter {
19648
19675
  this.handleParticipantDisconnected(info.sid, remoteParticipant);
19649
19676
  } else if (isNewParticipant) {
19650
19677
  // fire connected event
19651
- this.emit(RoomEvent.ParticipantConnected, remoteParticipant);
19678
+ this.emitWhenConnected(RoomEvent.ParticipantConnected, remoteParticipant);
19652
19679
  } else {
19653
19680
  // just update, no events
19654
19681
  remoteParticipant.updateInfo(info);
@@ -19690,7 +19717,7 @@ class Room extends events.exports.EventEmitter {
19690
19717
  }
19691
19718
  });
19692
19719
  this.activeSpeakers = activeSpeakers;
19693
- this.emit(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
19720
+ this.emitWhenConnected(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
19694
19721
  }; // process list of changed speakers
19695
19722
 
19696
19723
 
@@ -19722,7 +19749,7 @@ class Room extends events.exports.EventEmitter {
19722
19749
  const activeSpeakers = Array.from(lastSpeakers.values());
19723
19750
  activeSpeakers.sort((a, b) => b.audioLevel - a.audioLevel);
19724
19751
  this.activeSpeakers = activeSpeakers;
19725
- this.emit(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
19752
+ this.emitWhenConnected(RoomEvent.ActiveSpeakersChanged, activeSpeakers);
19726
19753
  };
19727
19754
 
19728
19755
  this.handleStreamStateUpdate = streamStateUpdate => {
@@ -19741,7 +19768,7 @@ class Room extends events.exports.EventEmitter {
19741
19768
 
19742
19769
  pub.track.streamState = Track.streamStateFromProto(streamState.state);
19743
19770
  participant.emit(ParticipantEvent.TrackStreamStateChanged, pub, pub.track.streamState);
19744
- this.emit(ParticipantEvent.TrackStreamStateChanged, pub, pub.track.streamState, participant);
19771
+ this.emitWhenConnected(RoomEvent.TrackStreamStateChanged, pub, pub.track.streamState, participant);
19745
19772
  });
19746
19773
  };
19747
19774
 
@@ -19760,7 +19787,7 @@ class Room extends events.exports.EventEmitter {
19760
19787
 
19761
19788
  pub._allowed = update.allowed;
19762
19789
  participant.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus);
19763
- this.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus, participant);
19790
+ this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus, participant);
19764
19791
  };
19765
19792
 
19766
19793
  this.handleDataPacket = (userPacket, kind) => {
@@ -19797,7 +19824,7 @@ class Room extends events.exports.EventEmitter {
19797
19824
 
19798
19825
  this.handleRoomUpdate = r => {
19799
19826
  this.metadata = r.metadata;
19800
- this.emit(RoomEvent.RoomMetadataChanged, r.metadata);
19827
+ this.emitWhenConnected(RoomEvent.RoomMetadataChanged, r.metadata);
19801
19828
  };
19802
19829
 
19803
19830
  this.handleConnectionQualityUpdate = update => {
@@ -19855,6 +19882,10 @@ class Room extends events.exports.EventEmitter {
19855
19882
  this.sendSyncState();
19856
19883
  }
19857
19884
  }).on(EngineEvent.Restarting, this.handleRestarting).on(EngineEvent.Restarted, this.handleRestarted);
19885
+
19886
+ if (this.localParticipant) {
19887
+ this.localParticipant.engine = this.engine;
19888
+ }
19858
19889
  }
19859
19890
  /**
19860
19891
  * getLocalDevices abstracts navigator.mediaDevices.enumerateDevices.
@@ -20031,6 +20062,17 @@ class Room extends events.exports.EventEmitter {
20031
20062
  }
20032
20063
  }
20033
20064
 
20065
+ recreateEngine() {
20066
+ this.engine.close();
20067
+ /* @ts-ignore */
20068
+
20069
+ this.engine = undefined; // clear out existing remote participants, since they may have attached
20070
+ // the old engine
20071
+
20072
+ this.participants.clear();
20073
+ this.createEngine();
20074
+ }
20075
+
20034
20076
  onTrackAdded(mediaTrack, stream, receiver) {
20035
20077
  // don't fire onSubscribed when connecting
20036
20078
  // WebRTC fires onTrack as soon as setRemoteDescription is called on the offer
@@ -20040,7 +20082,7 @@ class Room extends events.exports.EventEmitter {
20040
20082
  if (this.state === ConnectionState.Connecting || this.state === ConnectionState.Reconnecting) {
20041
20083
  setTimeout(() => {
20042
20084
  this.onTrackAdded(mediaTrack, stream, receiver);
20043
- }, 10);
20085
+ }, 50);
20044
20086
  return;
20045
20087
  }
20046
20088
 
@@ -20117,7 +20159,7 @@ class Room extends events.exports.EventEmitter {
20117
20159
  participant.tracks.forEach(publication => {
20118
20160
  participant.unpublishTrack(publication.trackSid, true);
20119
20161
  });
20120
- this.emit(RoomEvent.ParticipantDisconnected, participant);
20162
+ this.emitWhenConnected(RoomEvent.ParticipantDisconnected, participant);
20121
20163
  }
20122
20164
 
20123
20165
  acquireAudioContext() {
@@ -20251,12 +20293,41 @@ class Room extends events.exports.EventEmitter {
20251
20293
  }
20252
20294
  }
20253
20295
 
20254
- setAndEmitConnectionState(state) {
20296
+ setAndEmitConnectionState(state, error) {
20255
20297
  if (state === this.state) {
20256
20298
  // unchanged
20257
20299
  return false;
20258
20300
  }
20259
20301
 
20302
+ switch (state) {
20303
+ case ConnectionState.Connecting:
20304
+ case ConnectionState.Reconnecting:
20305
+ if (!this.connectFuture) {
20306
+ // reuse existing connect future if possible
20307
+ this.connectFuture = new Future();
20308
+ }
20309
+
20310
+ break;
20311
+
20312
+ case ConnectionState.Connected:
20313
+ if (this.connectFuture) {
20314
+ this.connectFuture.resolve();
20315
+ this.connectFuture = undefined;
20316
+ }
20317
+
20318
+ break;
20319
+
20320
+ case ConnectionState.Disconnected:
20321
+ if (this.connectFuture) {
20322
+ error !== null && error !== void 0 ? error : error = new Error('disconnected from Room');
20323
+ this.connectFuture.reject(error);
20324
+ this.connectFuture = undefined;
20325
+ }
20326
+
20327
+ break;
20328
+
20329
+ }
20330
+
20260
20331
  this.state = state;
20261
20332
  this.emit(RoomEvent.ConnectionStateChanged, this.state);
20262
20333
  return true;
@@ -20386,12 +20457,12 @@ async function createLocalScreenTracks(options) {
20386
20457
  throw new TrackInvalidError('no video track found');
20387
20458
  }
20388
20459
 
20389
- const screenVideo = new LocalVideoTrack(tracks[0]);
20460
+ const screenVideo = new LocalVideoTrack(tracks[0], undefined, false);
20390
20461
  screenVideo.source = Track.Source.ScreenShare;
20391
20462
  const localTracks = [screenVideo];
20392
20463
 
20393
20464
  if (stream.getAudioTracks().length > 0) {
20394
- const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0]);
20465
+ const screenAudio = new LocalAudioTrack(stream.getAudioTracks()[0], undefined, false);
20395
20466
  screenAudio.source = Track.Source.ScreenShareAudio;
20396
20467
  localTracks.push(screenAudio);
20397
20468
  }