livekit-client 1.6.2 → 1.6.4

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 (64) hide show
  1. package/dist/livekit-client.esm.mjs +468 -140
  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 +3 -3
  6. package/dist/src/api/SignalClient.d.ts.map +1 -1
  7. package/dist/src/connectionHelper/ConnectionCheck.d.ts +2 -2
  8. package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
  9. package/dist/src/index.d.ts +2 -1
  10. package/dist/src/index.d.ts.map +1 -1
  11. package/dist/src/proto/livekit_models.d.ts +53 -4
  12. package/dist/src/proto/livekit_models.d.ts.map +1 -1
  13. package/dist/src/proto/livekit_rtc.d.ts +650 -91
  14. package/dist/src/proto/livekit_rtc.d.ts.map +1 -1
  15. package/dist/src/room/PCTransport.d.ts +1 -0
  16. package/dist/src/room/PCTransport.d.ts.map +1 -1
  17. package/dist/src/room/RTCEngine.d.ts +2 -0
  18. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  19. package/dist/src/room/Room.d.ts +1 -1
  20. package/dist/src/room/Room.d.ts.map +1 -1
  21. package/dist/src/room/errors.d.ts +3 -0
  22. package/dist/src/room/errors.d.ts.map +1 -1
  23. package/dist/src/room/participant/LocalParticipant.d.ts +1 -3
  24. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  25. package/dist/src/room/participant/Participant.d.ts +1 -1
  26. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  27. package/dist/src/room/timers.d.ts +13 -0
  28. package/dist/src/room/timers.d.ts.map +1 -0
  29. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
  30. package/dist/src/room/track/create.d.ts.map +1 -1
  31. package/dist/src/room/track/options.d.ts +2 -2
  32. package/dist/src/room/track/options.d.ts.map +1 -1
  33. package/dist/src/test/mocks.d.ts +1 -1
  34. package/dist/ts4.2/src/api/SignalClient.d.ts +3 -3
  35. package/dist/ts4.2/src/connectionHelper/ConnectionCheck.d.ts +2 -2
  36. package/dist/ts4.2/src/index.d.ts +2 -1
  37. package/dist/ts4.2/src/proto/livekit_models.d.ts +59 -4
  38. package/dist/ts4.2/src/proto/livekit_rtc.d.ts +739 -120
  39. package/dist/ts4.2/src/room/PCTransport.d.ts +1 -0
  40. package/dist/ts4.2/src/room/RTCEngine.d.ts +2 -0
  41. package/dist/ts4.2/src/room/Room.d.ts +1 -1
  42. package/dist/ts4.2/src/room/errors.d.ts +3 -0
  43. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +1 -3
  44. package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -1
  45. package/dist/ts4.2/src/room/timers.d.ts +13 -0
  46. package/dist/ts4.2/src/room/track/options.d.ts +2 -2
  47. package/dist/ts4.2/src/test/mocks.d.ts +1 -1
  48. package/package.json +17 -17
  49. package/src/api/SignalClient.ts +33 -21
  50. package/src/connectionHelper/ConnectionCheck.ts +1 -1
  51. package/src/index.ts +2 -0
  52. package/src/proto/google/protobuf/timestamp.ts +2 -2
  53. package/src/proto/livekit_models.ts +158 -10
  54. package/src/proto/livekit_rtc.ts +205 -6
  55. package/src/room/PCTransport.ts +22 -6
  56. package/src/room/RTCEngine.ts +58 -45
  57. package/src/room/Room.ts +8 -10
  58. package/src/room/errors.ts +6 -0
  59. package/src/room/participant/LocalParticipant.ts +12 -17
  60. package/src/room/participant/Participant.ts +10 -2
  61. package/src/room/timers.ts +16 -0
  62. package/src/room/track/RemoteVideoTrack.ts +2 -1
  63. package/src/room/track/create.ts +6 -1
  64. package/src/room/track/options.ts +2 -2
package/src/room/Room.ts CHANGED
@@ -44,6 +44,7 @@ import type Participant from './participant/Participant';
44
44
  import type { ConnectionQuality } from './participant/Participant';
