livekit-client 1.10.0 → 1.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. package/dist/livekit-client.esm.mjs +504 -527
  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/connectionHelper/ConnectionCheck.d.ts +2 -3
  6. package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
  7. package/dist/src/connectionHelper/checks/Checker.d.ts +2 -3
  8. package/dist/src/connectionHelper/checks/Checker.d.ts.map +1 -1
  9. package/dist/src/room/PCTransport.d.ts +1 -1
  10. package/dist/src/room/PCTransport.d.ts.map +1 -1
  11. package/dist/src/room/RTCEngine.d.ts +2 -4
  12. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  13. package/dist/src/room/Room.d.ts +3 -4
  14. package/dist/src/room/Room.d.ts.map +1 -1
  15. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  16. package/dist/src/room/participant/Participant.d.ts +2 -4
  17. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  18. package/dist/src/room/participant/RemoteParticipant.d.ts +2 -1
  19. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  20. package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
  21. package/dist/src/room/track/LocalTrack.d.ts +3 -2
  22. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  23. package/dist/src/room/track/LocalVideoTrack.d.ts +1 -1
  24. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  25. package/dist/src/room/track/RemoteVideoTrack.d.ts +1 -0
  26. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
  27. package/dist/src/room/track/Track.d.ts +2 -4
  28. package/dist/src/room/track/Track.d.ts.map +1 -1
  29. package/dist/src/room/track/TrackPublication.d.ts +2 -4
  30. package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
  31. package/dist/src/room/track/options.d.ts +13 -4
  32. package/dist/src/room/track/options.d.ts.map +1 -1
  33. package/dist/src/room/track/types.d.ts +2 -1
  34. package/dist/src/room/track/types.d.ts.map +1 -1
  35. package/dist/src/room/utils.d.ts.map +1 -1
  36. package/dist/ts4.2/src/connectionHelper/ConnectionCheck.d.ts +2 -3
  37. package/dist/ts4.2/src/connectionHelper/checks/Checker.d.ts +2 -3
  38. package/dist/ts4.2/src/room/PCTransport.d.ts +1 -1
  39. package/dist/ts4.2/src/room/RTCEngine.d.ts +2 -4
  40. package/dist/ts4.2/src/room/Room.d.ts +3 -4
  41. package/dist/ts4.2/src/room/participant/Participant.d.ts +2 -4
  42. package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +2 -1
  43. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -2
  44. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +1 -1
  45. package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +1 -0
  46. package/dist/ts4.2/src/room/track/Track.d.ts +2 -4
  47. package/dist/ts4.2/src/room/track/TrackPublication.d.ts +2 -4
  48. package/dist/ts4.2/src/room/track/options.d.ts +13 -4
  49. package/dist/ts4.2/src/room/track/types.d.ts +2 -1
  50. package/package.json +2 -3
  51. package/src/connectionHelper/ConnectionCheck.ts +2 -3
  52. package/src/connectionHelper/checks/Checker.ts +2 -3
  53. package/src/logger.ts +4 -4
  54. package/src/room/PCTransport.ts +1 -1
  55. package/src/room/RTCEngine.ts +4 -4
  56. package/src/room/Room.ts +41 -11
  57. package/src/room/participant/LocalParticipant.ts +11 -3
  58. package/src/room/participant/Participant.ts +2 -4
  59. package/src/room/participant/RemoteParticipant.ts +4 -3
  60. package/src/room/participant/publishUtils.ts +16 -18
  61. package/src/room/track/LocalTrack.ts +68 -46
  62. package/src/room/track/LocalVideoTrack.ts +9 -7
  63. package/src/room/track/RemoteVideoTrack.ts +23 -6
  64. package/src/room/track/Track.ts +2 -4
  65. package/src/room/track/TrackPublication.ts +2 -4
  66. package/src/room/track/options.ts +13 -4
  67. package/src/room/track/types.ts +2 -1
  68. package/src/room/utils.ts +6 -3
@@ -1,4 +1,4 @@
1
- import type TypedEmitter from 'typed-emitter';
1
+ import EventEmitter from 'eventemitter3';
2
2
  import { DataPacket_Kind, ParticipantInfo, ParticipantPermission, ConnectionQuality as ProtoQuality, SubscriptionError } from '../../proto/livekit_models';
