livekit-client 1.12.1 → 1.12.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. package/README.md +7 -3
  2. package/dist/livekit-client.e2ee.worker.js +1 -1
  3. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  4. package/dist/livekit-client.e2ee.worker.mjs +389 -301
  5. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  6. package/dist/livekit-client.esm.mjs +11279 -13498
  7. package/dist/livekit-client.esm.mjs.map +1 -1
  8. package/dist/livekit-client.umd.js +1 -1
  9. package/dist/livekit-client.umd.js.map +1 -1
  10. package/dist/src/api/SignalClient.d.ts +2 -2
  11. package/dist/src/api/SignalClient.d.ts.map +1 -1
  12. package/dist/src/connectionHelper/ConnectionCheck.d.ts +3 -2
  13. package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
  14. package/dist/src/connectionHelper/checks/Checker.d.ts +3 -2
  15. package/dist/src/connectionHelper/checks/Checker.d.ts.map +1 -1
  16. package/dist/src/connectionHelper/checks/webrtc.d.ts.map +1 -1
  17. package/dist/src/connectionHelper/checks/websocket.d.ts.map +1 -1
  18. package/dist/src/e2ee/E2eeManager.d.ts +4 -2
  19. package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
  20. package/dist/src/e2ee/KeyProvider.d.ts +4 -2
  21. package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
  22. package/dist/src/e2ee/constants.d.ts +1 -0
  23. package/dist/src/e2ee/constants.d.ts.map +1 -1
  24. package/dist/src/e2ee/types.d.ts +1 -0
  25. package/dist/src/e2ee/types.d.ts.map +1 -1
  26. package/dist/src/e2ee/worker/FrameCryptor.d.ts +4 -2
  27. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  28. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +14 -3
  29. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
  30. package/dist/src/index.d.ts +1 -1
  31. package/dist/src/index.d.ts.map +1 -1
  32. package/dist/src/proto/livekit_models_pb.d.ts +1264 -0
  33. package/dist/src/proto/livekit_models_pb.d.ts.map +1 -0
  34. package/dist/src/proto/livekit_rtc_pb.d.ts +1373 -0
  35. package/dist/src/proto/livekit_rtc_pb.d.ts.map +1 -0
  36. package/dist/src/room/PCTransport.d.ts +2 -1
  37. package/dist/src/room/PCTransport.d.ts.map +1 -1
  38. package/dist/src/room/RTCEngine.d.ts +9 -5
  39. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  40. package/dist/src/room/RegionUrlProvider.d.ts +4 -1
  41. package/dist/src/room/RegionUrlProvider.d.ts.map +1 -1
  42. package/dist/src/room/Room.d.ts +15 -11
  43. package/dist/src/room/Room.d.ts.map +1 -1
  44. package/dist/src/room/participant/LocalParticipant.d.ts +2 -2
  45. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  46. package/dist/src/room/participant/Participant.d.ts +5 -3
  47. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  48. package/dist/src/room/participant/ParticipantTrackPermission.d.ts +1 -1
  49. package/dist/src/room/participant/ParticipantTrackPermission.d.ts.map +1 -1
  50. package/dist/src/room/participant/RemoteParticipant.d.ts +2 -3
  51. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  52. package/dist/src/room/participant/publishUtils.d.ts +1 -1
  53. package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
  54. package/dist/src/room/timers.d.ts +5 -4
  55. package/dist/src/room/timers.d.ts.map +1 -1
  56. package/dist/src/room/track/LocalTrack.d.ts +3 -0
  57. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  58. package/dist/src/room/track/LocalTrackPublication.d.ts +1 -1
  59. package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -1
  60. package/dist/src/room/track/LocalVideoTrack.d.ts +2 -2
  61. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  62. package/dist/src/room/track/RemoteTrackPublication.d.ts +1 -1
  63. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  64. package/dist/src/room/track/Track.d.ts +6 -4
  65. package/dist/src/room/track/Track.d.ts.map +1 -1
  66. package/dist/src/room/track/TrackPublication.d.ts +7 -5
  67. package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
  68. package/dist/src/room/track/create.d.ts.map +1 -1
  69. package/dist/src/room/track/options.d.ts +8 -0
  70. package/dist/src/room/track/options.d.ts.map +1 -1
  71. package/dist/src/room/track/utils.d.ts +5 -1
  72. package/dist/src/room/track/utils.d.ts.map +1 -1
  73. package/dist/src/room/utils.d.ts +3 -1
  74. package/dist/src/room/utils.d.ts.map +1 -1
  75. package/dist/src/test/mocks.d.ts +4 -3
  76. package/dist/src/test/mocks.d.ts.map +1 -1
  77. package/dist/ts4.2/src/api/SignalClient.d.ts +2 -2
  78. package/dist/ts4.2/src/connectionHelper/ConnectionCheck.d.ts +3 -2
  79. package/dist/ts4.2/src/connectionHelper/checks/Checker.d.ts +3 -2
  80. package/dist/ts4.2/src/e2ee/E2eeManager.d.ts +4 -2
  81. package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +4 -2
  82. package/dist/ts4.2/src/e2ee/constants.d.ts +1 -0
  83. package/dist/ts4.2/src/e2ee/types.d.ts +1 -0
  84. package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +4 -2
  85. package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +14 -3
  86. package/dist/ts4.2/src/index.d.ts +1 -1
  87. package/dist/ts4.2/src/proto/livekit_models_pb.d.ts +1264 -0
  88. package/dist/ts4.2/src/proto/livekit_rtc_pb.d.ts +1373 -0
  89. package/dist/ts4.2/src/room/PCTransport.d.ts +2 -1
  90. package/dist/ts4.2/src/room/RTCEngine.d.ts +9 -5
  91. package/dist/ts4.2/src/room/RegionUrlProvider.d.ts +4 -1
  92. package/dist/ts4.2/src/room/Room.d.ts +15 -11
  93. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +2 -2
  94. package/dist/ts4.2/src/room/participant/Participant.d.ts +5 -3
  95. package/dist/ts4.2/src/room/participant/ParticipantTrackPermission.d.ts +1 -1
  96. package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +2 -3
  97. package/dist/ts4.2/src/room/participant/publishUtils.d.ts +1 -1
  98. package/dist/ts4.2/src/room/timers.d.ts +5 -4
  99. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -0
  100. package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +1 -1
  101. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -2
  102. package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +1 -1
  103. package/dist/ts4.2/src/room/track/Track.d.ts +6 -4
  104. package/dist/ts4.2/src/room/track/TrackPublication.d.ts +7 -5
  105. package/dist/ts4.2/src/room/track/options.d.ts +8 -0
  106. package/dist/ts4.2/src/room/track/utils.d.ts +5 -1
  107. package/dist/ts4.2/src/room/utils.d.ts +3 -1
  108. package/dist/ts4.2/src/test/mocks.d.ts +4 -3
  109. package/package.json +10 -10
  110. package/src/api/SignalClient.ts +104 -101
  111. package/src/connectionHelper/ConnectionCheck.ts +3 -2
  112. package/src/connectionHelper/checks/Checker.ts +3 -3
  113. package/src/connectionHelper/checks/webrtc.ts +66 -2
  114. package/src/connectionHelper/checks/websocket.ts +4 -0
  115. package/src/e2ee/E2eeManager.ts +4 -3
  116. package/src/e2ee/KeyProvider.ts +3 -2
  117. package/src/e2ee/constants.ts +4 -0
  118. package/src/e2ee/types.ts +1 -0
  119. package/src/e2ee/worker/FrameCryptor.test.ts +1 -3
  120. package/src/e2ee/worker/FrameCryptor.ts +5 -5
  121. package/src/e2ee/worker/ParticipantKeyHandler.ts +37 -6
  122. package/src/e2ee/worker/e2ee.worker.ts +1 -1
  123. package/src/index.ts +1 -1
  124. package/src/proto/livekit_models_pb.ts +2096 -0
  125. package/src/proto/livekit_rtc_pb.ts +2332 -0
  126. package/src/room/PCTransport.ts +1 -1
  127. package/src/room/RTCEngine.ts +28 -22
  128. package/src/room/RegionUrlProvider.ts +11 -2
  129. package/src/room/Room.test.ts +1 -0
  130. package/src/room/Room.ts +158 -79
  131. package/src/room/participant/LocalParticipant.ts +43 -59
  132. package/src/room/participant/Participant.ts +6 -4
  133. package/src/room/participant/ParticipantTrackPermission.ts +3 -3
  134. package/src/room/participant/RemoteParticipant.ts +5 -6
  135. package/src/room/participant/publishUtils.test.ts +1 -0
  136. package/src/room/participant/publishUtils.ts +4 -2
  137. package/src/room/track/LocalTrack.ts +24 -9
  138. package/src/room/track/LocalTrackPublication.ts +1 -1
  139. package/src/room/track/LocalVideoTrack.test.ts +2 -1
  140. package/src/room/track/LocalVideoTrack.ts +28 -26
  141. package/src/room/track/RemoteTrackPublication.ts +12 -7
  142. package/src/room/track/RemoteVideoTrack.test.ts +5 -4
  143. package/src/room/track/Track.ts +9 -6
  144. package/src/room/track/TrackPublication.ts +7 -5
  145. package/src/room/track/create.ts +9 -17
  146. package/src/room/track/facingMode.test.ts +1 -0
  147. package/src/room/track/options.ts +23 -16
  148. package/src/room/track/utils.test.ts +1 -0
  149. package/src/room/track/utils.ts +44 -2
  150. package/src/room/utils.test.ts +16 -0
  151. package/src/room/utils.ts +20 -4
  152. package/src/test/mocks.ts +7 -5
  153. package/src/utils/AsyncQueue.test.ts +1 -0
  154. package/src/utils/browserParser.test.ts +33 -3
  155. package/src/utils/browserParser.ts +1 -1
  156. package/dist/src/proto/google/protobuf/timestamp.d.ts +0 -146
  157. package/dist/src/proto/google/protobuf/timestamp.d.ts.map +0 -1
  158. package/dist/src/proto/livekit_models.d.ts +0 -2399
  159. package/dist/src/proto/livekit_models.d.ts.map +0 -1
  160. package/dist/src/proto/livekit_rtc.d.ts +0 -14352
  161. package/dist/src/proto/livekit_rtc.d.ts.map +0 -1
  162. package/dist/ts4.2/src/proto/google/protobuf/timestamp.d.ts +0 -150
  163. package/dist/ts4.2/src/proto/livekit_models.d.ts +0 -2659
  164. package/dist/ts4.2/src/proto/livekit_rtc.d.ts +0 -15764
  165. package/src/proto/google/protobuf/timestamp.ts +0 -230
  166. package/src/proto/livekit_models.ts +0 -4006
  167. package/src/proto/livekit_rtc.ts +0 -4672
