livekit-client 1.7.0 → 1.7.1

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 +83 -28
  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/options.d.ts +5 -0
  6. package/dist/src/options.d.ts.map +1 -1
  7. package/dist/src/room/RTCEngine.d.ts +1 -0
  8. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  9. package/dist/src/room/Room.d.ts +2 -1
  10. package/dist/src/room/Room.d.ts.map +1 -1
  11. package/dist/src/room/defaults.d.ts.map +1 -1
  12. package/dist/src/room/events.d.ts +7 -0
  13. package/dist/src/room/events.d.ts.map +1 -1
  14. package/dist/src/room/track/LocalAudioTrack.d.ts +1 -1
  15. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  16. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  17. package/dist/src/room/track/RemoteVideoTrack.d.ts +1 -0
  18. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
  19. package/dist/src/room/track/utils.d.ts.map +1 -1
  20. package/dist/ts4.2/src/options.d.ts +5 -0
  21. package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -0
  22. package/dist/ts4.2/src/room/Room.d.ts +2 -1
  23. package/dist/ts4.2/src/room/events.d.ts +7 -0
  24. package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +1 -1
  25. package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +1 -0
  26. package/package.json +1 -1
  27. package/src/options.ts +6 -0
  28. package/src/room/RTCEngine.ts +25 -16
  29. package/src/room/Room.ts +15 -5
  30. package/src/room/defaults.ts +1 -0
  31. package/src/room/events.ts +8 -0
  32. package/src/room/track/LocalAudioTrack.ts +1 -0
  33. package/src/room/track/RemoteTrackPublication.ts +6 -1
  34. package/src/room/track/RemoteVideoTrack.test.ts +2 -0
  35. package/src/room/track/RemoteVideoTrack.ts +48 -5
  36. package/src/room/track/utils.ts +3 -2
@@ -12916,6 +12916,13 @@ var RoomEvent;
12916
12916
  * args: ([[LocalTrackPublication]], [[LocalParticipant]])
12917
12917
  */
12918
12918
  RoomEvent["LocalTrackUnpublished"] = "localTrackUnpublished";
12919
+ /**
12920
+ * When a local audio track is published the SDK checks whether there is complete silence
12921
+ * on that track and emits the LocalAudioSilenceDetected event in that case.
12922
+ * This allows for applications to show UI informing users that they might have to
12923
+ * reset their audio hardware or check for proper device connectivity.
12924
+ */
12925
+ RoomEvent["LocalAudioSilenceDetected"] = "localAudioSilenceDetected";
12919
12926
  /**
12920
12927
  * Active speakers changed. List of speakers are ordered by their audio level.
12921
12928
  * loudest speakers first. This will include the LocalParticipant too.
@@ -13940,7 +13947,7 @@ var uaParser = {
13940
13947
  })(uaParser, uaParserExports);
13941
13948
  var UAParser = uaParserExports;
13942
13949
 
13943
- var version$1 = "1.7.0";
13950
+ var version$1 = "1.7.1";
13944
13951
 
13945
13952
  const version = version$1;
13946
13953
  const protocolVersion = 9;
@@ -14026,8 +14033,9 @@ async function detectSilence(track) {
14026
14033
  * @internal
14027
14034
  */
