livekit-client 1.12.0 → 1.12.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. package/README.md +19 -1
  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 +442 -334
  5. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  6. package/dist/livekit-client.esm.mjs +12303 -14499
  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 -3
  27. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  28. package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +21 -2
  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 +8 -7
  51. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  52. package/dist/src/room/timers.d.ts +5 -4
  53. package/dist/src/room/timers.d.ts.map +1 -1
  54. package/dist/src/room/track/LocalTrack.d.ts +3 -0
  55. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  56. package/dist/src/room/track/LocalTrackPublication.d.ts +1 -1
  57. package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -1
  58. package/dist/src/room/track/LocalVideoTrack.d.ts +2 -2
  59. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  60. package/dist/src/room/track/RemoteTrackPublication.d.ts +1 -1
  61. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  62. package/dist/src/room/track/Track.d.ts +6 -4
  63. package/dist/src/room/track/Track.d.ts.map +1 -1
  64. package/dist/src/room/track/TrackPublication.d.ts +7 -5
  65. package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
  66. package/dist/src/room/track/create.d.ts.map +1 -1
  67. package/dist/src/room/track/options.d.ts +7 -0
  68. package/dist/src/room/track/options.d.ts.map +1 -1
  69. package/dist/src/room/track/utils.d.ts +5 -1
  70. package/dist/src/room/track/utils.d.ts.map +1 -1
  71. package/dist/src/room/utils.d.ts +3 -1
  72. package/dist/src/room/utils.d.ts.map +1 -1
  73. package/dist/src/test/mocks.d.ts +4 -3
  74. package/dist/src/test/mocks.d.ts.map +1 -1
  75. package/dist/src/utils/browserParser.d.ts +2 -0
  76. package/dist/src/utils/browserParser.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 -3
  85. package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +21 -2
  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 +8 -7
  97. package/dist/ts4.2/src/room/timers.d.ts +5 -4
  98. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -0
  99. package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +1 -1
  100. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -2
  101. package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +1 -1
  102. package/dist/ts4.2/src/room/track/Track.d.ts +6 -4
  103. package/dist/ts4.2/src/room/track/TrackPublication.d.ts +7 -5
  104. package/dist/ts4.2/src/room/track/options.d.ts +7 -0
  105. package/dist/ts4.2/src/room/track/utils.d.ts +5 -1
  106. package/dist/ts4.2/src/room/utils.d.ts +3 -1
  107. package/dist/ts4.2/src/test/mocks.d.ts +4 -3
  108. package/dist/ts4.2/src/utils/browserParser.d.ts +2 -0
  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 +14 -16
  121. package/src/e2ee/worker/ParticipantKeyHandler.ts +48 -2
  122. package/src/e2ee/worker/e2ee.worker.ts +12 -6
  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 +24 -18
  128. package/src/room/RegionUrlProvider.ts +11 -2
  129. package/src/room/Room.test.ts +1 -0
  130. package/src/room/Room.ts +175 -86
  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 +24 -21
  135. package/src/room/participant/publishUtils.test.ts +1 -0
  136. package/src/room/track/LocalTrack.ts +24 -9
  137. package/src/room/track/LocalTrackPublication.ts +1 -1
  138. package/src/room/track/LocalVideoTrack.test.ts +2 -1
  139. package/src/room/track/LocalVideoTrack.ts +22 -22
  140. package/src/room/track/RemoteTrackPublication.ts +12 -7
  141. package/src/room/track/RemoteVideoTrack.test.ts +5 -4
  142. package/src/room/track/Track.ts +9 -6
  143. package/src/room/track/TrackPublication.ts +7 -5
  144. package/src/room/track/create.ts +18 -17
  145. package/src/room/track/facingMode.test.ts +1 -0
  146. package/src/room/track/options.ts +6 -0
  147. package/src/room/track/utils.test.ts +1 -0
  148. package/src/room/track/utils.ts +44 -2
  149. package/src/room/utils.test.ts +16 -0
  150. package/src/room/utils.ts +20 -4
  151. package/src/test/mocks.ts +7 -5
  152. package/src/utils/AsyncQueue.test.ts +1 -0
  153. package/src/utils/browserParser.test.ts +33 -3
  154. package/src/utils/browserParser.ts +5 -0
  155. package/dist/src/proto/google/protobuf/timestamp.d.ts +0 -146
  156. package/dist/src/proto/google/protobuf/timestamp.d.ts.map +0 -1
  157. package/dist/src/proto/livekit_models.d.ts +0 -2399
  158. package/dist/src/proto/livekit_models.d.ts.map +0 -1
  159. package/dist/src/proto/livekit_rtc.d.ts +0 -14352
  160. package/dist/src/proto/livekit_rtc.d.ts.map +0 -1
  161. package/dist/ts4.2/src/proto/google/protobuf/timestamp.d.ts +0 -150
  162. package/dist/ts4.2/src/proto/livekit_models.d.ts +0 -2659
  163. package/dist/ts4.2/src/proto/livekit_rtc.d.ts +0 -15764
  164. package/src/proto/google/protobuf/timestamp.ts +0 -230
  165. package/src/proto/livekit_models.ts +0 -4006
  166. package/src/proto/livekit_rtc.ts +0 -4672
