livekit-client 1.15.11 → 2.0.0

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 (76) hide show
  1. package/README.md +21 -17
  2. package/dist/livekit-client.esm.mjs +1573 -1479
  3. package/dist/livekit-client.esm.mjs.map +1 -1
  4. package/dist/livekit-client.umd.js +1 -1
  5. package/dist/livekit-client.umd.js.map +1 -1
  6. package/dist/src/api/SignalClient.d.ts +0 -2
  7. package/dist/src/api/SignalClient.d.ts.map +1 -1
  8. package/dist/src/index.d.ts +3 -3
  9. package/dist/src/index.d.ts.map +1 -1
  10. package/dist/src/options.d.ts +3 -9
  11. package/dist/src/options.d.ts.map +1 -1
  12. package/dist/src/proto/livekit_models_pb.d.ts +47 -0
  13. package/dist/src/proto/livekit_models_pb.d.ts.map +1 -1
  14. package/dist/src/room/RTCEngine.d.ts +1 -0
  15. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  16. package/dist/src/room/Room.d.ts +12 -15
  17. package/dist/src/room/Room.d.ts.map +1 -1
  18. package/dist/src/room/defaults.d.ts.map +1 -1
  19. package/dist/src/room/events.d.ts +0 -4
  20. package/dist/src/room/events.d.ts.map +1 -1
  21. package/dist/src/room/participant/LocalParticipant.d.ts +8 -25
  22. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  23. package/dist/src/room/participant/Participant.d.ts +6 -10
  24. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  25. package/dist/src/room/participant/RemoteParticipant.d.ts +9 -6
  26. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  27. package/dist/src/room/timers.d.ts +4 -5
  28. package/dist/src/room/timers.d.ts.map +1 -1
  29. package/dist/src/room/track/LocalVideoTrack.d.ts +3 -3
  30. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  31. package/dist/src/room/track/RemoteTrackPublication.d.ts +2 -2
  32. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  33. package/dist/src/room/track/Track.d.ts +5 -0
  34. package/dist/src/room/track/Track.d.ts.map +1 -1
  35. package/dist/src/room/track/options.d.ts +0 -5
  36. package/dist/src/room/track/options.d.ts.map +1 -1
  37. package/dist/src/room/types.d.ts +11 -3
  38. package/dist/src/room/types.d.ts.map +1 -1
  39. package/dist/src/version.d.ts +1 -1
  40. package/dist/ts4.2/src/api/SignalClient.d.ts +0 -2
  41. package/dist/ts4.2/src/index.d.ts +3 -3
  42. package/dist/ts4.2/src/options.d.ts +3 -9
  43. package/dist/ts4.2/src/proto/livekit_models_pb.d.ts +47 -0
  44. package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -0
  45. package/dist/ts4.2/src/room/Room.d.ts +12 -15
  46. package/dist/ts4.2/src/room/events.d.ts +0 -4
  47. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +8 -25
  48. package/dist/ts4.2/src/room/participant/Participant.d.ts +6 -10
  49. package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +9 -6
  50. package/dist/ts4.2/src/room/timers.d.ts +4 -5
  51. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +3 -3
  52. package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +2 -2
  53. package/dist/ts4.2/src/room/track/Track.d.ts +5 -0
  54. package/dist/ts4.2/src/room/track/options.d.ts +0 -5
  55. package/dist/ts4.2/src/room/types.d.ts +11 -3
  56. package/dist/ts4.2/src/version.d.ts +1 -1
  57. package/package.json +8 -7
  58. package/src/api/SignalClient.ts +2 -6
  59. package/src/e2ee/E2eeManager.ts +2 -2
  60. package/src/index.ts +2 -4
  61. package/src/options.ts +3 -10
  62. package/src/proto/livekit_models_pb.ts +66 -0
  63. package/src/room/RTCEngine.ts +6 -1
  64. package/src/room/Room.ts +145 -114
  65. package/src/room/defaults.ts +1 -5
  66. package/src/room/events.ts +0 -5
  67. package/src/room/participant/LocalParticipant.ts +36 -77
  68. package/src/room/participant/Participant.ts +23 -24
  69. package/src/room/participant/RemoteParticipant.ts +27 -24
  70. package/src/room/track/LocalVideoTrack.test.ts +1 -1
  71. package/src/room/track/LocalVideoTrack.ts +11 -7
  72. package/src/room/track/RemoteTrackPublication.ts +2 -7
  73. package/src/room/track/Track.ts +10 -1
  74. package/src/room/track/options.ts +0 -6
  75. package/src/room/types.ts +11 -4
  76. package/src/version.ts +1 -1