14028
14035
  function getNewAudioContext() {
14036
+ const AudioContext =
14029
14037
  // @ts-ignore
14030
- const AudioContext = window.AudioContext || window.webkitAudioContext;
14038
+ typeof window !== 'undefined' && (window.AudioContext || window.webkitAudioContext);
14031
14039
  if (AudioContext) {
14032
14040
  return new AudioContext({
14033
14041
  latencyHint: 'interactive'
@@ -15569,6 +15577,7 @@ class LocalAudioTrack extends LocalTrack {
15569
15577
  }
15570
15578
  this.emit(TrackEvent.AudioSilenceDetected);
15571
15579
  }
15580
+ return trackIsSilent;
15572
15581
  }
15573
15582
  }
15574
15583
 
@@ -16401,7 +16410,8 @@ class RemoteVideoTrack extends RemoteTrack {
16401
16410
  const lastVisibilityChange = this.elementInfos.reduce((prev, info) => Math.max(prev, info.visibilityChangedAt || 0), 0);
16402
16411
  const backgroundPause = ((_b = (_a = this.adaptiveStreamSettings) === null || _a === void 0 ? void 0 : _a.pauseVideoInBackground) !== null && _b !== void 0 ? _b : true // default to true
16403
16412
  ) ? this.isInBackground : false;
16404
- const isVisible = this.elementInfos.some(info => info.visible) && !backgroundPause;
16413
+ const isPiPMode = this.elementInfos.some(info => info.pictureInPicture);
16414
+ const isVisible = this.elementInfos.some(info => info.visible) && !backgroundPause || isPiPMode;
16405
16415
  if (this.lastVisible === isVisible) {
16406
16416
  return;
16407
16417
  }
@@ -16440,6 +16450,12 @@ class RemoteVideoTrack extends RemoteTrack {
16440
16450
  }
16441
16451
  }
16442
16452
  class HTMLElementInfo {
16453
+ get visible() {
16454
+ return this.isPiP || this.isIntersecting;
16455
+ }
16456
+ get pictureInPicture() {
16457
+ return this.isPiP;
16458
+ }
16443
16459
  constructor(element, visible) {
16444
16460
  this.onVisibilityChanged = entry => {
16445
16461
  var _a;
@@ -16448,13 +16464,24 @@ class HTMLElementInfo {
16448
16464
  isIntersecting
16449
16465
  } = entry;
16450
16466
  if (target === this.element) {
16451
- this.visible = isIntersecting;
16467
+ this.isIntersecting = isIntersecting;
16452
16468
  this.visibilityChangedAt = Date.now();
16453
16469
  (_a = this.handleVisibilityChanged) === null || _a === void 0 ? void 0 : _a.call(this);
16454
16470
  }
16455
16471
  };
16472
+ this.onEnterPiP = () => {
16473
+ var _a;
16474
+ this.isPiP = true;
16475
+ (_a = this.handleVisibilityChanged) === null || _a === void 0 ? void 0 : _a.call(this);
16476
+ };
16477
+ this.onLeavePiP = () => {
16478
+ var _a;
16479
+ this.isPiP = false;
16480
+ (_a = this.handleVisibilityChanged) === null || _a === void 0 ? void 0 : _a.call(this);
16481
+ };
16456
16482
  this.element = element;
16457
- this.visible = visible !== null && visible !== void 0 ? visible : isElementInViewport(element);
16483
+ this.isIntersecting = visible !== null && visible !== void 0 ? visible : isElementInViewport(element);
16484
+ this.isPiP = isWeb() && document.pictureInPictureElement === element;
16458
16485
  this.visibilityChangedAt = 0;
16459
16486
  }
16460
16487
  width() {
@@ -16464,6 +16491,9 @@ class HTMLElementInfo {
16464
16491
  return this.element.clientHeight;
16465
16492
  }
16466
16493
  observe() {
16494
+ // make sure we update the current visible state once we start to observe
16495
+ this.isIntersecting = isElementInViewport(this.element);
16496
+ this.isPiP = document.pictureInPictureElement === this.element;
16467
16497
  this.element.handleResize = () => {
16468
16498
  var _a;
16469
16499
  (_a = this.handleResize) === null || _a === void 0 ? void 0 : _a.call(this);
@@ -16471,11 +16501,15 @@ class HTMLElementInfo {
16471
16501
  this.element.handleVisibilityChanged = this.onVisibilityChanged;
16472
16502
  getIntersectionObserver().observe(this.element);
16473
16503
  getResizeObserver().observe(this.element);
16504
+ this.element.addEventListener('enterpictureinpicture', this.onEnterPiP);
16505
+ this.element.addEventListener('leavepictureinpicture', this.onLeavePiP);
16474
16506
  }
16475
16507
  stopObserving() {
16476
16508
  var _a, _b;
16477
16509
  (_a = getIntersectionObserver()) === null || _a === void 0 ? void 0 : _a.unobserve(this.element);
16478
16510
  (_b = getResizeObserver()) === null || _b === void 0 ? void 0 : _b.unobserve(this.element);
16511
+ this.element.removeEventListener('enterpictureinpicture', this.onEnterPiP);
16512
+ this.element.removeEventListener('leavepictureinpicture', this.onLeavePiP);
16479
16513
  }
16480
16514
  }
16481
16515
  // does not account for occlusion by other elements
@@ -17340,10 +17374,14 @@ class RemoteTrackPublication extends TrackPublication {
17340
17374
  }
17341
17375
  /** @internal */
17342
17376
  updateInfo(info) {
17343
- var _a;
17344
17377
  super.updateInfo(info);
17378
+ const prevMetadataMuted = this.metadataMuted;
17345
17379
  this.metadataMuted = info.muted;
17346
- (_a = this.track) === null || _a === void 0 ? void 0 : _a.setMuted(info.muted);
17380
+ if (this.track) {
17381
+ this.track.setMuted(info.muted);
17382
+ } else if (prevMetadataMuted !== info.muted) {
17383
+ this.emit(info.muted ? TrackEvent.Muted : TrackEvent.Unmuted);
17384
+ }
17347
17385
  }
17348
17386
  emitSubscriptionUpdateIfChanged(previousStatus) {
17349
17387
  const currentStatus = this.subscriptionStatus;
@@ -19110,6 +19148,7 @@ const roomOptionDefaults = {
19110
19148
  dynacast: false,
19111
19149
  stopLocalTrackOnUnpublish: true,
19112
19150
  reconnectPolicy: new DefaultReconnectPolicy(),
19151
+ disconnectOnPageLeave: true,
19113
19152
  expWebAudioMix: false
19114
19153
  };
19115
19154
  const roomConnectOptionDefaults = {
@@ -20102,22 +20141,28 @@ class RTCEngine extends eventsExports.EventEmitter {
20102
20141
  };
20103
20142
  this.handleDataMessage = async message => {
20104
20143
  var _a, _b;
20105
- // decode
20106
- let buffer;
20107
- if (message.data instanceof ArrayBuffer) {
20108
- buffer = message.data;
20109
- } else if (message.data instanceof Blob) {
20110
- buffer = await message.data.arrayBuffer();
20111
- } else {
20112
- livekitLogger.error('unsupported data type', message.data);
20113
- return;
20114
- }
20115
- const dp = DataPacket.decode(new Uint8Array(buffer));
20116
- if (((_a = dp.value) === null || _a === void 0 ? void 0 : _a.$case) === 'speaker') {
20117
- // dispatch speaker updates
20118
- this.emit(EngineEvent.ActiveSpeakersUpdate, dp.value.speaker.speakers);
20119
- } else if (((_b = dp.value) === null || _b === void 0 ? void 0 : _b.$case) === 'user') {
20120
- this.emit(EngineEvent.DataPacketReceived, dp.value.user, dp.kind);
20144
+ // make sure to respect incoming data message order by processing message events one after the other
20145
+ const unlock = await this.dataProcessLock.lock();
20146
+ try {
20147
+ // decode
20148
+ let buffer;
20149
+ if (message.data instanceof ArrayBuffer) {
20150
+ buffer = message.data;
20151
+ } else if (message.data instanceof Blob) {
20152
+ buffer = await message.data.arrayBuffer();
20153
+ } else {
20154
+ livekitLogger.error('unsupported data type', message.data);
20155
+ return;
20156
+ }
20157
+ const dp = DataPacket.decode(new Uint8Array(buffer));
20158
+ if (((_a = dp.value) === null || _a === void 0 ? void 0 : _a.$case) === 'speaker') {
20159
+ // dispatch speaker updates
20160
+ this.emit(EngineEvent.ActiveSpeakersUpdate, dp.value.speaker.speakers);
20161
+ } else if (((_b = dp.value) === null || _b === void 0 ? void 0 : _b.$case) === 'user') {
20162
+ this.emit(EngineEvent.DataPacketReceived, dp.value.user, dp.kind);
20163
+ }
20164
+ } finally {
20165
+ unlock();
20121
20166
  }
20122
20167
  };
20123
20168
  this.handleDataError = event => {
@@ -20177,6 +20222,7 @@ class RTCEngine extends eventsExports.EventEmitter {
20177
20222
  this.reconnectPolicy = this.options.reconnectPolicy;
20178
20223
  this.registerOnLineListener();
20179
20224
  this.closingLock = new Mutex();
20225
+ this.dataProcessLock = new Mutex();
20180
20226
  }
20181
20227
  async join(url, token, opts, abortSignal) {
20182
20228
  this.url = url;
@@ -21097,8 +21143,10 @@ class Room extends eventsExports.EventEmitter {
21097
21143
  CriticalTimers.clearTimeout(connectTimeout);
21098
21144
  (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal.removeEventListener('abort', abortHandler);
21099
21145
  // also hook unload event
21100
- if (isWeb()) {
21101
- window.addEventListener('beforeunload', this.onBeforeUnload);
21146
+ if (isWeb() && this.options.disconnectOnPageLeave) {
21147
+ // capturing both 'pagehide' and 'beforeunload' to capture broadest set of browser behaviors
21148
+ window.addEventListener('pagehide', this.onPageLeave);
21149
+ window.addEventListener('beforeunload', this.onPageLeave);
21102
21150
  (_b = navigator.mediaDevices) === null || _b === void 0 ? void 0 : _b.addEventListener('devicechange', this.handleDeviceChange);
21103
21151
  }
21104
21152
  this.setAndEmitConnectionState(ConnectionState.Connected);
@@ -21149,7 +21197,7 @@ class Room extends eventsExports.EventEmitter {
21149
21197
  unlock();
21150
21198
  }
21151
21199
  };
21152
- this.onBeforeUnload = async () => {
21200
+ this.onPageLeave = async () => {
21153
21201
  await this.disconnect();
21154
21202
  };
21155
21203
  this.handleRestarting = () => {
@@ -21376,8 +21424,14 @@ class Room extends eventsExports.EventEmitter {
21376
21424
  this.onLocalTrackUnmuted = pub => {
21377
21425
  this.emit(RoomEvent.TrackUnmuted, pub, this.localParticipant);
21378
21426
  };
21379
- this.onLocalTrackPublished = pub => {
21427
+ this.onLocalTrackPublished = async pub => {
21380
21428
  this.emit(RoomEvent.LocalTrackPublished, pub, this.localParticipant);
21429
+ if (pub.track instanceof LocalAudioTrack) {
21430
+ const trackIsSilent = await pub.track.checkForSilence();
21431
+ if (trackIsSilent) {
21432
+ this.emit(RoomEvent.LocalAudioSilenceDetected, pub);
21433
+ }
21434
+ }
21381
21435
  };
21382
21436
  this.onLocalTrackUnpublished = pub => {
21383
21437
  this.emit(RoomEvent.LocalTrackUnpublished, pub, this.localParticipant);
@@ -21756,7 +21810,8 @@ class Room extends eventsExports.EventEmitter {
21756
21810
  this.audioContext = undefined;
21757
21811
  }
21758
21812
  if (isWeb()) {
21759
- window.removeEventListener('beforeunload', this.onBeforeUnload);
21813
+ window.removeEventListener('beforeunload', this.onPageLeave);
21814
+ window.removeEventListener('pagehide', this.onPageLeave);
21760
21815
  (_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.removeEventListener('devicechange', this.handleDeviceChange);
21761
21816
  }
21762
21817
  this.setAndEmitConnectionState(ConnectionState.Disconnected);