@@ -1,3 +1,4 @@
1
+ import { protoInt64 } from '@bufbuild/protobuf';
1
2
  import log from '../logger';
2
3
  import {
3
4
  ClientInfo,
@@ -7,12 +8,14 @@ import {
7
8
  Room,
8
9
  SpeakerInfo,
9
10
  VideoLayer,
10
- } from '../proto/livekit_models';
11
+ } from '../proto/livekit_models_pb';
11
12
  import {
12
13
  AddTrackRequest,
13
14
  ConnectionQualityUpdate,
14
15
  JoinResponse,
15
16
  LeaveRequest,
17
+ MuteTrackRequest,
18
+ Ping,
16
19
  ReconnectResponse,
17
20
  SessionDescription,
18
21
  SignalRequest,
@@ -21,18 +24,22 @@ import {
21
24
  SimulateScenario,
22
25
  StreamStateUpdate,
23
26
  SubscribedQualityUpdate,
27
+ SubscriptionPermission,
24
28
  SubscriptionPermissionUpdate,
25
29
  SubscriptionResponse,
26
30
  SyncState,
27
31
  TrackPermission,
28
32
  TrackPublishedResponse,
29
33
  TrackUnpublishedResponse,
34
+ TrickleRequest,
35
+ UpdateParticipantMetadata,
30
36
  UpdateSubscription,
31
37
  UpdateTrackSettings,
32
- } from '../proto/livekit_rtc';
38
+ UpdateVideoLayers,
39
+ } from '../proto/livekit_rtc_pb';
33
40
  import { ConnectionError, ConnectionErrorReason } from '../room/errors';
34
41
  import CriticalTimers from '../room/timers';
35
- import { Mutex, getClientInfo, isReactNative, sleep } from '../room/utils';
42
+ import { Mutex, getClientInfo, isReactNative, sleep, toWebsocketUrl } from '../room/utils';
36
43
  import { AsyncQueue } from '../utils/AsyncQueue';
37
44
 
38
45
  // internal options