3
3
  import type LocalTrackPublication from '../track/LocalTrackPublication';
4
4
  import type RemoteTrack from '../track/RemoteTrack';
@@ -11,8 +11,7 @@ export declare enum ConnectionQuality {
11
11
  Poor = "poor",
12
12
  Unknown = "unknown"
13
13
  }
14
- declare const Participant_base: new () => TypedEmitter<ParticipantEventCallbacks>;
15
- export default class Participant extends Participant_base {
14
+ export default class Participant extends EventEmitter<ParticipantEventCallbacks> {
16
15
  protected participantInfo?: ParticipantInfo;
17
16
  audioTracks: Map<string, TrackPublication>;
18
17
  videoTracks: Map<string, TrackPublication>;
@@ -90,5 +89,4 @@ export type ParticipantEventCallbacks = {
90
89
  participantPermissionsChanged: (prevPermissions?: ParticipantPermission) => void;
91
90
  trackSubscriptionStatusChanged: (publication: RemoteTrackPublication, status: TrackPublication.SubscriptionStatus) => void;
92
91
  };
93
- export {};
94
92
  //# sourceMappingURL=Participant.d.ts.map
@@ -1,3 +1,4 @@
1
+ import type EventEmitter from 'eventemitter3';
1
2
  import type { SignalClient } from '../../api/SignalClient';
2
3
  import type { ParticipantInfo } from '../../proto/livekit_models';
3
4
  import RemoteTrackPublication from '../track/RemoteTrackPublication';
@@ -48,6 +49,6 @@ export default class RemoteParticipant extends Participant {
48
49
  */
49
50
  setAudioOutput(output: AudioOutputOptions): Promise<void>;
50
51
  /** @internal */
51
- emit<E extends keyof ParticipantEventCallbacks>(event: E, ...args: Parameters<ParticipantEventCallbacks[E]>): boolean;
52
+ emit<T extends EventEmitter.EventNames<ParticipantEventCallbacks>>(event: T, ...args: EventEmitter.EventArgs<ParticipantEventCallbacks, T>): boolean;
52
53
  }
53
54
  //# sourceMappingURL=RemoteParticipant.d.ts.map
@@ -29,6 +29,7 @@ export default abstract class LocalTrack extends Track {
29
29
  get isUpstreamPaused(): boolean;
30
30
  get isUserProvided(): boolean;
31
31
  get mediaStreamTrack(): MediaStreamTrack;
32
+ private setMediaStreamTrack;
32
33
  waitForDimensions(timeout?: number): Promise<Track.Dimensions>;
33
34
  /**
34
35
  * @returns DeviceID of the device that is currently being used for this track
@@ -49,8 +50,8 @@ export default abstract class LocalTrack extends Track {
49
50
  * the server.
50
51
  * this API is unsupported on Safari < 12 due to a bug
51
52
  **/
52
- pauseUpstream(): Promise<void>;
53
- resumeUpstream(): Promise<void>;
53
+ pauseUpstream: () => Promise<void>;
54
+ resumeUpstream: () => Promise<void>;
54
55
  /**
55
56
  * Sets a processor on this track.
56
57
  * See https://github.com/livekit/track-processors-js for example usage
@@ -50,5 +50,5 @@ export default class LocalVideoTrack extends LocalTrack {
50
50
  protected handleAppVisibilityChanged(): Promise<void>;
51
51
  }
52
52
  export declare function videoQualityForRid(rid: string): VideoQuality;
53
- export declare function videoLayersFromEncodings(width: number, height: number, encodings?: RTCRtpEncodingParameters[]): VideoLayer[];
53
+ export declare function videoLayersFromEncodings(width: number, height: number, encodings?: RTCRtpEncodingParameters[], svc?: boolean): VideoLayer[];
54
54
  //# sourceMappingURL=LocalVideoTrack.d.ts.map
@@ -37,6 +37,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
37
37
  private readonly debouncedHandleResize;
38
38
  private updateVisibility;
39
39
  private updateDimensions;
40
+ private getPixelDensity;
40
41
  }
41
42
  export interface ElementInfo {
42
43
  element: object;
@@ -1,9 +1,8 @@
1
- import type TypedEventEmitter from 'typed-emitter';
1
+ import EventEmitter from 'eventemitter3';
2
2
  import type { SignalClient } from '../../api/SignalClient';
3
3
  import { TrackSource, TrackType } from '../../proto/livekit_models';
4
4
  import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc';
5
- declare const Track_base: new () => TypedEventEmitter<TrackEventCallbacks>;
6
- export declare abstract class Track extends Track_base {
5
+ export declare abstract class Track extends EventEmitter<TrackEventCallbacks> {
7
6
  kind: Track.Kind;
8
7
  attachedElements: HTMLMediaElement[];
9
8
  isMuted: boolean;
@@ -121,5 +120,4 @@ export type TrackEventCallbacks = {
121
120
  upstreamPaused: (track: any) => void;
122
121
  upstreamResumed: (track: any) => void;
123
122
  };
124
- export {};
125
123
  //# sourceMappingURL=Track.d.ts.map
@@ -1,4 +1,4 @@
1
- import type TypedEventEmitter from 'typed-emitter';
1
+ import EventEmitter from 'eventemitter3';
2
2
  import type { SubscriptionError, TrackInfo } from '../../proto/livekit_models';
3
3
  import type { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc';
4
4
  import LocalAudioTrack from './LocalAudioTrack';
@@ -7,8 +7,7 @@ import RemoteAudioTrack from './RemoteAudioTrack';
7
7
  import type RemoteTrack from './RemoteTrack';
8
8
  import RemoteVideoTrack from './RemoteVideoTrack';
9
9
  import { Track } from './Track';
10
- declare const TrackPublication_base: new () => TypedEventEmitter<PublicationEventCallbacks>;
11
- export declare class TrackPublication extends TrackPublication_base {
10
+ export declare class TrackPublication extends EventEmitter<PublicationEventCallbacks> {
12
11
  kind: Track.Kind;
13
12
  trackName: string;
14
13
  trackSid: Track.SID;
@@ -65,5 +64,4 @@ export type PublicationEventCallbacks = {
65
64
  subscriptionStatusChanged: (status: TrackPublication.SubscriptionStatus, prevStatus: TrackPublication.SubscriptionStatus) => void;
66
65
  subscriptionFailed: (error: SubscriptionError) => void;
67
66
  };
68
- export {};
69
67
  //# sourceMappingURL=TrackPublication.d.ts.map
@@ -54,10 +54,19 @@ export interface TrackPublishDefaults {
54
54
  */
55
55
  scalabilityMode?: ScalabilityMode;
56
56
  /**
57
- * custom video simulcast layers for camera tracks, defaults to h180, h360
58
- * You can specify up to two custom layers that will be used instead of
59
- * the LiveKit default layers.
60
- * Note: the layers need to be ordered from lowest to highest quality
57
+ * Up to two additional simulcast layers to publish in addition to the original
58
+ * Track.
59
+ * When left blank, it defaults to h180, h360.
60
+ * If a SVC codec is used (VP9 or AV1), this field has no effect.
61
+ *
62
+ * To publish three total layers, you would specify:
63
+ * {
64
+ * videoEncoding: {...}, // encoding of the primary layer
65
+ * videoSimulcastLayers: [
66
+ * VideoPresets.h540,
67
+ * VideoPresets.h216,
68
+ * ],
69
+ * }
61
70
  */
62
71
  videoSimulcastLayers?: Array<VideoPreset>;
63
72
  /**
@@ -6,7 +6,8 @@ export type AudioTrack = RemoteAudioTrack | LocalAudioTrack;
6
6
  export type VideoTrack = RemoteVideoTrack | LocalVideoTrack;
7
7
  export type AdaptiveStreamSettings = {
8
8
  /**
9
- * Set a custom pixel density, defaults to 1
9
+ * Set a custom pixel density. Defaults to 2 for high density screens (3+) or
10
+ * 1 otherwise.
10
11
  * When streaming videos on a ultra high definition screen this setting
11
12
  * let's you account for the devicePixelRatio of those screens.
12
13
  * Set it to `screen` to use the actual pixel density of the screen
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livekit-client",
3
- "version": "1.10.0",
3
+ "version": "1.11.1",
4
4
  "description": "JavaScript/TypeScript client SDK for LiveKit",
5
5
  "main": "./dist/livekit-client.umd.js",
6
6
  "unpkg": "./dist/livekit-client.umd.js",
@@ -42,12 +42,11 @@
42
42
  "size-limit": "size-limit"
43
43
  },
44
44
  "dependencies": {
45
- "events": "^3.3.0",
45
+ "eventemitter3": "^5.0.1",
46
46
  "loglevel": "^1.8.0",
47
47
  "protobufjs": "^7.0.0",
48
48
  "sdp-transform": "^2.14.1",
49
49
  "ts-debounce": "^4.0.0",
50
- "typed-emitter": "^2.1.0",
51
50
  "webrtc-adapter": "^8.1.1"
52
51
  },
53
52
  "devDependencies": {
@@ -1,5 +1,4 @@
1
- import { EventEmitter } from 'events';
2
- import type TypedEmitter from 'typed-emitter';
1
+ import EventEmitter from 'eventemitter3';
3
2
  import { CheckStatus, Checker } from './checks/Checker';
4
3
  import type { CheckInfo, InstantiableCheck } from './checks/Checker';
5
4
  import { PublishAudioCheck } from './checks/publishAudio';
@@ -11,7 +10,7 @@ import { WebSocketCheck } from './checks/websocket';
11
10
 
12
11
  export type { CheckInfo, CheckStatus };
13
12
 
14
- export class ConnectionCheck extends (EventEmitter as new () => TypedEmitter<ConnectionCheckCallbacks>) {
13
+ export class ConnectionCheck extends EventEmitter<ConnectionCheckCallbacks> {
15
14
  token: string;
16
15
 
17
16
  url: string;
@@ -1,5 +1,4 @@
1
- import { EventEmitter } from 'events';
2
- import type TypedEmitter from 'typed-emitter';
1
+ import EventEmitter from 'eventemitter3';
3
2
  import type { RoomConnectOptions, RoomOptions } from '../../options';
4
3
  import type RTCEngine from '../../room/RTCEngine';
5
4
  import Room, { ConnectionState } from '../../room/Room';
@@ -30,7 +29,7 @@ export interface CheckerOptions {
30
29
  connectOptions?: RoomConnectOptions;
31
30
  }
32
31
 
33
- export abstract class Checker extends (EventEmitter as new () => TypedEmitter<CheckerCallbacks>) {
32
+ export abstract class Checker extends EventEmitter<CheckerCallbacks> {
34
33
  protected url: string;
35
34
 
36
35
  protected token: string;
package/src/logger.ts CHANGED
@@ -21,7 +21,7 @@ type StructuredLogger = {
21
21
 
22
22
  const livekitLogger = log.getLogger('livekit');
23
23
 
24
- livekitLogger.setLevel(LogLevel.info);
24
+ livekitLogger.setDefaultLevel(LogLevel.info);
25
25
 
26
26
  export default livekitLogger as StructuredLogger;
27
27
 
@@ -38,10 +38,10 @@ export type LogExtension = (level: LogLevel, msg: string, context?: object) => v
38
38
  export function setLogExtension(extension: LogExtension) {
39
39
  const originalFactory = livekitLogger.methodFactory;
40
40
 
41
- livekitLogger.methodFactory = (methodName, logLevel, loggerName) => {
42
- const rawMethod = originalFactory(methodName, logLevel, loggerName);
41
+ livekitLogger.methodFactory = (methodName, configLevel, loggerName) => {
42
+ const rawMethod = originalFactory(methodName, configLevel, loggerName);
43
43
 
44
- const configLevel = livekitLogger.getLevel();
44
+ const logLevel = LogLevel[methodName as LogLevelString];
45
45
  const needLog = logLevel >= configLevel && logLevel < LogLevel.silent;
46
46
 
47
47
  return (msg, context?: [msg: string, context: object]) => {
@@ -1,4 +1,4 @@
1
- import { EventEmitter } from 'events';
1
+ import EventEmitter from 'eventemitter3';
2
2
  import { parse, write } from 'sdp-transform';
3
3
  import type { MediaDescription } from 'sdp-transform';
4
4
  import { debounce } from 'ts-debounce';
@@ -1,5 +1,4 @@
1
- import { EventEmitter } from 'events';
2
- import type TypedEventEmitter from 'typed-emitter';
1
+ import EventEmitter from 'eventemitter3';
3
2
  import { SignalClient } from '../api/SignalClient';
4
3
  import type { SignalOptions } from '../api/SignalClient';
5
4
  import log from '../logger';
@@ -65,7 +64,7 @@ enum PCState {
65
64
  }
66
65
 
67
66
  /** @internal */
68
- export default class RTCEngine extends (EventEmitter as new () => TypedEventEmitter<EngineEventCallbacks>) {
67
+ export default class RTCEngine extends EventEmitter<EngineEventCallbacks> {
69
68
  publisher?: PCTransport;
70
69
 
71
70
  subscriber?: PCTransport;
@@ -1046,6 +1045,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1046
1045
  };
1047
1046
  this.once(EngineEvent.Restarted, onRestarted);
1048
1047
  this.once(EngineEvent.Disconnected, onDisconnected);
1048
+ this.once(EngineEvent.Closing, onDisconnected);
1049
1049
  });
1050
1050
  };
1051
1051
 
@@ -1172,7 +1172,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1172
1172
  this.hasPublished = true;
1173
1173
 
1174
1174
  const handleClosed = () => {
1175
- log.debug('engine disconnected while negotiation was ongoing');
1175
+ log.warn('engine disconnected while negotiation was ongoing');
1176
1176
  cleanup();
1177
1177
  resolve();
1178
1178
  return;
package/src/room/Room.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { EventEmitter } from 'events';
2
- import type TypedEmitter from 'typed-emitter';
1
+ import EventEmitter from 'eventemitter3';
3
2
  import 'webrtc-adapter';
4
3
  import { toProtoSessionDescription } from '../api/SignalClient';
5
4
  import log from '../logger';
@@ -65,6 +64,7 @@ import {
65
64
  createDummyVideoStreamTrack,
66
65
  getEmptyAudioStreamTrack,
67
66
  isCloud,
67
+ isSafari,
68
68
  isWeb,
69
69
  supportsSetSinkId,
70
70
  unpackStreamId,
@@ -90,7 +90,7 @@ export const RoomState = ConnectionState;
90
90
  *
91
91
  * @noInheritDoc
92
92
  */
93
- class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>) {
93
+ class Room extends EventEmitter<RoomEventCallbacks> {
94
94
  state: ConnectionState = ConnectionState.Disconnected;
95
95
 
96
96
  /** map of sid: [[RemoteParticipant]] */
@@ -140,7 +140,6 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
140
140
  */
141
141
  constructor(options?: RoomOptions) {
142
142
  super();
143
- this.setMaxListeners(100);
144
143
  this.participants = new Map();
145
144
  this.cachedParticipantSids = [];
146
145
  this.identityToSid = new Map();
@@ -495,6 +494,9 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
495
494
  // capturing both 'pagehide' and 'beforeunload' to capture broadest set of browser behaviors
496
495
  window.addEventListener('pagehide', this.onPageLeave);
497
496
  window.addEventListener('beforeunload', this.onPageLeave);
497
+ }
498
+ if (isWeb()) {
499
+ document.addEventListener('freeze', this.onPageLeave);
498
500
  navigator.mediaDevices?.addEventListener('devicechange', this.handleDeviceChange);
499
501
  }
500
502
  this.setAndEmitConnectionState(ConnectionState.Connected);
@@ -657,8 +659,31 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
657
659
  */
658
660
  async startAudio() {
659
661
  await this.acquireAudioContext();
660
-
661
662
  const elements: Array<HTMLMediaElement> = [];
663
+
664
+ if (isSafari()) {
665
+ /**
666
+ * iOS Safari blocks audio element playback if
667
+ * - user is not publishing audio themselves and
668
+ * - no other audio source is playing
669
+ *
670
+ * as a workaround, we create an audio element with an empty track, so that
671
+ * silent audio is always playing
672
+ */
673
+ const audioId = 'livekit-dummy-audio-el';
674
+ let dummyAudioEl = document.getElementById(audioId) as HTMLAudioElement | null;
675
+ if (!dummyAudioEl) {
676
+ dummyAudioEl = document.createElement('audio');
677
+ dummyAudioEl.autoplay = true;
678
+ dummyAudioEl.hidden = true;
679
+ const track = getEmptyAudioStreamTrack();
680
+ track.enabled = true;
681
+ dummyAudioEl.srcObject = new MediaStream([track]);
682
+ document.body.append(dummyAudioEl);
683
+ }
684
+ elements.push(dummyAudioEl);
685
+ }
686
+
662
687
  this.participants.forEach((p) => {
663
688
  p.audioTracks.forEach((t) => {
664
689
  if (t.track) {
@@ -965,6 +990,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
965
990
  if (isWeb()) {
966
991
  window.removeEventListener('beforeunload', this.onPageLeave);
967
992
  window.removeEventListener('pagehide', this.onPageLeave);
993
+ window.removeEventListener('freeze', this.onPageLeave);
968
994
  navigator.mediaDevices?.removeEventListener('devicechange', this.handleDeviceChange);
969
995
  }
970
996
  } finally {
@@ -1420,9 +1446,9 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1420
1446
  return true;
1421
1447
  }
1422
1448
 
1423
- private emitWhenConnected<E extends keyof RoomEventCallbacks>(
1424
- event: E,
1425
- ...args: Parameters<RoomEventCallbacks[E]>
1449
+ private emitWhenConnected<T extends EventEmitter.EventNames<RoomEventCallbacks>>(
1450
+ event: T,
1451
+ ...args: EventEmitter.EventArgs<RoomEventCallbacks, T>
1426
1452
  ): boolean {
1427
1453
  if (this.state === ConnectionState.Connected) {
1428
1454
  return this.emit(event, ...args);
@@ -1599,10 +1625,14 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1599
1625
  }
1600
1626
 
1601
1627
  // /** @internal */
1602
- emit<E extends keyof RoomEventCallbacks>(
1603
- event: E,
1604
- ...args: Parameters<RoomEventCallbacks[E]>
1628
+ emit<T extends EventEmitter.EventNames<RoomEventCallbacks>>(
1629
+ event: T,
1630
+ ...args: EventEmitter.EventArgs<RoomEventCallbacks, T>
1605
1631
  ): boolean {
1632
+ // emit<E extends keyof RoomEventCallbacks>(
1633
+ // event: E,
1634
+ // ...args: Parameters<RoomEventCallbacks[E]>
1635
+ // ): boolean {
1606
1636
  // active speaker updates are too spammy
1607
1637
  if (event !== RoomEvent.ActiveSpeakersChanged) {
1608
1638
  log.debug(`room event ${event}`, { event, args });
@@ -143,8 +143,11 @@ export default class LocalParticipant extends Participant {
143
143
  };
144
144
 
145
145
  private handleDisconnected = () => {
146
- this.reconnectFuture?.reject?.('Got disconnected during publishing attempt');
147
- this.reconnectFuture = undefined;
146
+ if (this.reconnectFuture) {
147
+ this.reconnectFuture.promise.catch((e) => log.warn(e));
148
+ this.reconnectFuture?.reject?.('Got disconnected during reconnection attempt');
149
+ this.reconnectFuture = undefined;
150
+ }
148
151
  };
149
152
 
150
153
  /**
@@ -666,7 +669,12 @@ export default class LocalParticipant extends Participant {
666
669
  dims.height,
667
670
  opts,
668
671
  );
669
- req.layers = videoLayersFromEncodings(req.width, req.height, encodings);
672
+ req.layers = videoLayersFromEncodings(
673
+ req.width,
674
+ req.height,
675
+ encodings,
676
+ isSVCCodec(opts.videoCodec),
677
+ );
670
678
  } else if (track.kind === Track.Kind.Audio) {
671
679
  encodings = [
672
680
  {
@@ -1,5 +1,4 @@
1
- import { EventEmitter } from 'events';
2
- import type TypedEmitter from 'typed-emitter';
1
+ import EventEmitter from 'eventemitter3';
3
2
  import log from '../../logger';
4
3
  import {
5
4
  DataPacket_Kind,
@@ -35,7 +34,7 @@ function qualityFromProto(q: ProtoQuality): ConnectionQuality {
35
34
  }
36
35
  }
37
36
 
38
- export default class Participant extends (EventEmitter as new () => TypedEmitter<ParticipantEventCallbacks>) {
37
+ export default class Participant extends EventEmitter<ParticipantEventCallbacks> {
39
38
  protected participantInfo?: ParticipantInfo;
40
39
 
41
40
  audioTracks: Map<string, TrackPublication>;
@@ -72,7 +71,6 @@ export default class Participant extends (EventEmitter as new () => TypedEmitter
72
71
  /** @internal */
73
72
  constructor(sid: string, identity: string, name?: string, metadata?: string) {
74
73
  super();
75
- this.setMaxListeners(100);
76
74
  this.sid = sid;
77
75
  this.identity = identity;
78
76
  this.name = name;
@@ -1,3 +1,4 @@
1
+ import type EventEmitter from 'eventemitter3';
1
2
  import type { SignalClient } from '../../api/SignalClient';
2
3
  import log from '../../logger';
3
4
  import type { ParticipantInfo, SubscriptionError } from '../../proto/livekit_models';
@@ -345,9 +346,9 @@ export default class RemoteParticipant extends Participant {
345
346
  }
346
347
 
347
348
  /** @internal */
348
- emit<E extends keyof ParticipantEventCallbacks>(
349
- event: E,
350
- ...args: Parameters<ParticipantEventCallbacks[E]>
349
+ emit<T extends EventEmitter.EventNames<ParticipantEventCallbacks>>(
350
+ event: T,
351
+ ...args: EventEmitter.EventArgs<ParticipantEventCallbacks, T>
351
352
  ): boolean {
352
353
  log.trace('participant event', { participant: this.sid, event, args });
353
354
  return super.emit(event, ...args);
@@ -123,27 +123,25 @@ export function computeVideoEncodings(
123
123
  if (scalabilityMode && isSVCCodec(videoCodec)) {
124
124
  log.debug(`using svc with scalabilityMode ${scalabilityMode}`);
125
125
 
126
- const encodings: RTCRtpEncodingParameters[] = [];
126
+ const sm = new ScalabilityMode(scalabilityMode);
127
127
 
128
- // svc use first encoding as the original, so we sort encoding from high to low
129
- switch (scalabilityMode) {
130
- case 'L3T3':
131
- case 'L3T3_KEY':
132
- encodings.push({
133
- rid: videoRids[2],
134
- maxBitrate: videoEncoding.maxBitrate,
135
- /* @ts-ignore */
136
- maxFramerate: original.encoding.maxFramerate,
137
- /* @ts-ignore */
138
- scalabilityMode: scalabilityMode,
139
- });
140
- log.debug('encodings', encodings);
141
- return encodings;
128
+ const encodings: RTCRtpEncodingParameters[] = [];
142
129
 
143
- default:
144
- // TODO : support other scalability modes
145
- throw new Error(`unsupported scalabilityMode: ${scalabilityMode}`);
130
+ if (sm.spatial > 3) {
131
+ throw new Error(`unsupported scalabilityMode: ${scalabilityMode}`);
132
+ }
133
+ for (let i = 0; i < sm.spatial; i += 1) {
134
+ encodings.push({
135
+ rid: videoRids[2 - i],
136
+ maxBitrate: videoEncoding.maxBitrate / 3 ** i,
137
+ /* @ts-ignore */
138
+ maxFramerate: original.encoding.maxFramerate,
139
+ });
146
140
  }
141
+ /* @ts-ignore */
142
+ encodings[0].scalabilityMode = scalabilityMode;
143
+ log.debug('encodings', encodings);
144
+ return encodings;
147
145
  }
148
146
 
149
147
  if (!useSimulcast) {