@@ -6,15 +6,17 @@ import {
6
6
  Encryption_Type,
7
7
  ParticipantInfo,
8
8
  ParticipantPermission,
9
- } from '../../proto/livekit_models';
9
+ UserPacket,
10
+ } from '../../proto/livekit_models_pb';
10
11
  import {
11
12
  AddTrackRequest,
12
13
  DataChannelInfo,
13
14
  SignalTarget,
15
+ SimulcastCodec,
14
16
  SubscribedQualityUpdate,
15
17
  TrackPublishedResponse,
16
18
  TrackUnpublishedResponse,
17
- } from '../../proto/livekit_rtc';
19
+ } from '../../proto/livekit_rtc_pb';
18
20
  import type RTCEngine from '../RTCEngine';
19
21
  import { DeviceUnsupportedError, TrackInvalidError, UnexpectedConnectionState } from '../errors';
20
22
  import { EngineEvent, ParticipantEvent, TrackEvent } from '../events';
@@ -32,7 +34,11 @@ import type {
32
34
  VideoCaptureOptions,
33
35
  } from '../track/options';
34
36
  import { ScreenSharePresets, VideoPresets, isBackupCodec, isCodecEqual } from '../track/options';
35
- import { constraintsForOptions, mergeDefaultOptions } from '../track/utils';
37
+ import {
38
+ constraintsForOptions,
39
+ mergeDefaultOptions,
40
+ screenCaptureToDisplayMediaStreamOptions,
41
+ } from '../track/utils';
36
42
  import type { DataPublishOptions } from '../types';