@@ -65,7 +72,7 @@ export interface SignalOptions {
65
72
 
66
73
  type SignalMessage = SignalRequest['message'];
67
74
 
68
- type SignalKind = NonNullable<SignalMessage>['$case'];
75
+ type SignalKind = NonNullable<SignalMessage>['case'];
69
76
 
70
77
  const passThroughQueueSignals: Array<SignalKind> = [
71
78
  'syncState',
@@ -77,7 +84,7 @@ const passThroughQueueSignals: Array<SignalKind> = [
77
84
  ];
78
85
 
79
86
  function canPassThroughQueue(req: SignalMessage): boolean {
80
- const canPass = passThroughQueueSignals.indexOf(req!.$case) >= 0;
87
+ const canPass = passThroughQueueSignals.indexOf(req!.case) >= 0;
81
88
  log.trace('request allowed to bypass queue:', { canPass, req });
82
89
  return canPass;
83
90
  }
@@ -206,9 +213,7 @@ export class SignalClient {
206
213
  abortSignal?: AbortSignal,
207
214
  ): Promise<JoinResponse | ReconnectResponse | void> {
208
215
  this.connectOptions = opts;
209
- if (url.startsWith('http')) {
210
- url = url.replace('http', 'ws');
211
- }
216
+ url = toWebsocketUrl(url);
212
217
  // strip trailing slash
213
218
  url = url.replace(/\/$/, '');
214
219
  url += '/rtc';
@@ -268,9 +273,9 @@ export class SignalClient {
268
273
  let resp: SignalResponse;
269
274
  if (typeof ev.data === 'string') {
270
275
  const json = JSON.parse(ev.data);
271
- resp = SignalResponse.fromJSON(json);
276
+ resp = SignalResponse.fromJson(json);
272
277
  } else if (ev.data instanceof ArrayBuffer) {
273
- resp = SignalResponse.decode(new Uint8Array(ev.data));
278
+ resp = SignalResponse.fromBinary(new Uint8Array(ev.data));
274
279
  } else {
275
280
  log.error(`could not decode websocket message: ${typeof ev.data}`);
276
281
  return;
@@ -279,11 +284,11 @@ export class SignalClient {
279
284
  if (!this.isConnected) {
280
285
  let shouldProcessMessage = false;
281
286
  // handle join message only
282
- if (resp.message?.$case === 'join') {
287
+ if (resp.message?.case === 'join') {
283
288
  this.isConnected = true;
284
289
  abortSignal?.removeEventListener('abort', abortHandler);
285
- this.pingTimeoutDuration = resp.message.join.pingTimeout;
286
- this.pingIntervalDuration = resp.message.join.pingInterval;
290
+ this.pingTimeoutDuration = resp.message.value.pingTimeout;
291
+ this.pingIntervalDuration = resp.message.value.pingInterval;
287
292
 
288
293
  if (this.pingTimeoutDuration && this.pingTimeoutDuration > 0) {
289
294
  log.debug('ping config', {
@@ -292,14 +297,14 @@ export class SignalClient {
292
297
  });
293
298
  this.startPingInterval();
294
299
  }
295
- resolve(resp.message.join);
300
+ resolve(resp.message.value);
296
301
  } else if (opts.reconnect) {
297
302
  // in reconnecting, any message received means signal reconnected
298
303
  this.isConnected = true;
299
304
  abortSignal?.removeEventListener('abort', abortHandler);
300
305
  this.startPingInterval();
301
- if (resp.message?.$case === 'reconnect') {
302
- resolve(resp.message?.reconnect);
306
+ if (resp.message?.case === 'reconnect') {
307
+ resolve(resp.message?.value);
303
308
  } else {
304
309
  resolve();
305
310
  shouldProcessMessage = true;
@@ -308,7 +313,7 @@ export class SignalClient {
308
313
  // non-reconnect case, should receive join response first
309
314
  reject(
310
315
  new ConnectionError(
311
- `did not receive join response, got ${resp.message?.$case} instead`,
316
+ `did not receive join response, got ${resp.message?.case} instead`,
312
317
  ),
313
318
  );
314
319
  }
@@ -382,8 +387,8 @@ export class SignalClient {
382
387
  sendOffer(offer: RTCSessionDescriptionInit) {
383
388
  log.debug('sending offer', offer);
384
389
  this.sendRequest({
385
- $case: 'offer',
386
- offer: toProtoSessionDescription(offer),
390
+ case: 'offer',
391
+ value: toProtoSessionDescription(offer),
387
392
  });
388
393
  }
389
394
 
@@ -391,94 +396,94 @@ export class SignalClient {
391
396
  sendAnswer(answer: RTCSessionDescriptionInit) {
392
397
  log.debug('sending answer');
393
398
  return this.sendRequest({
394
- $case: 'answer',
395
- answer: toProtoSessionDescription(answer),
399
+ case: 'answer',
400
+ value: toProtoSessionDescription(answer),
396
401
  });
397
402
  }
398
403
 
399
404
  sendIceCandidate(candidate: RTCIceCandidateInit, target: SignalTarget) {
400
405
  log.trace('sending ice candidate', candidate);
401
406
  return this.sendRequest({
402
- $case: 'trickle',
403
- trickle: {
407
+ case: 'trickle',
408
+ value: new TrickleRequest({
404
409
  candidateInit: JSON.stringify(candidate),
405
410
  target,
406
- },
411
+ }),
407
412
  });
408
413
  }
409
414
 
410
415
  sendMuteTrack(trackSid: string, muted: boolean) {
411
416
  return this.sendRequest({
412
- $case: 'mute',
413
- mute: {
417
+ case: 'mute',
418
+ value: new MuteTrackRequest({
414
419
  sid: trackSid,
415
420
  muted,
416
- },
421
+ }),
417
422
  });
418
423
  }
419
424
 
420
425
  sendAddTrack(req: AddTrackRequest) {
421
426
  return this.sendRequest({
422
- $case: 'addTrack',
423
- addTrack: req,
427
+ case: 'addTrack',
428
+ value: req,
424
429
  });
425
430
  }
426
431
 
427
432
  sendUpdateLocalMetadata(metadata: string, name: string) {
428
433
  return this.sendRequest({
429
- $case: 'updateMetadata',
430
- updateMetadata: {
434
+ case: 'updateMetadata',
435
+ value: new UpdateParticipantMetadata({
431
436
  metadata,
432
437
  name,
433
- },
438
+ }),
434
439
  });
435
440
  }
436
441
 
437
442
  sendUpdateTrackSettings(settings: UpdateTrackSettings) {
438
443
  this.sendRequest({
439
- $case: 'trackSetting',
440
- trackSetting: settings,
444
+ case: 'trackSetting',
445
+ value: settings,
441
446
  });
442
447
  }
443
448
 
444
449
  sendUpdateSubscription(sub: UpdateSubscription) {
445
450
  return this.sendRequest({
446
- $case: 'subscription',
447
- subscription: sub,
451
+ case: 'subscription',
452
+ value: sub,
448
453
  });
449
454
  }
450
455
 
451
456
  sendSyncState(sync: SyncState) {
452
457
  return this.sendRequest({
453
- $case: 'syncState',
454
- syncState: sync,
458
+ case: 'syncState',
459
+ value: sync,
455
460
  });
456
461
  }
457
462
 
458
463
  sendUpdateVideoLayers(trackSid: string, layers: VideoLayer[]) {
459
464
  return this.sendRequest({
460
- $case: 'updateLayers',
461
- updateLayers: {
465
+ case: 'updateLayers',
466
+ value: new UpdateVideoLayers({
462
467
  trackSid,
463
468
  layers,
464
- },
469
+ }),
465
470
  });
466
471
  }
467
472
 
468
473
  sendUpdateSubscriptionPermissions(allParticipants: boolean, trackPermissions: TrackPermission[]) {
469
474
  return this.sendRequest({
470
- $case: 'subscriptionPermission',
471
- subscriptionPermission: {
475
+ case: 'subscriptionPermission',
476
+ value: new SubscriptionPermission({
472
477
  allParticipants,
473
478
  trackPermissions,
474
- },
479
+ }),
475
480
  });
476
481
  }
477
482
 
478
483
  sendSimulateScenario(scenario: SimulateScenario) {
479
484
  return this.sendRequest({
480
- $case: 'simulate',
481
- simulate: scenario,
485
+ case: 'simulate',
486
+ value: scenario,
482
487
  });
483
488
  }
484
489
 
@@ -486,26 +491,26 @@ export class SignalClient {
486
491
  /** send both of ping and pingReq for compatibility to old and new server */
487
492
  return Promise.all([
488
493
  this.sendRequest({
489
- $case: 'ping',
490
- ping: Date.now(),
494
+ case: 'ping',
495
+ value: protoInt64.parse(Date.now()),
491
496
  }),
492
497
  this.sendRequest({
493
- $case: 'pingReq',
494
- pingReq: {
495
- timestamp: Date.now(),
496
- rtt: this.rtt,
497
- },
498
+ case: 'pingReq',
499
+ value: new Ping({
500
+ timestamp: protoInt64.parse(Date.now()),
501
+ rtt: protoInt64.parse(this.rtt),
502
+ }),
498
503
  }),
499
504
  ]);
500
505
  }
501
506
 
502
507
  sendLeave() {
503
508
  return this.sendRequest({
504
- $case: 'leave',
505
- leave: {
509
+ case: 'leave',
510
+ value: new LeaveRequest({
506
511
  canReconnect: false,
507
512
  reason: DisconnectReason.CLIENT_INITIATED,
508
- },
513
+ }),
509
514
  });
510
515
  }
511
516
 
@@ -527,18 +532,16 @@ export class SignalClient {
527
532
  await sleep(this.signalLatency);
528
533
  }
529
534
  if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
530
- log.error(`cannot send signal request before connected, type: ${message?.$case}`);
535
+ log.error(`cannot send signal request before connected, type: ${message?.case}`);
531
536
  return;
532
537
  }
538
+ const req = new SignalRequest({ message });
533
539
 
534
- const req = {
535
- message,
536
- };
537
540
  try {
538
541
  if (this.useJSON) {
539
- this.ws.send(JSON.stringify(SignalRequest.toJSON(req)));
542
+ this.ws.send(req.toJsonString());
540
543
  } else {
541
- this.ws.send(SignalRequest.encode(req).finish());
544
+ this.ws.send(req.toBinary());
542
545
  }
543
546
  } catch (e) {
544
547
  log.error('error sending signal message', { error: e });
@@ -551,77 +554,77 @@ export class SignalClient {
551
554
  log.debug('received unsupported message');
552
555
  return;
553
556
  }
554
- if (msg.$case === 'answer') {
555
- const sd = fromProtoSessionDescription(msg.answer);
557
+ if (msg.case === 'answer') {
558
+ const sd = fromProtoSessionDescription(msg.value);
556
559
  if (this.onAnswer) {
557
560
  this.onAnswer(sd);
558
561
  }
559
- } else if (msg.$case === 'offer') {
560
- const sd = fromProtoSessionDescription(msg.offer);
562
+ } else if (msg.case === 'offer') {
563
+ const sd = fromProtoSessionDescription(msg.value);
561
564
  if (this.onOffer) {
562
565
  this.onOffer(sd);
563
566
  }
564
- } else if (msg.$case === 'trickle') {
565
- const candidate: RTCIceCandidateInit = JSON.parse(msg.trickle.candidateInit!);
567
+ } else if (msg.case === 'trickle') {
568
+ const candidate: RTCIceCandidateInit = JSON.parse(msg.value.candidateInit!);
566
569
  if (this.onTrickle) {
567
- this.onTrickle(candidate, msg.trickle.target);
570
+ this.onTrickle(candidate, msg.value.target);
568
571
  }
569
- } else if (msg.$case === 'update') {
572
+ } else if (msg.case === 'update') {
570
573
  if (this.onParticipantUpdate) {
571
- this.onParticipantUpdate(msg.update.participants ?? []);
574
+ this.onParticipantUpdate(msg.value.participants ?? []);
572
575
  }
573
- } else if (msg.$case === 'trackPublished') {
576
+ } else if (msg.case === 'trackPublished') {
574
577
  if (this.onLocalTrackPublished) {
575
- this.onLocalTrackPublished(msg.trackPublished);
578
+ this.onLocalTrackPublished(msg.value);
576
579
  }
577
- } else if (msg.$case === 'speakersChanged') {
580
+ } else if (msg.case === 'speakersChanged') {
578
581
  if (this.onSpeakersChanged) {
579
- this.onSpeakersChanged(msg.speakersChanged.speakers ?? []);
582
+ this.onSpeakersChanged(msg.value.speakers ?? []);
580
583
  }
581
- } else if (msg.$case === 'leave') {
584
+ } else if (msg.case === 'leave') {
582
585
  if (this.onLeave) {
583
- this.onLeave(msg.leave);
586
+ this.onLeave(msg.value);
584
587
  }
585
- } else if (msg.$case === 'mute') {
588
+ } else if (msg.case === 'mute') {
586
589
  if (this.onRemoteMuteChanged) {
587
- this.onRemoteMuteChanged(msg.mute.sid, msg.mute.muted);
590
+ this.onRemoteMuteChanged(msg.value.sid, msg.value.muted);
588
591
  }
589
- } else if (msg.$case === 'roomUpdate') {
590
- if (this.onRoomUpdate && msg.roomUpdate.room) {
591
- this.onRoomUpdate(msg.roomUpdate.room);
592
+ } else if (msg.case === 'roomUpdate') {
593
+ if (this.onRoomUpdate && msg.value.room) {
594
+ this.onRoomUpdate(msg.value.room);
592
595
  }
593
- } else if (msg.$case === 'connectionQuality') {
596
+ } else if (msg.case === 'connectionQuality') {
594
597
  if (this.onConnectionQuality) {
595
- this.onConnectionQuality(msg.connectionQuality);
598
+ this.onConnectionQuality(msg.value);
596
599
  }
597
- } else if (msg.$case === 'streamStateUpdate') {
600
+ } else if (msg.case === 'streamStateUpdate') {
598
601
  if (this.onStreamStateUpdate) {
599
- this.onStreamStateUpdate(msg.streamStateUpdate);
602
+ this.onStreamStateUpdate(msg.value);
600
603
  }
601
- } else if (msg.$case === 'subscribedQualityUpdate') {
604
+ } else if (msg.case === 'subscribedQualityUpdate') {
602
605
  if (this.onSubscribedQualityUpdate) {
603
- this.onSubscribedQualityUpdate(msg.subscribedQualityUpdate);
606
+ this.onSubscribedQualityUpdate(msg.value);
604
607
  }
605
- } else if (msg.$case === 'subscriptionPermissionUpdate') {
608
+ } else if (msg.case === 'subscriptionPermissionUpdate') {
606
609
  if (this.onSubscriptionPermissionUpdate) {
607
- this.onSubscriptionPermissionUpdate(msg.subscriptionPermissionUpdate);
610
+ this.onSubscriptionPermissionUpdate(msg.value);
608
611
  }
609
- } else if (msg.$case === 'refreshToken') {
612
+ } else if (msg.case === 'refreshToken') {
610
613
  if (this.onTokenRefresh) {
611
- this.onTokenRefresh(msg.refreshToken);
614
+ this.onTokenRefresh(msg.value);
612
615
  }
613
- } else if (msg.$case === 'trackUnpublished') {
616
+ } else if (msg.case === 'trackUnpublished') {
614
617
  if (this.onLocalTrackUnpublished) {
615
- this.onLocalTrackUnpublished(msg.trackUnpublished);
618
+ this.onLocalTrackUnpublished(msg.value);
616
619
  }
617
- } else if (msg.$case === 'subscriptionResponse') {
620
+ } else if (msg.case === 'subscriptionResponse') {
618
621
  if (this.onSubscriptionError) {
619
- this.onSubscriptionError(msg.subscriptionResponse);
622
+ this.onSubscriptionError(msg.value);
620
623
  }
621
- } else if (msg.$case === 'pong') {
624
+ } else if (msg.case === 'pong') {
622
625
  this.resetPingTimeout();
623
- } else if (msg.$case === 'pongResp') {
624
- this.rtt = Date.now() - msg.pongResp.lastPingTimestamp;
626
+ } else if (msg.case === 'pongResp') {
627
+ this.rtt = Date.now() - Number.parseInt(msg.value.lastPingTimestamp.toString());
625
628
  this.resetPingTimeout();
626
629
  } else {
627
630
  log.debug('unsupported message', msg);
@@ -724,10 +727,10 @@ function fromProtoSessionDescription(sd: SessionDescription): RTCSessionDescript
724
727
  export function toProtoSessionDescription(
725
728
  rsd: RTCSessionDescription | RTCSessionDescriptionInit,
726
729
  ): SessionDescription {
727
- const sd: SessionDescription = {
730
+ const sd = new SessionDescription({
728
731
  sdp: rsd.sdp!,
729
732
  type: rsd.type!,
730
- };
733
+ });
731
734
  return sd;
732
735
  }
733
736
 
@@ -1,4 +1,5 @@
1
- import EventEmitter from 'eventemitter3';
1
+ import { EventEmitter } from 'events';
2
+ import type TypedEmitter from 'typed-emitter';
2
3
  import { CheckStatus, Checker } from './checks/Checker';
3
4
  import type { CheckInfo, InstantiableCheck } from './checks/Checker';
4
5
  import { PublishAudioCheck } from './checks/publishAudio';
@@ -10,7 +11,7 @@ import { WebSocketCheck } from './checks/websocket';
10
11
 
11
12
  export type { CheckInfo, CheckStatus };
12
13
 
13
- export class ConnectionCheck extends EventEmitter<ConnectionCheckCallbacks> {
14
+ export class ConnectionCheck extends (EventEmitter as new () => TypedEmitter<ConnectionCheckCallbacks>) {
14
15
  token: string;
15
16
 
16
17
  url: string;
@@ -1,4 +1,5 @@
1
- import EventEmitter from 'eventemitter3';
1
+ import { EventEmitter } from 'events';
2
+ import type TypedEmitter from 'typed-emitter';
2
3
  import type { RoomConnectOptions, RoomOptions } from '../../options';
3
4
  import type RTCEngine from '../../room/RTCEngine';
4
5
  import Room, { ConnectionState } from '../../room/Room';
@@ -29,7 +30,7 @@ export interface CheckerOptions {
29
30
  connectOptions?: RoomConnectOptions;
30
31
  }
31
32
 
32
- export abstract class Checker extends EventEmitter<CheckerCallbacks> {
33
+ export abstract class Checker extends (EventEmitter as new () => TypedEmitter<CheckerCallbacks>) {
33
34
  protected url: string;
34
35
 
35
36
  protected token: string;
@@ -67,7 +68,6 @@ export abstract class Checker extends EventEmitter<CheckerCallbacks> {
67
68
  throw Error('check is running already');
68
69
  }
69
70
  this.setStatus(CheckStatus.RUNNING);
70
- this.appendMessage(`${this.name} started.`);
71
71
 
72
72
  try {
73
73
  await this.perform();
@@ -1,3 +1,4 @@
1
+ import { RoomEvent } from '../../room/events';
1
2
  import { Checker } from './Checker';
2
3
 
3
4
  export class WebRTCCheck extends Checker {
@@ -6,13 +7,76 @@ export class WebRTCCheck extends Checker {
6
7
  }
7
8
 
8
9
  protected async perform(): Promise<void> {
10
+ let hasTcp = false;
11
+ let hasIpv4Udp = false;
12
+ this.room.on(RoomEvent.SignalConnected, () => {
13
+ const prevTrickle = this.room.engine.client.onTrickle;
14
+
15
+ const candidates: RTCIceCandidate[] = [];
16
+ this.room.engine.client.onTrickle = (sd, target) => {
17
+ console.log('got candidate', sd);
18
+ if (sd.candidate) {
19
+ const candidate = new RTCIceCandidate(sd);
20
+ candidates.push(candidate);
21
+ let str = `${candidate.protocol} ${candidate.address}:${candidate.port} ${candidate.type}`;
22
+ if (candidate.protocol === 'tcp' && candidate.tcpType === 'passive') {
23
+ hasTcp = true;
24
+ str += ' (active)';
25
+ } else if (candidate.protocol === 'udp' && candidate.address) {
26
+ if (isIPPrivate(candidate.address)) {
27
+ str += ' (private)';
28
+ } else {
29
+ hasIpv4Udp = true;
30
+ }
31
+ }
32
+ this.appendMessage(str);
33
+ }
34
+ if (prevTrickle) {
35
+ prevTrickle(sd, target);
36
+ }
37
+ };
38
+
39
+ if (this.room.engine.subscriber) {
40
+ this.room.engine.subscriber.pc.onicecandidateerror = (ev) => {
41
+ if (ev instanceof RTCPeerConnectionIceErrorEvent) {
42
+ this.appendWarning(
43
+ `error with ICE candidate: ${ev.errorCode} ${ev.errorText} ${ev.url}`,
44
+ );
45
+ }
46
+ };
47
+ }
48
+ });
9
49
  try {
10
- console.log('initiating room connection');
11
- this.room = await this.connect();
50
+ await this.connect();
12
51
  console.log('now the room is connected');
13
52
  } catch (err) {
14
53
  this.appendWarning('ports need to be open on firewall in order to connect.');
15
54
  throw err;
16
55
  }
56
+ if (!hasTcp) {
57
+ this.appendWarning('Server is not configured for ICE/TCP');
58
+ }
59
+ if (!hasIpv4Udp) {
60
+ this.appendWarning(
61
+ 'No public IPv4 UDP candidates were found. Your server is likely not configured correctly',
62
+ );
63
+ }
64
+ }
65
+ }
66
+
67
+ function isIPPrivate(address: string): boolean {
68
+ const parts = address.split('.');
69
+ if (parts.length === 4) {
70
+ if (parts[0] === '10') {
71
+ return true;
72
+ } else if (parts[0] === '192' && parts[1] === '168') {
73
+ return true;
74
+ } else if (parts[0] === '172') {
75
+ const second = parseInt(parts[1], 10);
76
+ if (second >= 16 && second <= 31) {
77
+ return true;
78
+ }
79
+ }
17
80
  }
81
+ return false;
18
82
  }
@@ -1,4 +1,5 @@
1
1
  import { SignalClient } from '../../api/SignalClient';
2
+ import { ServerInfo_Edition } from '../../proto/livekit_models_pb';
2
3
  import { Checker } from './Checker';
3
4
 
4
5
  export class WebSocketCheck extends Checker {
@@ -18,6 +19,9 @@ export class WebSocketCheck extends Checker {
18
19
  e2eeEnabled: false,
19
20
  });
20
21
  this.appendMessage(`Connected to server, version ${joinRes.serverVersion}.`);
22
+ if (joinRes.serverInfo?.edition === ServerInfo_Edition.Cloud && joinRes.serverInfo?.region) {
23
+ this.appendMessage(`LiveKit Cloud: ${joinRes.serverInfo?.region}`);
24
+ }
21
25
  await signalClient.close();
22
26
  }
23
27
  }
@@ -1,6 +1,7 @@
1
- import EventEmitter from 'eventemitter3';
1
+ import { EventEmitter } from 'events';
2
+ import type TypedEventEmitter from 'typed-emitter';
2
3
  import log from '../logger';
3
- import { Encryption_Type, TrackInfo } from '../proto/livekit_models';
4
+ import { Encryption_Type, TrackInfo } from '../proto/livekit_models_pb';
4
5
  import type RTCEngine from '../room/RTCEngine';
5
6
  import type Room from '../room/Room';
6
7
  import { ConnectionState } from '../room/Room';
@@ -32,7 +33,7 @@ import { isE2EESupported, isScriptTransformSupported, mimeTypeToVideoCodecString
32
33
  /**
33
34
  * @experimental
34
35
  */
35
- export class E2EEManager extends EventEmitter<E2EEManagerCallbacks> {
36
+ export class E2EEManager extends (EventEmitter as new () => TypedEventEmitter<E2EEManagerCallbacks>) {
36
37
  protected worker: Worker;
37
38
 
38
39
  protected room?: Room;
@@ -1,4 +1,5 @@
1
- import EventEmitter from 'eventemitter3';
1
+ import { EventEmitter } from 'events';
2
+ import type TypedEventEmitter from 'typed-emitter';
2
3
  import { KEY_PROVIDER_DEFAULTS } from './constants';
3
4
  import type { KeyInfo, KeyProviderCallbacks, KeyProviderOptions } from './types';
4
5
  import { createKeyMaterialFromString } from './utils';
@@ -6,7 +7,7 @@ import { createKeyMaterialFromString } from './utils';
6
7
  /**
7
8
  * @experimental
8
9
  */
9
- export class BaseKeyProvider extends EventEmitter<KeyProviderCallbacks> {
10
+ export class BaseKeyProvider extends (EventEmitter as new () => TypedEventEmitter<KeyProviderCallbacks>) {
10
11
  private keyInfoMap: Map<string, KeyInfo>;
11
12
 
12
13
  private options: KeyProviderOptions;
@@ -7,6 +7,9 @@ export const ENCRYPTION_ALGORITHM = 'AES-GCM';
7
7
  // in the frame trailer.
8
8
  export const KEYRING_SIZE = 16;
9
9
 
10
+ // How many consecutive frames can fail decrypting before a particular key gets marked as invalid
11
+ export const DECRYPTION_FAILURE_TOLERANCE = 10;
12
+
10
13
  // We copy the first bytes of the VP8 payload unencrypted.
11
14
  // For keyframes this is 10 bytes, for non-keyframes (delta) 3. See
12
15
  // https://tools.ietf.org/html/rfc6386#section-9.1
@@ -37,4 +40,5 @@ export const KEY_PROVIDER_DEFAULTS: KeyProviderOptions = {
37
40
  sharedKey: false,
38
41
  ratchetSalt: SALT,
39
42
  ratchetWindowSize: 8,
43
+ failureTolerance: DECRYPTION_FAILURE_TOLERANCE,
40
44
  } as const;
package/src/e2ee/types.ts CHANGED
@@ -110,6 +110,7 @@ export type KeyProviderOptions = {
110
110
  sharedKey: boolean;
111
111
  ratchetSalt: string;
112
112
  ratchetWindowSize: number;
113
+ failureTolerance: number;
113
114
  };
114
115
 
115
116
  export type KeyProviderCallbacks = {
@@ -1,6 +1,4 @@
1
- /**
2
- * @jest-environment node
3
- */
1
+ import { describe, expect, it } from 'vitest';
4
2
  import { isFrameServerInjected } from './FrameCryptor';
5
3
 
6
4
  describe('FrameCryptor', () => {