45
45
  import RemoteParticipant from './participant/RemoteParticipant';
46
46
  import RTCEngine from './RTCEngine';
47
+ import CriticalTimers from './timers';
47
48
  import LocalAudioTrack from './track/LocalAudioTrack';
48
49
  import LocalTrackPublication from './track/LocalTrackPublication';
49
50
  import LocalVideoTrack from './track/LocalVideoTrack';
@@ -364,7 +365,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
364
365
  }
365
366
 
366
367
  // don't return until ICE connected
367
- const connectTimeout = setTimeout(() => {
368
+ const connectTimeout = CriticalTimers.setTimeout(() => {
368
369
  // timeout
369
370
  this.recreateEngine();
370
371
  this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
@@ -372,7 +373,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
372
373
  }, this.connOptions.peerConnectionTimeout);
373
374
  const abortHandler = () => {
374
375
  log.warn('closing engine');
375
- clearTimeout(connectTimeout);
376
+ CriticalTimers.clearTimeout(connectTimeout);
376
377
  this.recreateEngine();
377
378
  this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
378
379
  reject(new ConnectionError('room connection has been cancelled'));
@@ -383,7 +384,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
383
384
  this.abortController?.signal.addEventListener('abort', abortHandler);
384
385
 
385
386
  this.engine.once(EngineEvent.Connected, () => {
386
- clearTimeout(connectTimeout);
387
+ CriticalTimers.clearTimeout(connectTimeout);
387
388
  this.abortController?.signal.removeEventListener('abort', abortHandler);
388
389
  // also hook unload event
389
390
  if (isWeb()) {
@@ -842,10 +843,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
842
843
  private handleParticipantUpdates = (participantInfos: ParticipantInfo[]) => {
843
844
  // handle changes to participant state, and send events
844
845
  participantInfos.forEach((info) => {
845
- if (
846
- info.sid === this.localParticipant.sid ||
847
- info.identity === this.localParticipant.identity
848
- ) {
846
+ if (info.identity === this.localParticipant.identity) {
849
847
  this.localParticipant.updateInfo(info);
850
848
  return;
851
849
  }
@@ -1137,7 +1135,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1137
1135
  })
1138
1136
  .on(
1139
1137
  ParticipantEvent.ParticipantPermissionsChanged,
1140
- (prevPermissions: ParticipantPermission) => {
1138
+ (prevPermissions?: ParticipantPermission) => {
1141
1139
  this.emitWhenConnected(
1142
1140
  RoomEvent.ParticipantPermissionsChanged,
1143
1141
  prevPermissions,
@@ -1272,7 +1270,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1272
1270
  this.emit(RoomEvent.MediaDevicesError, e);
1273
1271
  };
1274
1272
 
1275
- private onLocalParticipantPermissionsChanged = (prevPermissions: ParticipantPermission) => {
1273
+ private onLocalParticipantPermissionsChanged = (prevPermissions?: ParticipantPermission) => {
1276
1274
  this.emit(RoomEvent.ParticipantPermissionsChanged, prevPermissions, this.localParticipant);
1277
1275
  };
1278
1276
 
@@ -1441,7 +1439,7 @@ export type RoomEventCallbacks = {
1441
1439
  participant: RemoteParticipant | LocalParticipant,
1442
1440
  ) => void;
1443
1441
  participantPermissionsChanged: (
1444
- prevPermissions: ParticipantPermission,
1442
+ prevPermissions: ParticipantPermission | undefined,
1445
1443
  participant: RemoteParticipant | LocalParticipant,
1446
1444
  ) => void;
1447
1445
  activeSpeakersChanged: (speakers: Array<Participant>) => void;
@@ -25,6 +25,12 @@ export class ConnectionError extends LivekitError {
25
25
  }
26
26
  }
27
27
 
28
+ export class DeviceUnsupportedError extends LivekitError {
29
+ constructor(message?: string) {
30
+ super(21, message ?? 'device is unsupported');
31
+ }
32
+ }
33
+
28
34
  export class TrackInvalidError extends LivekitError {
29
35
  constructor(message?: string) {
30
36
  super(20, message ?? 'track is invalid');
@@ -1,12 +1,7 @@
1
1
  import 'webrtc-adapter';
2
2
  import log from '../../logger';
3
3
  import type { InternalRoomOptions } from '../../options';
4
- import {
5
- DataPacket,
6
- DataPacket_Kind,
7
- ParticipantInfo,
8
- ParticipantPermission,
9
- } from '../../proto/livekit_models';
4
+ import { DataPacket, DataPacket_Kind, ParticipantInfo } from '../../proto/livekit_models';
10
5
  import {
11
6
  AddTrackRequest,
12
7
  DataChannelInfo,
@@ -15,7 +10,7 @@ import {
15
10
  TrackPublishedResponse,
16
11
  TrackUnpublishedResponse,
17
12
  } from '../../proto/livekit_rtc';
18
- import { TrackInvalidError, UnexpectedConnectionState } from '../errors';
13
+ import { DeviceUnsupportedError, TrackInvalidError, UnexpectedConnectionState } from '../errors';
19
14
  import { EngineEvent, ParticipantEvent, TrackEvent } from '../events';
20
15
  import type RTCEngine from '../RTCEngine';
21
16
  import LocalAudioTrack from '../track/LocalAudioTrack';
@@ -168,16 +163,6 @@ export default class LocalParticipant extends Participant {
168
163
  return this.setTrackEnabled(Track.Source.ScreenShare, enabled, options, publishOptions);
169
164
  }
170
165
 
171
- /** @internal */
172
- setPermissions(permissions: ParticipantPermission): boolean {
173
- const prevPermissions = this.permissions;
174
- const changed = super.setPermissions(permissions);
175
- if (changed && prevPermissions) {
176
- this.emit(ParticipantEvent.ParticipantPermissionsChanged, prevPermissions);
177
- }
178
- return changed;
179
- }
180
-
181
166
  /**
182
167
  * Enable or disable publishing for a track by source. This serves as a simple
183
168
  * way to manage the common tracks (camera, mic, or screen share).
@@ -389,6 +374,11 @@ export default class LocalParticipant extends Participant {
389
374
  };
390
375
  }
391
376
  }
377
+
378
+ if (navigator.mediaDevices.getDisplayMedia === undefined) {
379
+ throw new DeviceUnsupportedError('getDisplayMedia not supported');
380
+ }
381
+
392
382
  const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia({
393
383
  audio: options.audio ?? false,
394
384
  video: videoConstraints,
@@ -876,6 +866,11 @@ export default class LocalParticipant extends Participant {
876
866
 
877
867
  /** @internal */
878
868
  updateInfo(info: ParticipantInfo) {
869
+ if (info.sid !== this.sid) {
870
+ // drop updates that specify a wrong sid.
871
+ // the sid for local participant is only explicitly set on join and full reconnect
872
+ return;
873
+ }
879
874
  super.updateInfo(info);
880
875
 
881
876
  // reconcile track mute status.
@@ -173,14 +173,22 @@ export default class Participant extends (EventEmitter as new () => TypedEmitter
173
173
 
174
174
  /** @internal */
175
175
  setPermissions(permissions: ParticipantPermission): boolean {
176
+ const prevPermissions = this.permissions;
176
177
  const changed =
177
178
  permissions.canPublish !== this.permissions?.canPublish ||
178
179
  permissions.canSubscribe !== this.permissions?.canSubscribe ||
179
180
  permissions.canPublishData !== this.permissions?.canPublishData ||
180
181
  permissions.hidden !== this.permissions?.hidden ||
181
- permissions.recorder !== this.permissions?.recorder;
182
+ permissions.recorder !== this.permissions?.recorder ||
183
+ permissions.canPublishSources.length !== this.permissions.canPublishSources.length ||
184
+ permissions.canPublishSources.some(
185
+ (value, index) => value !== this.permissions?.canPublishSources[index],
186
+ );
182
187
  this.permissions = permissions;
183
188
 
189
+ if (changed) {
190
+ this.emit(ParticipantEvent.ParticipantPermissionsChanged, prevPermissions);
191
+ }
184
192
  return changed;
185
193
  }
186
194
 
@@ -257,7 +265,7 @@ export type ParticipantEventCallbacks = {
257
265
  status: TrackPublication.PermissionStatus,
258
266
  ) => void;
259
267
  mediaDevicesError: (error: Error) => void;
260
- participantPermissionsChanged: (prevPermissions: ParticipantPermission) => void;
268
+ participantPermissionsChanged: (prevPermissions?: ParticipantPermission) => void;
261
269
  trackSubscriptionStatusChanged: (
262
270
  publication: RemoteTrackPublication,
263
271
  status: TrackPublication.SubscriptionStatus,
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Timers that can be overridden with platform specific implementations
3
+ * that ensure that they are fired. These should be used when it is critical
4
+ * that the timer fires on time.
5
+ */
6
+ export default class CriticalTimers {
7
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
8
+ static setTimeout = (...args: Parameters<typeof setTimeout>) => setTimeout(...args);
9
+
10
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval
11
+ static setInterval = (...args: Parameters<typeof setInterval>) => setInterval(...args);
12
+
13
+ static clearTimeout = (...args: Parameters<typeof clearTimeout>) => clearTimeout(...args);
14
+
15
+ static clearInterval = (...args: Parameters<typeof clearInterval>) => clearInterval(...args);
16
+ }
@@ -2,6 +2,7 @@ import { debounce } from 'ts-debounce';
2
2
  import log from '../../logger';
3
3
  import { TrackEvent } from '../events';
4
4
  import { computeBitrate, VideoReceiverStats } from '../stats';
5
+ import CriticalTimers from '../timers';
5
6
  import { getIntersectionObserver, getResizeObserver, ObservableMediaElement } from '../utils';
6
7
  import RemoteTrack from './RemoteTrack';
7
8
  import { attachToElement, detachTrack, Track } from './Track';
@@ -233,7 +234,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
233
234
 
234
235
  if (!isVisible && Date.now() - lastVisibilityChange < REACTION_DELAY) {
235
236
  // delay hidden events
236
- setTimeout(() => {
237
+ CriticalTimers.setTimeout(() => {
237
238
  this.updateVisibility();
238
239
  }, REACTION_DELAY);
239
240
  return;
@@ -1,5 +1,5 @@
1
1
  import DeviceManager from '../DeviceManager';
2
- import { TrackInvalidError } from '../errors';
2
+ import { DeviceUnsupportedError, TrackInvalidError } from '../errors';
3
3
  import { mediaTrackToLocalTrack } from '../participant/publishUtils';
4
4
  import { audioDefaults, videoDefaults } from '../defaults';
5
5
  import LocalAudioTrack from './LocalAudioTrack';
@@ -114,6 +114,11 @@ export async function createLocalScreenTracks(
114
114
  height: options.resolution.height,
115
115
  };
116
116
  }
117
+
118
+ if (navigator.mediaDevices.getDisplayMedia === undefined) {
119
+ throw new DeviceUnsupportedError('getDisplayMedia not supported');
120
+ }
121
+
117
122
  // typescript definition is missing getDisplayMedia: https://github.com/microsoft/TypeScript/issues/33232
118
123
  // @ts-ignore
119
124
  const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia({
@@ -232,9 +232,9 @@ export interface AudioPreset {
232
232
  const codecs = ['vp8', 'h264', 'av1'] as const;
233
233
  const backupCodecs = ['vp8', 'h264'] as const;
234
234
 
235
- export type VideoCodec = typeof codecs[number];
235
+ export type VideoCodec = (typeof codecs)[number];
236
236
 
237
- export type BackupVideoCodec = typeof backupCodecs[number];
237
+ export type BackupVideoCodec = (typeof backupCodecs)[number];
238
238
 
239
239
  export function isBackupCodec(codec: string): codec is BackupVideoCodec {
240
240
  return !!backupCodecs.find((backup) => backup === codec);