37
43
  import { Future, isFireFox, isSVCCodec, isSafari, isWeb, supportsAV1, supportsVP9 } from '../utils';
38
44
  import Participant from './Participant';
@@ -311,6 +317,9 @@ export default class LocalParticipant extends Participant {
311
317
  // revisit if we want to return an array of tracks instead for v2
312
318
  [track] = publishedTracks;
313
319
  } catch (e) {
320
+ localTracks?.forEach((tr) => {
321
+ tr.stop();
322
+ });
314
323
  if (e instanceof Error && !(e instanceof TrackInvalidError)) {
315
324
  this.emit(ParticipantEvent.MediaDevicesError, e);
316
325
  }
@@ -433,36 +442,12 @@ export default class LocalParticipant extends Participant {
433
442
  options.resolution = ScreenSharePresets.h1080fps15.resolution;
434
443
  }
435
444
 
436
- let videoConstraints: MediaTrackConstraints | boolean = true;
437
- if (options.resolution) {
438
- if (isSafari()) {
439
- videoConstraints = {
440
- width: { max: options.resolution.width },
441
- height: { max: options.resolution.height },
442
- frameRate: options.resolution.frameRate,
443
- };
444
- } else {
445
- videoConstraints = {
446
- width: { ideal: options.resolution.width },
447
- height: { ideal: options.resolution.height },
448
- frameRate: options.resolution.frameRate,
449
- };
450
- }
451
- }
452
-
453
445
  if (navigator.mediaDevices.getDisplayMedia === undefined) {
454
446
  throw new DeviceUnsupportedError('getDisplayMedia not supported');
455
447
  }
456
448
 
457
- const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia({
458
- audio: options.audio ?? false,
459
- video: videoConstraints,
460
- // @ts-expect-error support for experimental display media features
461
- controller: options.controller,
462
- selfBrowserSurface: options.selfBrowserSurface,
463
- surfaceSwitching: options.surfaceSwitching,
464
- systemAudio: options.systemAudio,
465
- });
449
+ const constraints = screenCaptureToDisplayMediaStreamOptions(options);
450
+ const stream: MediaStream = await navigator.mediaDevices.getDisplayMedia(constraints);
466
451
 
467
452
  const tracks = stream.getVideoTracks();
468
453
  if (tracks.length === 0) {
@@ -585,7 +570,7 @@ export default class LocalParticipant extends Participant {
585
570
  if (opts.source) {
586
571
  track.source = opts.source;
587
572
  }
588
- const publishPromise = this.publish(track, opts, options, isStereo);
573
+ const publishPromise = this.publish(track, opts, isStereo);
589
574
  this.pendingPublishPromises.set(track, publishPromise);
590
575
  try {
591
576
  const publication = await publishPromise;
@@ -597,12 +582,7 @@ export default class LocalParticipant extends Participant {
597
582
  }
598
583
  }
599
584
 
600
- private async publish(
601
- track: LocalTrack,
602
- opts: TrackPublishOptions,
603
- options: TrackPublishOptions | undefined,
604
- isStereo: boolean,
605
- ) {
585
+ private async publish(track: LocalTrack, opts: TrackPublishOptions, isStereo: boolean) {
606
586
  const existingTrackOfSource = Array.from(this.tracks.values()).find(
607
587
  (publishedTrack) => track instanceof LocalTrack && publishedTrack.source === track.source,
608
588
  );
@@ -646,10 +626,10 @@ export default class LocalParticipant extends Participant {
646
626
  track.on(TrackEvent.UpstreamResumed, this.onTrackUpstreamResumed);
647
627
 
648
628
  // create track publication from track
649
- const req = AddTrackRequest.fromPartial({
629
+ const req = new AddTrackRequest({
650
630
  // get local track id for use during publishing
651
631
  cid: track.mediaStreamTrack.id,
652
- name: options?.name,
632
+ name: opts.name,
653
633
  type: Track.kindToProto(track.kind),
654
634
  muted: track.isMuted,
655
635
  source: Track.sourceToProto(track.source),
@@ -698,26 +678,26 @@ export default class LocalParticipant extends Participant {
698
678
  simEncodings = computeTrackBackupEncodings(track, opts.backupCodec.codec, simOpts);
699
679
 
700
680
  req.simulcastCodecs = [
701
- {
681
+ new SimulcastCodec({
702
682
  codec: opts.videoCodec,
703
683
  cid: track.mediaStreamTrack.id,
704
684
  enableSimulcastLayers: true,
705
- },
706
- {
685
+ }),
686
+ new SimulcastCodec({
707
687
  codec: opts.backupCodec.codec,
708
688
  cid: '',
709
689
  enableSimulcastLayers: true,
710
- },
690
+ }),
711
691
  ];
712
692
  } else if (opts.videoCodec) {
713
693
  // pass codec info to sfu so it can prefer codec for the client which don't support
714
694
  // setCodecPreferences
715
695
  req.simulcastCodecs = [
716
- {
696
+ new SimulcastCodec({
717
697
  codec: opts.videoCodec,
718
698
  cid: track.mediaStreamTrack.id,
719
699
  enableSimulcastLayers: opts.simulcast ?? false,
720
- },
700
+ }),
721
701
  ];
722
702
  }
723
703
  }
@@ -879,7 +859,7 @@ export default class LocalParticipant extends Participant {
879
859
  return;
880
860
  }
881
861
  const simulcastTrack = track.addSimulcastTrack(videoCodec, encodings);
882
- const req = AddTrackRequest.fromPartial({
862
+ const req = new AddTrackRequest({
883
863
  cid: simulcastTrack.mediaStreamTrack.id,
884
864
  type: Track.kindToProto(track.kind),
885
865
  muted: track.isMuted,
@@ -1099,18 +1079,18 @@ export default class LocalParticipant extends Participant {
1099
1079
  });
1100
1080
  }
1101
1081
 
1102
- const packet: DataPacket = {
1082
+ const packet = new DataPacket({
1103
1083
  kind,
1104
1084
  value: {
1105
- $case: 'user',
1106
- user: {
1085
+ case: 'user',
1086
+ value: new UserPacket({
1107
1087
  participantSid: this.sid,
1108
1088
  payload: data,
1109
1089
  destinationSids: destinationSids,
1110
1090
  topic,
1111
- },
1091
+ }),
1112
1092
  },
1113
- };
1093
+ });
1114
1094
 
1115
1095
  await this.engine.sendDataPacket(packet, kind);
1116
1096
  }
@@ -1333,10 +1313,12 @@ export default class LocalParticipant extends Participant {
1333
1313
  const infos: TrackPublishedResponse[] = [];
1334
1314
  this.tracks.forEach((track: LocalTrackPublication) => {
1335
1315
  if (track.track !== undefined) {
1336
- infos.push({
1337
- cid: track.track.mediaStreamID,
1338
- track: track.trackInfo,
1339
- });
1316
+ infos.push(
1317
+ new TrackPublishedResponse({
1318
+ cid: track.track.mediaStreamID,
1319
+ track: track.trackInfo,
1320
+ }),
1321
+ );
1340
1322
  }
1341
1323
  });
1342
1324
  return infos;
@@ -1347,11 +1329,13 @@ export default class LocalParticipant extends Participant {
1347
1329
  const infos: DataChannelInfo[] = [];
1348
1330
  const getInfo = (dc: RTCDataChannel | undefined, target: SignalTarget) => {
1349
1331
  if (dc?.id !== undefined && dc.id !== null) {
1350
- infos.push({
1351
- label: dc.label,
1352
- id: dc.id,
1353
- target,
1354
- });
1332
+ infos.push(
1333
+ new DataChannelInfo({
1334
+ label: dc.label,
1335
+ id: dc.id,
1336
+ target,
1337
+ }),
1338
+ );
1355
1339
  }
1356
1340
  };
1357
1341
  getInfo(this.engine.dataChannelForKind(DataPacket_Kind.LOSSY), SignalTarget.PUBLISHER);
@@ -1,4 +1,5 @@
1
- import EventEmitter from 'eventemitter3';
1
+ import { EventEmitter } from 'events';
2
+ import type TypedEmitter from 'typed-emitter';
2
3
  import log from '../../logger';
3
4
  import {
4
5
  DataPacket_Kind,
@@ -6,7 +7,7 @@ import {
6
7
  ParticipantPermission,
7
8
  ConnectionQuality as ProtoQuality,
8
9
  SubscriptionError,
9
- } from '../../proto/livekit_models';
10
+ } from '../../proto/livekit_models_pb';
10
11
  import { ParticipantEvent, TrackEvent } from '../events';
11
12
  import type LocalTrackPublication from '../track/LocalTrackPublication';
12
13
  import type RemoteTrack from '../track/RemoteTrack';
@@ -34,7 +35,7 @@ function qualityFromProto(q: ProtoQuality): ConnectionQuality {
34
35
  }
35
36
  }
36
37
 
37
- export default class Participant extends EventEmitter<ParticipantEventCallbacks> {
38
+ export default class Participant extends (EventEmitter as new () => TypedEmitter<ParticipantEventCallbacks>) {
38
39
  protected participantInfo?: ParticipantInfo;
39
40
 
40
41
  audioTracks: Map<string, TrackPublication>;
@@ -75,6 +76,7 @@ export default class Participant extends EventEmitter<ParticipantEventCallbacks>
75
76
  /** @internal */
76
77
  constructor(sid: string, identity: string, name?: string, metadata?: string) {
77
78
  super();
79
+ this.setMaxListeners(100);
78
80
  this.sid = sid;
79
81
  this.identity = identity;
80
82
  this.name = name;
@@ -141,7 +143,7 @@ export default class Participant extends EventEmitter<ParticipantEventCallbacks>
141
143
  /** when participant joined the room */
142
144
  get joinedAt(): Date | undefined {
143
145
  if (this.participantInfo) {
144
- return new Date(this.participantInfo.joinedAt * 1000);
146
+ return new Date(Number.parseInt(this.participantInfo.joinedAt.toString()) * 1000);
145
147
  }
146
148
  return new Date();
147
149
  }
@@ -1,4 +1,4 @@
1
- import type { TrackPermission } from '../../proto/livekit_rtc';
1
+ import { TrackPermission } from '../../proto/livekit_rtc_pb';
2
2
 
3
3
  export interface ParticipantTrackPermission {
4
4
  /**
@@ -33,10 +33,10 @@ export function trackPermissionToProto(perms: ParticipantTrackPermission): Track
33
33
  'Invalid track permission, must provide at least one of participantIdentity and participantSid',
34
34
  );
35
35
  }
36
- return {
36
+ return new TrackPermission({
37
37
  participantIdentity: perms.participantIdentity ?? '',
38
38
  participantSid: perms.participantSid ?? '',
39
39
  allTracks: perms.allowAll ?? false,
40
40
  trackSids: perms.allowedTrackSids || [],
41
- };
41
+ });
42
42
  }
@@ -1,8 +1,7 @@
1
- import type EventEmitter from 'eventemitter3';
2
1
  import type { SignalClient } from '../../api/SignalClient';
3
2
  import log from '../../logger';
4
- import type { ParticipantInfo, SubscriptionError } from '../../proto/livekit_models';
5
- import type { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc';
3
+ import type { ParticipantInfo, SubscriptionError } from '../../proto/livekit_models_pb';
4
+ import type { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc_pb';
6
5
  import { ParticipantEvent, TrackEvent } from '../events';
7
6
  import RemoteAudioTrack from '../track/RemoteAudioTrack';
8
7
  import type RemoteTrack from '../track/RemoteTrack';
@@ -350,9 +349,9 @@ export default class RemoteParticipant extends Participant {
350
349
  }
351
350
 
352
351
  /** @internal */
353
- emit<T extends EventEmitter.EventNames<ParticipantEventCallbacks>>(
354
- event: T,
355
- ...args: EventEmitter.EventArgs<ParticipantEventCallbacks, T>
352
+ emit<E extends keyof ParticipantEventCallbacks>(
353
+ event: E,
354
+ ...args: Parameters<ParticipantEventCallbacks[E]>
356
355
  ): boolean {
357
356
  log.trace('participant event', { participant: this.sid, event, args });
358
357
  return super.emit(event, ...args);
@@ -1,3 +1,4 @@
1
+ import { describe, expect, it } from 'vitest';
1
2
  import { ScreenSharePresets, VideoPreset, VideoPresets, VideoPresets43 } from '../track/options';
2
3
  import {
3
4
  computeDefaultScreenShareSimulcastPresets,
@@ -3,13 +3,13 @@ import { TrackInvalidError } from '../errors';
3
3
  import LocalAudioTrack from '../track/LocalAudioTrack';
4
4
  import LocalVideoTrack from '../track/LocalVideoTrack';
5
5
  import { Track } from '../track/Track';
6
- import { ScreenSharePresets, VideoPreset, VideoPresets, VideoPresets43 } from '../track/options';
7
6
  import type {
8
7
  BackupVideoCodec,
9
8
  TrackPublishOptions,
10
9
  VideoCodec,
11
10
  VideoEncoding,
12
11
  } from '../track/options';
12
+ import { ScreenSharePresets, VideoPreset, VideoPresets, VideoPresets43 } from '../track/options';
13
13
  import { getReactNativeOs, isFireFox, isReactNative, isSVCCodec } from '../utils';
14
14
 
15
15
  /** @internal */
@@ -240,7 +240,9 @@ export function determineAppropriateEncoding(
240
240
  }
241
241
  // presets are based on the assumption of vp8 as a codec
242
242
  // for other codecs we adjust the maxBitrate if no specific videoEncoding has been provided
243
- // TODO make the bitrate multipliers configurable per codec
243
+ // users should override these with ones that are optimized for their use case
244
+ // NOTE: SVC codec bitrates are inclusive of all scalability layers. while
245
+ // bitrate for non-SVC codecs does not include other simulcast layers.
244
246
  if (codec) {
245
247
  switch (codec) {
246
248
  case 'av1':
@@ -1,3 +1,4 @@
1
+ import { debounce } from 'ts-debounce';
1
2
  import log from '../../logger';
2
3
  import { getBrowser } from '../../utils/browserParser';
3
4
  import DeviceManager from '../DeviceManager';
@@ -108,8 +109,8 @@ export default abstract class LocalTrack extends Track {
108
109
  detachTrack(this._mediaStreamTrack, el);
109
110
  });
110
111
  this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
111
- this._mediaStreamTrack.removeEventListener('mute', this.pauseUpstream);
112
- this._mediaStreamTrack.removeEventListener('unmute', this.resumeUpstream);
112
+ this._mediaStreamTrack.removeEventListener('mute', this.handleTrackMuteEvent);
113
+ this._mediaStreamTrack.removeEventListener('unmute', this.handleTrackUnmuteEvent);
113
114
  if (!this.providedByUser && this._mediaStreamTrack !== newTrack) {
114
115
  this._mediaStreamTrack.stop();
115
116
  }
@@ -123,8 +124,8 @@ export default abstract class LocalTrack extends Track {
123
124
  // the track is "muted"
124
125
  // note this is different from LocalTrack.mute because we do not want to
125
126
  // touch MediaStreamTrack.enabled
126
- newTrack.addEventListener('mute', this.pauseUpstream);
127
- newTrack.addEventListener('unmute', this.resumeUpstream);
127
+ newTrack.addEventListener('mute', this.handleTrackMuteEvent);
128
+ newTrack.addEventListener('unmute', this.handleTrackUnmuteEvent);
128
129
  this._constraints = newTrack.getConstraints();
129
130
  }
130
131
  if (this.sender) {
@@ -274,18 +275,32 @@ export default abstract class LocalTrack extends Track {
274
275
  log.debug(`visibility changed, is in Background: ${this.isInBackground}`);
275
276
 
276
277
  if (!this.isInBackground && this.needsReAcquisition && !this.isUserProvided && !this.isMuted) {
277
- log.debug(`track needs to be reaquired, restarting ${this.source}`);
278
+ log.debug(`track needs to be reacquired, restarting ${this.source}`);
278
279
  await this.restart();
279
280
  this.reacquireTrack = false;
280
281
  }
281
282
  }
282
283
 
284
+ private handleTrackMuteEvent = () =>
285
+ this.debouncedTrackMuteHandler().catch(() =>
286
+ log.debug('track mute bounce got cancelled by an unmute event'),
287
+ );
288
+
289
+ private debouncedTrackMuteHandler = debounce(async () => {
290
+ await this.pauseUpstream();
291
+ }, 5000);
292
+
293
+ private handleTrackUnmuteEvent = async () => {
294
+ this.debouncedTrackMuteHandler.cancel('unmute');
295
+ await this.resumeUpstream();
296
+ };
297
+
283
298
  private handleEnded = () => {
284
299
  if (this.isInBackground) {
285
300
  this.reacquireTrack = true;
286
301
  }
287
- this._mediaStreamTrack.removeEventListener('mute', this.pauseUpstream);
288
- this._mediaStreamTrack.removeEventListener('unmute', this.resumeUpstream);
302
+ this._mediaStreamTrack.removeEventListener('mute', this.handleTrackMuteEvent);
303
+ this._mediaStreamTrack.removeEventListener('unmute', this.handleTrackUnmuteEvent);
289
304
  this.emit(TrackEvent.Ended, this);
290
305
  };
291
306
 
@@ -293,8 +308,8 @@ export default abstract class LocalTrack extends Track {
293
308
  super.stop();
294
309
 
295
310
  this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
296
- this._mediaStreamTrack.removeEventListener('mute', this.pauseUpstream);
297
- this._mediaStreamTrack.removeEventListener('unmute', this.resumeUpstream);
311
+ this._mediaStreamTrack.removeEventListener('mute', this.handleTrackMuteEvent);
312
+ this._mediaStreamTrack.removeEventListener('unmute', this.handleTrackUnmuteEvent);
298
313
  this.processor?.destroy();
299
314
  this.processor = undefined;
300
315
  }
@@ -1,4 +1,4 @@
1
- import type { TrackInfo } from '../../proto/livekit_models';
1
+ import type { TrackInfo } from '../../proto/livekit_models_pb';
2
2
  import { TrackEvent } from '../events';
3
3
  import type LocalAudioTrack from './LocalAudioTrack';
4
4
  import type LocalTrack from './LocalTrack';
@@ -1,4 +1,5 @@
1
- import { VideoQuality } from '../../proto/livekit_models';
1
+ import { describe, expect, it } from 'vitest';
2
+ import { VideoQuality } from '../../proto/livekit_models_pb';
2
3
  import { videoLayersFromEncodings } from './LocalVideoTrack';
3
4
 
4
5
  describe('videoLayersFromEncodings', () => {
@@ -1,10 +1,10 @@
1
1
  import type { SignalClient } from '../../api/SignalClient';
2
2
  import log from '../../logger';
3
- import { VideoLayer, VideoQuality } from '../../proto/livekit_models';
4
- import type { SubscribedCodec, SubscribedQuality } from '../../proto/livekit_rtc';
3
+ import { VideoLayer, VideoQuality } from '../../proto/livekit_models_pb';
4
+ import { SubscribedCodec, SubscribedQuality } from '../../proto/livekit_rtc_pb';
5
5
  import { ScalabilityMode } from '../participant/publishUtils';
6
- import { computeBitrate, monitorFrequency } from '../stats';
7
6
  import type { VideoSenderStats } from '../stats';
7
+ import { computeBitrate, monitorFrequency } from '../stats';
8
8
  import { Mutex, isFireFox, isMobile, isWeb, unwrapConstraint } from '../utils';
9
9
  import LocalTrack from './LocalTrack';
10
10
  import { Track } from './Track';
@@ -173,10 +173,12 @@ export default class LocalVideoTrack extends LocalTrack {
173
173
  setPublishingQuality(maxQuality: VideoQuality) {
174
174
  const qualities: SubscribedQuality[] = [];
175
175
  for (let q = VideoQuality.LOW; q <= VideoQuality.HIGH; q += 1) {
176
- qualities.push({
177
- quality: q,
178
- enabled: q <= maxQuality,
179
- });
176
+ qualities.push(
177
+ new SubscribedQuality({
178
+ quality: q,
179
+ enabled: q <= maxQuality,
180
+ }),
181
+ );
180
182
  }
181
183
  log.debug(`setting publishing quality. max quality ${maxQuality}`);
182
184
  this.setPublishingLayers(qualities);
@@ -358,7 +360,7 @@ async function setPublishingLayersForSender(
358
360
  let hasChanged = false;
359
361
 
360
362
  /* disable closable spatial layer as it has video blur / frozen issue with current server / client
361
- 1. chrome 113: when switching to up layer with scalability Mode change, it will generate a
363
+ 1. chrome 113: when switching to up layer with scalability Mode change, it will generate a
362
364
  low resolution frame and recover very quickly, but noticable
363
365
  2. livekit sfu: additional pli request cause video frozen for a few frames, also noticable */
364
366
  const closableSpatial = false;
@@ -456,7 +458,7 @@ export function videoQualityForRid(rid: string): VideoQuality {
456
458
  case 'q':
457
459
  return VideoQuality.LOW;
458
460
  default:
459
- return VideoQuality.UNRECOGNIZED;
461
+ return VideoQuality.HIGH;
460
462
  }
461
463
  }
462
464
 
@@ -469,29 +471,32 @@ export function videoLayersFromEncodings(
469
471
  // default to a single layer, HQ
470
472
  if (!encodings) {
471
473
  return [
472
- {
474
+ new VideoLayer({
473
475
  quality: VideoQuality.HIGH,
474
476
  width,
475
477
  height,
476
478
  bitrate: 0,
477
479
  ssrc: 0,
478
- },
480
+ }),
479
481
  ];
480
482
  }
481
483
 
482
484
  if (svc) {
483
485
  // svc layers
484
486
  /* @ts-ignore */
485
- const sm = new ScalabilityMode(encodings[0].scalabilityMode);
487
+ const encodingSM = encodings[0].scalabilityMode as string;
488
+ const sm = new ScalabilityMode(encodingSM);
486
489
  const layers = [];
487
490
  for (let i = 0; i < sm.spatial; i += 1) {
488
- layers.push({
489
- quality: VideoQuality.HIGH - i,
490
- width: width / 2 ** i,
491
- height: height / 2 ** i,
492
- bitrate: encodings[0].maxBitrate ? encodings[0].maxBitrate / 3 ** i : 0,
493
- ssrc: 0,
494
- });
491
+ layers.push(
492
+ new VideoLayer({
493
+ quality: VideoQuality.HIGH - i,
494
+ width: Math.ceil(width / 2 ** i),
495
+ height: Math.ceil(height / 2 ** i),
496
+ bitrate: encodings[0].maxBitrate ? Math.ceil(encodings[0].maxBitrate / 3 ** i) : 0,
497
+ ssrc: 0,
498
+ }),
499
+ );
495
500
  }
496
501
  return layers;
497
502
  }
@@ -499,15 +504,12 @@ export function videoLayersFromEncodings(
499
504
  return encodings.map((encoding) => {
500
505
  const scale = encoding.scaleResolutionDownBy ?? 1;
501
506
  let quality = videoQualityForRid(encoding.rid ?? '');
502
- if (quality === VideoQuality.UNRECOGNIZED && encodings.length === 1) {
503
- quality = VideoQuality.HIGH;
504
- }
505
- return {
507
+ return new VideoLayer({
506
508
  quality,
507
- width: width / scale,
508
- height: height / scale,
509
+ width: Math.ceil(width / scale),
510
+ height: Math.ceil(height / scale),
509
511
  bitrate: encoding.maxBitrate ?? 0,
510
512
  ssrc: 0,
511
- };
513
+ });
512
514
  });
513
515
  }
@@ -1,6 +1,11 @@
1
1
  import log from '../../logger';
2
- import { SubscriptionError, TrackInfo, VideoQuality } from '../../proto/livekit_models';
3
- import { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc';
2
+ import {
3
+ ParticipantTracks,
4
+ SubscriptionError,
5
+ TrackInfo,
6
+ VideoQuality,
7
+ } from '../../proto/livekit_models_pb';
8
+ import { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc_pb';
4
9
  import { TrackEvent } from '../events';
5
10
  import type RemoteTrack from './RemoteTrack';
6
11
  import RemoteVideoTrack from './RemoteVideoTrack';
@@ -46,18 +51,18 @@ export default class RemoteTrackPublication extends TrackPublication {
46
51
  this.allowed = true;
47
52
  }
48
53
 
49
- const sub: UpdateSubscription = {
54
+ const sub = new UpdateSubscription({
50
55
  trackSids: [this.trackSid],
51
56
  subscribe: this.subscribed,
52
57
  participantTracks: [
53
- {
58
+ new ParticipantTracks({
54
59
  // sending an empty participant id since TrackPublication doesn't keep it
55
60
  // this is filled in by the participant that receives this message
56
61
  participantSid: '',
57
62
  trackSids: [this.trackSid],
58
- },
63
+ }),
59
64
  ],
60
- };
65
+ });
61
66
  this.emit(TrackEvent.UpdateSubscription, sub);
62
67
  this.emitSubscriptionUpdateIfChanged(prevStatus);
63
68
  this.emitPermissionUpdateIfChanged(prevPermission);
@@ -286,7 +291,7 @@ export default class RemoteTrackPublication extends TrackPublication {
286
291
 
287
292
  /* @internal */
288
293
  emitTrackUpdate() {
289
- const settings: UpdateTrackSettings = UpdateTrackSettings.fromPartial({
294
+ const settings: UpdateTrackSettings = new UpdateTrackSettings({
290
295
  trackSids: [this.trackSid],
291
296
  disabled: this.disabled,
292
297
  fps: this.fps,
@@ -1,9 +1,10 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
1
2
  import MockMediaStreamTrack from '../../test/MockMediaStreamTrack';
2
3
  import { TrackEvent } from '../events';
3
4
  import RemoteVideoTrack, { ElementInfo } from './RemoteVideoTrack';
4
5
  import type { Track } from './Track';
5
6
 
6
- jest.useFakeTimers();
7
+ vi.useFakeTimers();
7
8
 
8
9
  describe('RemoteVideoTrack', () => {
9
10
  let track: RemoteVideoTrack;
@@ -73,7 +74,7 @@ describe('RemoteVideoTrack', () => {
73
74
  elementInfo.setDimensions(100, 100);
74
75
 
75
76
  track.observeElementInfo(elementInfo);
76
- jest.runAllTimers();
77
+ vi.runAllTimers();
77
78
 
78
79
  expect(events).toHaveLength(1);
79
80
  expect(events[0].width).toBe(100);
@@ -85,10 +86,10 @@ describe('RemoteVideoTrack', () => {
85
86
  elementInfo.setDimensions(100, 100);
86
87
 
87
88
  track.observeElementInfo(elementInfo);
88
- jest.runAllTimers();
89
+ vi.runAllTimers();
89
90
 
90
91
  elementInfo.setDimensions(200, 200);
91
- jest.runAllTimers();
92
+ vi.runAllTimers();
92
93
 
93
94
  expect(events).toHaveLength(2);
94
95
  expect(events[1].width).toBe(200);
@@ -1,8 +1,9 @@
1
- import EventEmitter from 'eventemitter3';
1
+ import { EventEmitter } from 'events';
2
+ import type TypedEventEmitter from 'typed-emitter';
2
3
  import type { SignalClient } from '../../api/SignalClient';
3
4
  import log from '../../logger';
4
- import { TrackSource, TrackType } from '../../proto/livekit_models';
5
- import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc';
5
+ import { TrackSource, TrackType } from '../../proto/livekit_models_pb';
6
+ import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc_pb';
6
7
  import { TrackEvent } from '../events';
7
8
  import { isFireFox, isSafari, isWeb } from '../utils';
8
9
 
@@ -12,7 +13,7 @@ const BACKGROUND_REACTION_DELAY = 5000;
12
13
  // Safari tracks which audio elements have been "blessed" by the user.
13
14
  const recycledElements: Array<HTMLAudioElement> = [];
14
15
 
15
- export abstract class Track extends EventEmitter<TrackEventCallbacks> {
16
+ export abstract class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEventCallbacks>) {
16
17
  kind: Track.Kind;
17
18
 
18
19
  attachedElements: HTMLMediaElement[] = [];
@@ -51,6 +52,7 @@ export abstract class Track extends EventEmitter<TrackEventCallbacks> {
51
52
 
52
53
  protected constructor(mediaTrack: MediaStreamTrack, kind: Track.Kind) {
53
54
  super();
55
+ this.setMaxListeners(100);
54
56
  this.kind = kind;
55
57
  this._mediaStreamTrack = mediaTrack;
56
58
  this._mediaStreamID = mediaTrack.id;
@@ -368,7 +370,8 @@ export namespace Track {
368
370
  case Kind.Video:
369
371
  return TrackType.VIDEO;
370
372
  default:
371
- return TrackType.UNRECOGNIZED;
373
+ // FIXME this was UNRECOGNIZED before
374
+ return TrackType.DATA;
372
375
  }
373
376
  }
374
377
 
@@ -396,7 +399,7 @@ export namespace Track {
396
399
  case Source.ScreenShareAudio:
397
400
  return TrackSource.SCREEN_SHARE_AUDIO;
398
401
  default:
399
- return TrackSource.UNRECOGNIZED;
402
+ return TrackSource.UNKNOWN;
400
403
  }
401
404
  }
402
405