@@ -53,7 +53,6 @@ import {
53
53
  import Participant from './Participant';
54
54
  import type { ParticipantTrackPermission } from './ParticipantTrackPermission';
55
55
  import { trackPermissionToProto } from './ParticipantTrackPermission';
56
- import RemoteParticipant from './RemoteParticipant';
57
56
  import {
58
57
  computeTrackBackupEncodings,
59
58
  computeVideoEncodings,
@@ -61,12 +60,12 @@ import {
61
60
  } from './publishUtils';
62
61
 
63
62
  export default class LocalParticipant extends Participant {
64
- audioTracks: Map<string, LocalTrackPublication>;
63
+ audioTrackPublications: Map<string, LocalTrackPublication>;
65
64
 
66
- videoTracks: Map<string, LocalTrackPublication>;
65
+ videoTrackPublications: Map<string, LocalTrackPublication>;
67
66
 
68
67
  /** map of track sid => all published tracks */
69
- tracks: Map<string, LocalTrackPublication>;
68
+ trackPublications: Map<string, LocalTrackPublication>;
70
69
 
71
70
  /** @internal */
72
71
  engine: RTCEngine;
@@ -99,9 +98,9 @@ export default class LocalParticipant extends Participant {
99
98
  loggerName: options.loggerName,
100
99
  loggerContextCb: () => this.engine.logContext,
101
100
  });
102
- this.audioTracks = new Map();
103
- this.videoTracks = new Map();
104
- this.tracks = new Map();
101
+ this.audioTrackPublications = new Map();
102
+ this.videoTrackPublications = new Map();
103
+ this.trackPublications = new Map();
105
104
  this.engine = engine;
106
105
  this.roomOptions = options;
107
106
  this.setupEngine(engine);
@@ -120,15 +119,15 @@ export default class LocalParticipant extends Participant {
120
119
  return this.encryptionType !== Encryption_Type.NONE;
121
120
  }
122
121
 
123
- getTrack(source: Track.Source): LocalTrackPublication | undefined {
124
- const track = super.getTrack(source);
122
+ getTrackPublication(source: Track.Source): LocalTrackPublication | undefined {
123
+ const track = super.getTrackPublication(source);
125
124
  if (track) {
126
125
  return track as LocalTrackPublication;
127
126
  }
128
127
  }
129
128
 
130
- getTrackByName(name: string): LocalTrackPublication | undefined {
131
- const track = super.getTrackByName(name);
129
+ getTrackPublicationByName(name: string): LocalTrackPublication | undefined {
130
+ const track = super.getTrackPublicationByName(name);
132
131
  if (track) {
133
132
  return track as LocalTrackPublication;
134
133
  }
@@ -140,7 +139,7 @@ export default class LocalParticipant extends Participant {
140
139
  setupEngine(engine: RTCEngine) {
141
140
  this.engine = engine;
142
141
  this.engine.on(EngineEvent.RemoteMute, (trackSid: string, muted: boolean) => {
143
- const pub = this.tracks.get(trackSid);
142
+ const pub = this.trackPublications.get(trackSid);
144
143
  if (!pub || !pub.track) {
145
144
  return;
146
145
  }
@@ -290,7 +289,7 @@ export default class LocalParticipant extends Participant {
290
289
  publishOptions?: TrackPublishOptions,
291
290
  ) {
292
291
  this.log.debug('setTrackEnabled', { ...this.logContext, source, enabled });
293
- let track = this.getTrack(source);
292
+ let track = this.getTrackPublication(source);
294
293
  if (enabled) {
295
294
  if (track) {
296
295
  await track.unmute();
@@ -351,7 +350,7 @@ export default class LocalParticipant extends Participant {
351
350
  // screenshare cannot be muted, unpublish instead
352
351
  if (source === Track.Source.ScreenShare) {
353
352
  track = await this.unpublishTrack(track.track);
354
- const screenAudioTrack = this.getTrack(Track.Source.ScreenShareAudio);
353
+ const screenAudioTrack = this.getTrackPublication(Track.Source.ScreenShareAudio);
355
354
  if (screenAudioTrack && screenAudioTrack.track) {
356
355
  this.unpublishTrack(screenAudioTrack.track);
357
356
  }
@@ -573,7 +572,7 @@ export default class LocalParticipant extends Participant {
573
572
 
574
573
  // is it already published? if so skip
575
574
  let existingPublication: LocalTrackPublication | undefined;
576
- this.tracks.forEach((publication) => {
575
+ this.trackPublications.forEach((publication) => {
577
576
  if (!publication.track) {
578
577
  return;
579
578
  }
@@ -651,7 +650,7 @@ export default class LocalParticipant extends Participant {
651
650
  }
652
651
 
653
652
  private async publish(track: LocalTrack, opts: TrackPublishOptions, isStereo: boolean) {
654
- const existingTrackOfSource = Array.from(this.tracks.values()).find(
653
+ const existingTrackOfSource = Array.from(this.trackPublications.values()).find(
655
654
  (publishedTrack) => track instanceof LocalTrack && publishedTrack.source === track.source,
656
655
  );
657
656
  if (existingTrackOfSource && track.source !== Track.Source.Unknown) {
@@ -788,7 +787,7 @@ export default class LocalParticipant extends Participant {
788
787
  } else if (track.kind === Track.Kind.Audio) {
789
788
  encodings = [
790
789
  {
791
- maxBitrate: opts.audioPreset?.maxBitrate ?? opts.audioBitrate,
790
+ maxBitrate: opts.audioPreset?.maxBitrate,
792
791
  priority: opts.audioPreset?.priority ?? 'high',
793
792
  networkPriority: opts.audioPreset?.priority ?? 'high',
794
793
  },
@@ -914,7 +913,7 @@ export default class LocalParticipant extends Participant {
914
913
 
915
914
  // is it not published? if so skip
916
915
  let existingPublication: LocalTrackPublication | undefined;
917
- this.tracks.forEach((publication) => {
916
+ this.trackPublications.forEach((publication) => {
918
917
  if (!publication.track) {
919
918
  return;
920
919
  }
@@ -947,6 +946,9 @@ export default class LocalParticipant extends Participant {
947
946
  return;
948
947
  }
949
948
  const simulcastTrack = track.addSimulcastTrack(videoCodec, encodings);
949
+ if (!simulcastTrack) {
950
+ return;
951
+ }
950
952
  const req = new AddTrackRequest({
951
953
  cid: simulcastTrack.mediaStreamTrack.id,
952
954
  type: Track.kindToProto(track.kind),
@@ -1061,13 +1063,13 @@ export default class LocalParticipant extends Participant {
1061
1063
  }
1062
1064
 
1063
1065
  // remove from our maps
1064
- this.tracks.delete(publication.trackSid);
1066
+ this.trackPublications.delete(publication.trackSid);
1065
1067
  switch (publication.kind) {
1066
1068
  case Track.Kind.Audio:
1067
- this.audioTracks.delete(publication.trackSid);
1069
+ this.audioTrackPublications.delete(publication.trackSid);
1068
1070
  break;
1069
1071
  case Track.Kind.Video:
1070
- this.videoTracks.delete(publication.trackSid);
1072
+ this.videoTrackPublications.delete(publication.trackSid);
1071
1073
  break;
1072
1074
  default:
1073
1075
  break;
@@ -1093,7 +1095,7 @@ export default class LocalParticipant extends Participant {
1093
1095
 
1094
1096
  async republishAllTracks(options?: TrackPublishOptions, restartTracks: boolean = true) {
1095
1097
  const localPubs: LocalTrackPublication[] = [];
1096
- this.tracks.forEach((pub) => {
1098
+ this.trackPublications.forEach((pub) => {
1097
1099
  if (pub.track) {
1098
1100
  if (options) {
1099
1101
  pub.options = { ...pub.options, ...options };
@@ -1132,64 +1134,21 @@ export default class LocalParticipant extends Participant {
1132
1134
  * participant in the room if the destination field in publishOptions is empty
1133
1135
  *
1134
1136
  * @param data Uint8Array of the payload. To send string data, use TextEncoder.encode
1135
- * @param kind whether to send this as reliable or lossy.
1136
- * For data that you need delivery guarantee (such as chat messages), use Reliable.
1137
- * For data that should arrive as quickly as possible, but you are ok with dropped
1138
- * packets, use Lossy.
1139
- * @param publishOptions optionally specify a `topic` and `destination`
1137
+ * @param options optionally specify a `reliable`, `topic` and `destination`
1140
1138
  */
1141
- async publishData(
1142
- data: Uint8Array,
1143
- kind: DataPacket_Kind,
1144
- publishOptions?: DataPublishOptions,
1145
- ): Promise<void>;
1146
- /**
1147
- * Publish a new data payload to the room. Data will be forwarded to each
1148
- * participant in the room if the destination argument is empty
1149
- *
1150
- * @param data Uint8Array of the payload. To send string data, use TextEncoder.encode
1151
- * @param kind whether to send this as reliable or lossy.
1152
- * For data that you need delivery guarantee (such as chat messages), use Reliable.
1153
- * For data that should arrive as quickly as possible, but you are ok with dropped
1154
- * packets, use Lossy.
1155
- * @param destination the participants who will receive the message
1156
- */
1157
- async publishData(
1158
- data: Uint8Array,
1159
- kind: DataPacket_Kind,
1160
- destination?: RemoteParticipant[] | string[],
1161
- ): Promise<void>;
1162
-
1163
- async publishData(
1164
- data: Uint8Array,
1165
- kind: DataPacket_Kind,
1166
- publishOptions: DataPublishOptions | RemoteParticipant[] | string[] = {},
1167
- ) {
1168
- const destination = Array.isArray(publishOptions)
1169
- ? publishOptions
1170
- : publishOptions?.destination;
1171
- const destinationSids: string[] = [];
1172
-
1173
- const topic = !Array.isArray(publishOptions) ? publishOptions.topic : undefined;
1174
-
1175
- if (destination !== undefined) {
1176
- destination.forEach((val: any) => {
1177
- if (val instanceof RemoteParticipant) {
1178
- destinationSids.push(val.sid);
1179
- } else {
1180
- destinationSids.push(val);
1181
- }
1182
- });
1183
- }
1139
+ async publishData(data: Uint8Array, options: DataPublishOptions = {}): Promise<void> {
1140
+ const kind = options.reliable ? DataPacket_Kind.RELIABLE : DataPacket_Kind.LOSSY;
1141
+ const destinationIdentities = options.destinationIdentities;
1142
+ const topic = options.topic;
1184
1143
 
1185
1144
  const packet = new DataPacket({
1186
- kind,
1145
+ kind: kind,
1187
1146
  value: {
1188
1147
  case: 'user',
1189
1148
  value: new UserPacket({
1190
- participantSid: this.sid,
1149
+ participantIdentity: this.identity,
1191
1150
  payload: data,
1192
- destinationSids: destinationSids,
1151
+ destinationIdentities,
1193
1152
  topic,
1194
1153
  }),
1195
1154
  },
@@ -1241,7 +1200,7 @@ export default class LocalParticipant extends Participant {
1241
1200
  // if server's track mute status doesn't match actual, we'll have to update
1242
1201
  // the server's copy
1243
1202
  info.tracks.forEach((ti) => {
1244
- const pub = this.tracks.get(ti.sid);
1203
+ const pub = this.trackPublications.get(ti.sid);
1245
1204
 
1246
1205
  if (pub) {
1247
1206
  const mutedOnServer = pub.isMuted || (pub.track?.isUpstreamPaused ?? false);
@@ -1313,7 +1272,7 @@ export default class LocalParticipant extends Participant {
1313
1272
  if (!this.roomOptions?.dynacast) {
1314
1273
  return;
1315
1274
  }
1316
- const pub = this.videoTracks.get(update.trackSid);
1275
+ const pub = this.videoTrackPublications.get(update.trackSid);
1317
1276
  if (!pub) {
1318
1277
  this.log.warn('received subscribed quality update for unknown track', {
1319
1278
  ...this.logContext,
@@ -1341,7 +1300,7 @@ export default class LocalParticipant extends Participant {
1341
1300
  };
1342
1301
 
1343
1302
  private handleLocalTrackUnpublished = (unpublished: TrackUnpublishedResponse) => {
1344
- const track = this.tracks.get(unpublished.trackSid);
1303
+ const track = this.trackPublications.get(unpublished.trackSid);
1345
1304
  if (!track) {
1346
1305
  this.log.warn('received unpublished event for unknown track', {
1347
1306
  ...this.logContext,
@@ -1415,7 +1374,7 @@ export default class LocalParticipant extends Participant {
1415
1374
  track: LocalTrack | MediaStreamTrack,
1416
1375
  ): LocalTrackPublication | undefined {
1417
1376
  let publication: LocalTrackPublication | undefined;
1418
- this.tracks.forEach((pub) => {
1377
+ this.trackPublications.forEach((pub) => {
1419
1378
  const localTrack = pub.track;
1420
1379
  if (!localTrack) {
1421
1380
  return;
@@ -48,12 +48,12 @@ function qualityFromProto(q: ProtoQuality): ConnectionQuality {
48
48
  export default class Participant extends (EventEmitter as new () => TypedEmitter<ParticipantEventCallbacks>) {
49
49
  protected participantInfo?: ParticipantInfo;
50
50
 
51
- audioTracks: Map<string, TrackPublication>;
51
+ audioTrackPublications: Map<string, TrackPublication>;
52
52
 
53
- videoTracks: Map<string, TrackPublication>;
53
+ videoTrackPublications: Map<string, TrackPublication>;
54
54
 
55
55
  /** map of track sid => all published tracks */
56
- tracks: Map<string, TrackPublication>;
56
+ trackPublications: Map<string, TrackPublication>;
57
57
 
58
58
  /** audio level between 0-1.0, 1 being loudest, 0 being softest */
59
59
  audioLevel: number = 0;
@@ -94,7 +94,10 @@ export default class Participant extends (EventEmitter as new () => TypedEmitter
94
94
  }
95
95
 
96
96
  get isEncrypted() {
97
- return this.tracks.size > 0 && Array.from(this.tracks.values()).every((tr) => tr.isEncrypted);
97
+ return (
98
+ this.trackPublications.size > 0 &&
99
+ Array.from(this.trackPublications.values()).every((tr) => tr.isEncrypted)
100
+ );
98
101
  }
99
102
 
100
103
  get isAgent() {
@@ -119,23 +122,21 @@ export default class Participant extends (EventEmitter as new () => TypedEmitter
119
122
  this.identity = identity;
120
123
  this.name = name;
121
124
  this.metadata = metadata;
122
- this.audioTracks = new Map();
123
- this.videoTracks = new Map();
124
- this.tracks = new Map();
125
+ this.audioTrackPublications = new Map();
126
+ this.videoTrackPublications = new Map();
127
+ this.trackPublications = new Map();
125
128
  }
126
129
 
127
- getTracks(): TrackPublication[] {
128
- return Array.from(this.tracks.values());
130
+ getTrackPublications(): TrackPublication[] {
131
+ return Array.from(this.trackPublications.values());
129
132
  }
130
133
 
131
134
  /**
132
135
  * Finds the first track that matches the source filter, for example, getting
133
136
  * the user's camera track with getTrackBySource(Track.Source.Camera).
134
- * @param source
135
- * @returns
136
137
  */
137
- getTrack(source: Track.Source): TrackPublication | undefined {
138
- for (const [, pub] of this.tracks) {
138
+ getTrackPublication(source: Track.Source): TrackPublication | undefined {
139
+ for (const [, pub] of this.trackPublications) {
139
140
  if (pub.source === source) {
140
141
  return pub;
141
142
  }
@@ -144,11 +145,9 @@ export default class Participant extends (EventEmitter as new () => TypedEmitter
144
145
 
145
146
  /**
146
147
  * Finds the first track that matches the track's name.
147
- * @param name
148
- * @returns
149
148
  */
150
- getTrackByName(name: string): TrackPublication | undefined {
151
- for (const [, pub] of this.tracks) {
149
+ getTrackPublicationByName(name: string): TrackPublication | undefined {
150
+ for (const [, pub] of this.trackPublications) {
152
151
  if (pub.trackName === name) {
153
152
  return pub;
154
153
  }
@@ -160,17 +159,17 @@ export default class Participant extends (EventEmitter as new () => TypedEmitter
160
159
  }
161
160
 
162
161
  get isCameraEnabled(): boolean {
163
- const track = this.getTrack(Track.Source.Camera);
162
+ const track = this.getTrackPublication(Track.Source.Camera);
164
163
  return !(track?.isMuted ?? true);
165
164
  }
166
165
 
167
166
  get isMicrophoneEnabled(): boolean {
168
- const track = this.getTrack(Track.Source.Microphone);
167
+ const track = this.getTrackPublication(Track.Source.Microphone);
169
168
  return !(track?.isMuted ?? true);
170
169
  }
171
170
 
172
171
  get isScreenShareEnabled(): boolean {
173
- const track = this.getTrack(Track.Source.ScreenShare);
172
+ const track = this.getTrackPublication(Track.Source.ScreenShare);
174
173
  return !!track;
175
174
  }
176
175
 
@@ -283,7 +282,7 @@ export default class Participant extends (EventEmitter as new () => TypedEmitter
283
282
  */
284
283
  setAudioContext(ctx: AudioContext | undefined) {
285
284
  this.audioContext = ctx;
286
- this.audioTracks.forEach(
285
+ this.audioTrackPublications.forEach(
287
286
  (track) =>
288
287
  (track.track instanceof RemoteAudioTrack || track.track instanceof LocalAudioTrack) &&
289
288
  track.track.setAudioContext(ctx),
@@ -305,13 +304,13 @@ export default class Participant extends (EventEmitter as new () => TypedEmitter
305
304
  pub.track.sid = publication.trackSid;
306
305
  }
307
306
 
308
- this.tracks.set(publication.trackSid, publication);
307
+ this.trackPublications.set(publication.trackSid, publication);
309
308
  switch (publication.kind) {
310
309
  case Track.Kind.Audio:
311
- this.audioTracks.set(publication.trackSid, publication);
310
+ this.audioTrackPublications.set(publication.trackSid, publication);
312
311
  break;
313
312
  case Track.Kind.Video:
314
- this.videoTracks.set(publication.trackSid, publication);
313
+ this.videoTrackPublications.set(publication.trackSid, publication);
315
314
  break;
316
315
  default:
317
316
  break;
@@ -16,11 +16,11 @@ import Participant from './Participant';
16
16
  import type { ParticipantEventCallbacks } from './Participant';
17
17
 
18
18
  export default class RemoteParticipant extends Participant {
19
- audioTracks: Map<string, RemoteTrackPublication>;
19
+ audioTrackPublications: Map<string, RemoteTrackPublication>;
20
20
 
21
- videoTracks: Map<string, RemoteTrackPublication>;
21
+ videoTrackPublications: Map<string, RemoteTrackPublication>;
22
22
 
23
- tracks: Map<string, RemoteTrackPublication>;
23
+ trackPublications: Map<string, RemoteTrackPublication>;
24
24
 
25
25
  signalClient: SignalClient;
26
26
 
@@ -44,9 +44,9 @@ export default class RemoteParticipant extends Participant {
44
44
  ) {
45
45
  super(sid, identity || '', name, metadata, loggerOptions);
46
46
  this.signalClient = signalClient;
47
- this.tracks = new Map();
48
- this.audioTracks = new Map();
49
- this.videoTracks = new Map();
47
+ this.trackPublications = new Map();
48
+ this.audioTrackPublications = new Map();
49
+ this.videoTrackPublications = new Map();
50
50
  this.volumeMap = new Map();
51
51
  }
52
52
 
@@ -90,15 +90,15 @@ export default class RemoteParticipant extends Participant {
90
90
  });
91
91
  }
92
92
 
93
- getTrack(source: Track.Source): RemoteTrackPublication | undefined {
94
- const track = super.getTrack(source);
93
+ getTrackPublication(source: Track.Source): RemoteTrackPublication | undefined {
94
+ const track = super.getTrackPublication(source);
95
95
  if (track) {
96
96
  return track as RemoteTrackPublication;
97
97
  }
98
98
  }
99
99
 
100
- getTrackByName(name: string): RemoteTrackPublication | undefined {
101
- const track = super.getTrackByName(name);
100
+ getTrackPublicationByName(name: string): RemoteTrackPublication | undefined {
101
+ const track = super.getTrackPublicationByName(name);
102
102
  if (track) {
103
103
  return track as RemoteTrackPublication;
104
104
  }
@@ -115,7 +115,7 @@ export default class RemoteParticipant extends Participant {
115
115
  source: Track.Source.Microphone | Track.Source.ScreenShareAudio = Track.Source.Microphone,
116
116
  ) {
117
117
  this.volumeMap.set(source, volume);
118
- const audioPublication = this.getTrack(source);
118
+ const audioPublication = this.getTrackPublication(source);
119
119
  if (audioPublication && audioPublication.track) {
120
120
  (audioPublication.track as RemoteAudioTrack).setVolume(volume);
121
121
  }
@@ -127,7 +127,7 @@ export default class RemoteParticipant extends Participant {
127
127
  getVolume(
128
128
  source: Track.Source.Microphone | Track.Source.ScreenShareAudio = Track.Source.Microphone,
129
129
  ) {
130
- const audioPublication = this.getTrack(source);
130
+ const audioPublication = this.getTrackPublication(source);
131
131
  if (audioPublication && audioPublication.track) {
132
132
  return (audioPublication.track as RemoteAudioTrack).getVolume();
133
133
  }
@@ -145,14 +145,14 @@ export default class RemoteParticipant extends Participant {
145
145
  ) {
146
146
  // find the track publication
147
147
  // it's possible for the media track to arrive before participant info
148
- let publication = this.getTrackPublication(sid);
148
+ let publication = this.getTrackPublicationBySid(sid);
149
149
 
150
150
  // it's also possible that the browser didn't honor our original track id
151
151
  // FireFox would use its own local uuid instead of server track id
152
152
  if (!publication) {
153
153
  if (!sid.startsWith('TR')) {
154
154
  // find the first track that matches type
155
- this.tracks.forEach((p) => {
155
+ this.trackPublications.forEach((p) => {
156
156
  if (!publication && mediaTrack.kind === p.kind.toString()) {
157
157
  publication = p;
158
158
  }
@@ -224,8 +224,11 @@ export default class RemoteParticipant extends Participant {
224
224
  return !!this.participantInfo;
225
225
  }
226
226
 
227
- getTrackPublication(sid: Track.SID): RemoteTrackPublication | undefined {
228
- return this.tracks.get(sid);
227
+ /**
228
+ * @internal
229
+ */
230
+ getTrackPublicationBySid(sid: Track.SID): RemoteTrackPublication | undefined {
231
+ return this.trackPublications.get(sid);
229
232
  }
230
233
 
231
234
  /** @internal */
@@ -243,7 +246,7 @@ export default class RemoteParticipant extends Participant {
243
246
  const newTracks = new Map<string, RemoteTrackPublication>();
244
247
 
245
248
  info.tracks.forEach((ti) => {
246
- let publication = this.getTrackPublication(ti.sid);
249
+ let publication = this.getTrackPublicationBySid(ti.sid);
247
250
  if (!publication) {
248
251
  // new publication
249
252
  const kind = Track.kindFromProto(ti.type);
@@ -258,7 +261,7 @@ export default class RemoteParticipant extends Participant {
258
261
  );
259
262
  publication.updateInfo(ti);
260
263
  newTracks.set(ti.sid, publication);
261
- const existingTrackOfSource = Array.from(this.tracks.values()).find(
264
+ const existingTrackOfSource = Array.from(this.trackPublications.values()).find(
262
265
  (publishedTrack) => publishedTrack.source === publication?.source,
263
266
  );
264
267
  if (existingTrackOfSource && publication.source !== Track.Source.Unknown) {
@@ -279,7 +282,7 @@ export default class RemoteParticipant extends Participant {
279
282
  });
280
283
 
281
284
  // detect removed tracks
282
- this.tracks.forEach((publication) => {
285
+ this.trackPublications.forEach((publication) => {
283
286
  if (!validTracks.has(publication.trackSid)) {
284
287
  this.log.trace('detected removed track on remote participant, unpublishing', {
285
288
  ...this.logContext,
@@ -298,7 +301,7 @@ export default class RemoteParticipant extends Participant {
298
301
 
299
302
  /** @internal */
300
303
  unpublishTrack(sid: Track.SID, sendUnpublish?: boolean) {
301
- const publication = <RemoteTrackPublication>this.tracks.get(sid);
304
+ const publication = <RemoteTrackPublication>this.trackPublications.get(sid);
302
305
  if (!publication) {
303
306
  return;
304
307
  }
@@ -311,15 +314,15 @@ export default class RemoteParticipant extends Participant {
311
314
  }
312
315
 
313
316
  // remove track from maps only after unsubscribed has been fired
314
- this.tracks.delete(sid);
317
+ this.trackPublications.delete(sid);
315
318
 
316
319
  // remove from the right type map
317
320
  switch (publication.kind) {
318
321
  case Track.Kind.Audio:
319
- this.audioTracks.delete(sid);
322
+ this.audioTrackPublications.delete(sid);
320
323
  break;
321
324
  case Track.Kind.Video:
322
- this.videoTracks.delete(sid);
325
+ this.videoTrackPublications.delete(sid);
323
326
  break;
324
327
  default:
325
328
  break;
@@ -336,7 +339,7 @@ export default class RemoteParticipant extends Participant {
336
339
  async setAudioOutput(output: AudioOutputOptions) {
337
340
  this.audioOutput = output;
338
341
  const promises: Promise<void>[] = [];
339
- this.audioTracks.forEach((pub) => {
342
+ this.audioTrackPublications.forEach((pub) => {
340
343
  if (pub.track instanceof RemoteAudioTrack) {
341
344
  promises.push(pub.track.setSinkId(output.deviceId ?? 'default'));
342
345
  }
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { VideoQuality } from '../../proto/livekit_models_pb';
3
2
  import { videoLayersFromEncodings } from './LocalVideoTrack';
3
+ import { VideoQuality } from './Track';
4
4
 
5
5
  describe('videoLayersFromEncodings', () => {
6
6
  it('returns single layer for no encoding', () => {
@@ -1,6 +1,6 @@
1
1
  import type { SignalClient } from '../../api/SignalClient';
2
2
  import type { StructuredLogger } from '../../logger';
3
- import { VideoLayer, VideoQuality } from '../../proto/livekit_models_pb';
3
+ import { VideoQuality as ProtoVideoQuality, VideoLayer } from '../../proto/livekit_models_pb';
4
4
  import { SubscribedCodec, SubscribedQuality } from '../../proto/livekit_rtc_pb';
5
5
  import { ScalabilityMode } from '../participant/publishUtils';
6
6
  import type { VideoSenderStats } from '../stats';
@@ -8,7 +8,7 @@ import { computeBitrate, monitorFrequency } from '../stats';
8
8
  import type { LoggerOptions } from '../types';
9
9
  import { Mutex, isFireFox, isMobile, isWeb, unwrapConstraint } from '../utils';
10
10
  import LocalTrack from './LocalTrack';
11
- import { Track } from './Track';
11
+ import { Track, VideoQuality } from './Track';
12
12
  import type { VideoCaptureOptions, VideoCodec } from './options';
13
13
  import type { TrackProcessor } from './processor/types';
14
14
  import { constraintsForOptions } from './utils';
@@ -254,9 +254,13 @@ export default class LocalVideoTrack extends LocalTrack {
254
254
  }
255
255
  }
256
256
 
257
- addSimulcastTrack(codec: VideoCodec, encodings?: RTCRtpEncodingParameters[]): SimulcastTrackInfo {
257
+ addSimulcastTrack(
258
+ codec: VideoCodec,
259
+ encodings?: RTCRtpEncodingParameters[],
260
+ ): SimulcastTrackInfo | undefined {
258
261
  if (this.simulcastCodecs.has(codec)) {
259
- throw new Error(`${codec} already added`);
262
+ this.log.error(`${codec} already added, skipping adding simulcast codec`, this.logContext);
263
+ return;
260
264
  }
261
265
  const simulcastCodecInfo: SimulcastTrackInfo = {
262
266
  codec,
@@ -427,14 +431,14 @@ async function setPublishingLayersForSender(
427
431
  const encoding = encodings[0];
428
432
  /* @ts-ignore */
429
433
  // const mode = new ScalabilityMode(encoding.scalabilityMode);
430
- let maxQuality = VideoQuality.OFF;
434
+ let maxQuality = ProtoVideoQuality.OFF;
431
435
  qualities.forEach((q) => {
432
- if (q.enabled && (maxQuality === VideoQuality.OFF || q.quality > maxQuality)) {
436
+ if (q.enabled && (maxQuality === ProtoVideoQuality.OFF || q.quality > maxQuality)) {
433
437
  maxQuality = q.quality;
434
438
  }
435
439
  });
436
440
 
437
- if (maxQuality === VideoQuality.OFF) {
441
+ if (maxQuality === ProtoVideoQuality.OFF) {
438
442
  if (encoding.active) {
439
443
  encoding.active = false;
440
444
  hasChanged = true;
@@ -1,15 +1,10 @@
1
- import {
2
- ParticipantTracks,
3
- SubscriptionError,
4
- TrackInfo,
5
- VideoQuality,
6
- } from '../../proto/livekit_models_pb';
1
+ import { ParticipantTracks, SubscriptionError, TrackInfo } from '../../proto/livekit_models_pb';
7
2
  import { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc_pb';
8
3
  import { TrackEvent } from '../events';
9
4
  import type { LoggerOptions } from '../types';
10
5
  import type RemoteTrack from './RemoteTrack';
11
6
  import RemoteVideoTrack from './RemoteVideoTrack';
12
- import { Track } from './Track';
7
+ import { Track, VideoQuality } from './Track';
13
8
  import { TrackPublication } from './TrackPublication';
14
9
 
15
10
  export default class RemoteTrackPublication extends TrackPublication {
@@ -2,7 +2,11 @@ import { EventEmitter } from 'events';
2
2
  import type TypedEventEmitter from 'typed-emitter';
3
3
  import type { SignalClient } from '../../api/SignalClient';
4
4
  import log, { LoggerNames, StructuredLogger, getLogger } from '../../logger';
5
- import { TrackSource, TrackType } from '../../proto/livekit_models_pb';
5
+ import {
6
+ VideoQuality as ProtoQuality,
7
+ TrackSource,
8
+ TrackType,
9
+ } from '../../proto/livekit_models_pb';
6
10
  import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc_pb';
7
11
  import { TrackEvent } from '../events';
8
12
  import type { LoggerOptions } from '../types';
@@ -15,6 +19,11 @@ const BACKGROUND_REACTION_DELAY = 5000;
15
19
  // Safari tracks which audio elements have been "blessed" by the user.
16
20
  const recycledElements: Array<HTMLAudioElement> = [];
17
21
 
22
+ export enum VideoQuality {
23
+ LOW = ProtoQuality.LOW,
24
+ MEDIUM = ProtoQuality.MEDIUM,
25
+ HIGH = ProtoQuality.HIGH,
26
+ }
18
27
  export abstract class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEventCallbacks>) {
19
28
  kind: Track.Kind;
20
29
 
@@ -30,12 +30,6 @@ export interface TrackPublishDefaults {
30
30
  */
31
31
  videoCodec?: VideoCodec;
32
32
 
33
- /**
34
- * max audio bitrate, defaults to [[AudioPresets.music]]
35
- * @deprecated use `audioPreset` instead
36
- */
37
- audioBitrate?: number;
38
-
39
33
  /**
40
34
  * which audio preset should be used for publishing (audio) tracks
41
35
  * defaults to [[AudioPresets.music]]