livekit-client 1.6.3 → 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. package/dist/livekit-client.esm.mjs +418 -70
  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 +13 -2
  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/proto/livekit_models.d.ts +20 -3
  10. package/dist/src/proto/livekit_models.d.ts.map +1 -1
  11. package/dist/src/proto/livekit_rtc.d.ts +2565 -464
  12. package/dist/src/proto/livekit_rtc.d.ts.map +1 -1
  13. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  14. package/dist/src/room/Room.d.ts +1 -1
  15. package/dist/src/room/Room.d.ts.map +1 -1
  16. package/dist/src/room/errors.d.ts +3 -0
  17. package/dist/src/room/errors.d.ts.map +1 -1
  18. package/dist/src/room/participant/LocalParticipant.d.ts +1 -3
  19. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  20. package/dist/src/room/participant/Participant.d.ts +1 -1
  21. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  22. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  23. package/dist/src/room/track/create.d.ts.map +1 -1
  24. package/dist/src/room/track/options.d.ts +2 -2
  25. package/dist/src/room/track/options.d.ts.map +1 -1
  26. package/dist/src/test/mocks.d.ts +1 -1
  27. package/dist/ts4.2/src/api/SignalClient.d.ts +13 -2
  28. package/dist/ts4.2/src/connectionHelper/ConnectionCheck.d.ts +2 -2
  29. package/dist/ts4.2/src/proto/livekit_models.d.ts +24 -3
  30. package/dist/ts4.2/src/proto/livekit_rtc.d.ts +2775 -540
  31. package/dist/ts4.2/src/room/Room.d.ts +1 -1
  32. package/dist/ts4.2/src/room/errors.d.ts +3 -0
  33. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +1 -3
  34. package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -1
  35. package/dist/ts4.2/src/room/track/options.d.ts +2 -2
  36. package/dist/ts4.2/src/test/mocks.d.ts +1 -1
  37. package/package.json +17 -17
  38. package/src/api/SignalClient.ts +46 -3
  39. package/src/connectionHelper/ConnectionCheck.ts +1 -1
  40. package/src/proto/google/protobuf/timestamp.ts +2 -2
  41. package/src/proto/livekit_models.ts +93 -9
  42. package/src/proto/livekit_rtc.ts +308 -6
  43. package/src/room/RTCEngine.ts +37 -16
  44. package/src/room/Room.ts +12 -11
  45. package/src/room/errors.ts +6 -0
  46. package/src/room/participant/LocalParticipant.ts +19 -20
  47. package/src/room/participant/Participant.ts +10 -2
  48. package/src/room/track/LocalAudioTrack.ts +5 -1
  49. package/src/room/track/create.ts +6 -1
  50. package/src/room/track/options.ts +2 -2
package/src/room/Room.ts CHANGED
@@ -355,12 +355,16 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
355
355
  } catch (err) {
356
356
  this.recreateEngine();
357
357
  this.handleDisconnect(this.options.stopLocalTrackOnUnpublish);
358
- let errorMessage = '';
358
+ const resultingError = new ConnectionError(`could not establish signal connection`);
359
359
  if (err instanceof Error) {
360
- errorMessage = err.message;
361
- log.debug(`error trying to establish signal connection`, { error: err });
360
+ resultingError.message = `${resultingError.message}: ${err.message}`;
362
361
  }
363
- reject(new ConnectionError(`could not establish signal connection: ${errorMessage}`));
362
+ if (err instanceof ConnectionError) {
363
+ resultingError.reason = err.reason;
364
+ resultingError.status = err.status;
365
+ }
366
+ log.debug(`error trying to establish signal connection`, { error: err });
367
+ reject(resultingError);
364
368
  return;
365
369
  }
366
370
 
@@ -843,10 +847,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
843
847
  private handleParticipantUpdates = (participantInfos: ParticipantInfo[]) => {
844
848
  // handle changes to participant state, and send events
845
849
  participantInfos.forEach((info) => {
846
- if (
847
- info.sid === this.localParticipant.sid ||
848
- info.identity === this.localParticipant.identity
849
- ) {
850
+ if (info.identity === this.localParticipant.identity) {
850
851
  this.localParticipant.updateInfo(info);
851
852
  return;
852
853
  }
@@ -1138,7 +1139,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1138
1139
  })
1139
1140
  .on(
1140
1141
  ParticipantEvent.ParticipantPermissionsChanged,
1141
- (prevPermissions: ParticipantPermission) => {
1142
+ (prevPermissions?: ParticipantPermission) => {
1142
1143
  this.emitWhenConnected(
1143
1144
  RoomEvent.ParticipantPermissionsChanged,
1144
1145
  prevPermissions,
@@ -1273,7 +1274,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1273
1274
  this.emit(RoomEvent.MediaDevicesError, e);
1274
1275
  };
1275
1276
 
1276
- private onLocalParticipantPermissionsChanged = (prevPermissions: ParticipantPermission) => {
1277
+ private onLocalParticipantPermissionsChanged = (prevPermissions?: ParticipantPermission) => {
1277
1278
  this.emit(RoomEvent.ParticipantPermissionsChanged, prevPermissions, this.localParticipant);
1278
1279
  };
1279
1280
 
@@ -1442,7 +1443,7 @@ export type RoomEventCallbacks = {
1442
1443
  participant: RemoteParticipant | LocalParticipant,
1443
1444
  ) => void;
1444
1445
  participantPermissionsChanged: (
1445
- prevPermissions: ParticipantPermission,
1446
+ prevPermissions: ParticipantPermission | undefined,
1446
1447
  participant: RemoteParticipant | LocalParticipant,
1447
1448
  ) => void;
1448
1449
  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.
@@ -1004,7 +999,9 @@ export default class LocalParticipant extends Participant {
1004
999
  // detect granted change after permissions were denied to try and resume then
1005
1000
  currentPermissions.onchange = () => {
1006
1001
  if (currentPermissions.state !== 'denied') {
1007
- track.restartTrack();
1002
+ if (!track.isMuted) {
1003
+ track.restartTrack();
1004
+ }
1008
1005
  currentPermissions.onchange = null;
1009
1006
  }
1010
1007
  };
@@ -1014,8 +1011,10 @@ export default class LocalParticipant extends Participant {
1014
1011
  // permissions query fails for firefox, we continue and try to restart the track
1015
1012
  }
1016
1013
  }
1017
- log.debug('track ended, attempting to use a different device');
1018
- await track.restartTrack();
1014
+ if (!track.isMuted) {
1015
+ log.debug('track ended, attempting to use a different device');
1016
+ await track.restartTrack();
1017
+ }
1019
1018
  } catch (e) {
1020
1019
  log.warn(`could not restart track, muting instead`);
1021
1020
  await track.mute();
@@ -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,
@@ -53,7 +53,11 @@ export default class LocalAudioTrack extends LocalTrack {
53
53
 
54
54
  async unmute(): Promise<LocalAudioTrack> {
55
55
  await this.muteQueue.run(async () => {
56
- if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) {
56
+ if (
57
+ this.source === Track.Source.Microphone &&
58
+ (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended') &&
59
+ !this.isUserProvided
60
+ ) {
57
61
  log.debug('reacquiring mic track');
58
62
  await this.restartTrack();
59
63
  }
@@ -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);