@livekit/rtc-node 0.13.22 → 0.13.24

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 (124) hide show
  1. package/dist/audio_frame.cjs +6 -1
  2. package/dist/audio_frame.cjs.map +1 -1
  3. package/dist/audio_frame.d.cts +4 -1
  4. package/dist/audio_frame.d.ts +4 -1
  5. package/dist/audio_frame.d.ts.map +1 -1
  6. package/dist/audio_frame.js +6 -1
  7. package/dist/audio_frame.js.map +1 -1
  8. package/dist/audio_mixer.cjs +11 -4
  9. package/dist/audio_mixer.cjs.map +1 -1
  10. package/dist/audio_mixer.d.ts.map +1 -1
  11. package/dist/audio_mixer.js +11 -4
  12. package/dist/audio_mixer.js.map +1 -1
  13. package/dist/audio_stream.cjs +20 -5
  14. package/dist/audio_stream.cjs.map +1 -1
  15. package/dist/audio_stream.d.cts +4 -3
  16. package/dist/audio_stream.d.ts +4 -3
  17. package/dist/audio_stream.d.ts.map +1 -1
  18. package/dist/audio_stream.js +20 -5
  19. package/dist/audio_stream.js.map +1 -1
  20. package/dist/data_streams/stream_reader.cjs.map +1 -1
  21. package/dist/data_streams/stream_reader.js.map +1 -1
  22. package/dist/frame_processor.cjs +38 -0
  23. package/dist/frame_processor.cjs.map +1 -0
  24. package/dist/frame_processor.d.cts +29 -0
  25. package/dist/frame_processor.d.ts +29 -0
  26. package/dist/frame_processor.d.ts.map +1 -0
  27. package/dist/frame_processor.js +14 -0
  28. package/dist/frame_processor.js.map +1 -0
  29. package/dist/index.cjs +3 -0
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +1 -0
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +4 -0
  35. package/dist/index.js.map +1 -1
  36. package/dist/log.cjs +1 -10
  37. package/dist/log.cjs.map +1 -1
  38. package/dist/log.d.cts +4 -0
  39. package/dist/log.d.ts +4 -0
  40. package/dist/log.d.ts.map +1 -1
  41. package/dist/log.js +1 -10
  42. package/dist/log.js.map +1 -1
  43. package/dist/proto/audio_frame_pb.cjs.map +1 -1
  44. package/dist/proto/audio_frame_pb.js.map +1 -1
  45. package/dist/proto/e2ee_pb.cjs.map +1 -1
  46. package/dist/proto/e2ee_pb.js.map +1 -1
  47. package/dist/proto/ffi_pb.cjs +4 -2
  48. package/dist/proto/ffi_pb.cjs.map +1 -1
  49. package/dist/proto/ffi_pb.d.cts +13 -1
  50. package/dist/proto/ffi_pb.d.ts +13 -1
  51. package/dist/proto/ffi_pb.d.ts.map +1 -1
  52. package/dist/proto/ffi_pb.js +5 -3
  53. package/dist/proto/ffi_pb.js.map +1 -1
  54. package/dist/proto/handle_pb.cjs.map +1 -1
  55. package/dist/proto/handle_pb.js.map +1 -1
  56. package/dist/proto/participant_pb.cjs +26 -4
  57. package/dist/proto/participant_pb.cjs.map +1 -1
  58. package/dist/proto/participant_pb.d.cts +31 -2
  59. package/dist/proto/participant_pb.d.ts +31 -2
  60. package/dist/proto/participant_pb.d.ts.map +1 -1
  61. package/dist/proto/participant_pb.js +24 -3
  62. package/dist/proto/participant_pb.js.map +1 -1
  63. package/dist/proto/room_pb.cjs +29 -2
  64. package/dist/proto/room_pb.cjs.map +1 -1
  65. package/dist/proto/room_pb.d.cts +30 -7
  66. package/dist/proto/room_pb.d.ts +30 -7
  67. package/dist/proto/room_pb.d.ts.map +1 -1
  68. package/dist/proto/room_pb.js +28 -2
  69. package/dist/proto/room_pb.js.map +1 -1
  70. package/dist/proto/rpc_pb.cjs.map +1 -1
  71. package/dist/proto/rpc_pb.js.map +1 -1
  72. package/dist/proto/stats_pb.cjs.map +1 -1
  73. package/dist/proto/stats_pb.js.map +1 -1
  74. package/dist/proto/track_pb.cjs.map +1 -1
  75. package/dist/proto/track_pb.js.map +1 -1
  76. package/dist/proto/track_publication_pb.cjs +66 -2
  77. package/dist/proto/track_publication_pb.cjs.map +1 -1
  78. package/dist/proto/track_publication_pb.d.cts +56 -1
  79. package/dist/proto/track_publication_pb.d.ts +56 -1
  80. package/dist/proto/track_publication_pb.d.ts.map +1 -1
  81. package/dist/proto/track_publication_pb.js +62 -1
  82. package/dist/proto/track_publication_pb.js.map +1 -1
  83. package/dist/proto/video_frame_pb.cjs +3 -1
  84. package/dist/proto/video_frame_pb.cjs.map +1 -1
  85. package/dist/proto/video_frame_pb.d.cts +5 -1
  86. package/dist/proto/video_frame_pb.d.ts +5 -1
  87. package/dist/proto/video_frame_pb.d.ts.map +1 -1
  88. package/dist/proto/video_frame_pb.js +3 -1
  89. package/dist/proto/video_frame_pb.js.map +1 -1
  90. package/dist/room.cjs +44 -26
  91. package/dist/room.cjs.map +1 -1
  92. package/dist/room.d.cts +19 -11
  93. package/dist/room.d.ts +19 -11
  94. package/dist/room.d.ts.map +1 -1
  95. package/dist/room.js +45 -27
  96. package/dist/room.js.map +1 -1
  97. package/dist/version.cjs +1 -1
  98. package/dist/version.cjs.map +1 -1
  99. package/dist/version.d.cts +1 -1
  100. package/dist/version.d.ts +1 -1
  101. package/dist/version.js +1 -1
  102. package/dist/version.js.map +1 -1
  103. package/package.json +11 -7
  104. package/src/audio_frame.ts +15 -1
  105. package/src/audio_mixer.ts +15 -4
  106. package/src/audio_stream.ts +23 -7
  107. package/src/data_streams/stream_reader.ts +4 -4
  108. package/src/frame_processor.ts +29 -0
  109. package/src/index.ts +5 -0
  110. package/src/log.ts +14 -10
  111. package/src/proto/audio_frame_pb.ts +1 -1
  112. package/src/proto/e2ee_pb.ts +1 -1
  113. package/src/proto/ffi_pb.ts +16 -2
  114. package/src/proto/handle_pb.ts +1 -1
  115. package/src/proto/participant_pb.ts +45 -1
  116. package/src/proto/room_pb.ts +52 -8
  117. package/src/proto/rpc_pb.ts +1 -1
  118. package/src/proto/stats_pb.ts +1 -1
  119. package/src/proto/track_pb.ts +1 -1
  120. package/src/proto/track_publication_pb.ts +105 -1
  121. package/src/proto/video_frame_pb.ts +7 -1
  122. package/src/room.ts +65 -38
  123. package/src/tests/e2e.test.ts +514 -0
  124. package/src/version.ts +1 -1
@@ -3,6 +3,7 @@
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  import { AsyncQueue } from './async_queue.js';
5
5
  import { AudioFrame } from './audio_frame.js';
6
+ import { log } from './log.js';
6
7
 
7
8
  // Re-export AsyncQueue for backward compatibility
8
9
  export { AsyncQueue } from './async_queue.js';
@@ -238,7 +239,7 @@ export class AudioMixer {
238
239
 
239
240
  for (const result of results) {
240
241
  if (result.status !== 'fulfilled') {
241
- console.warn('AudioMixer: Stream contribution failed:', result.reason);
242
+ log.warn('AudioMixer: Stream contribution failed:', result.reason);
242
243
  continue;
243
244
  }
244
245
 
@@ -261,6 +262,12 @@ export class AudioMixer {
261
262
  this.removeStream(stream);
262
263
  }
263
264
 
265
+ // If all streams are exhausted, end the mixer automatically.
266
+ // This keeps `for await...of` consumers from hanging indefinitely when inputs complete.
267
+ if (!this.ending && removals.length > 0 && this.streams.size === 0) {
268
+ this.ending = true;
269
+ }
270
+
264
271
  if (!anyData) {
265
272
  // No data available from any stream, wait briefly before trying again
266
273
  await this.sleep(1);
@@ -372,25 +379,29 @@ export class AudioMixer {
372
379
  }
373
380
 
374
381
  const length = this.chunkSize * this.numChannels;
375
- const mixed = new Int16Array(length);
382
+ // Use a wider accumulator to avoid int16 overflow while summing.
383
+ const acc = new Int32Array(length);
376
384
 
377
385
  // Sum all contributions
378
386
  for (const contrib of contributions) {
379
387
  for (let i = 0; i < length; i++) {
380
388
  const val = contrib[i];
381
389
  if (val !== undefined) {
382
- mixed[i] = (mixed[i] ?? 0) + val;
390
+ acc[i] = (acc[i] ?? 0) + val;
383
391
  }
384
392
  }
385
393
  }
386
394
 
387
395
  // Clip to Int16 range
396
+ const mixed = new Int16Array(length);
388
397
  for (let i = 0; i < length; i++) {
389
- const val = mixed[i] ?? 0;
398
+ const val = acc[i] ?? 0;
390
399
  if (val > 32767) {
391
400
  mixed[i] = 32767;
392
401
  } else if (val < -32768) {
393
402
  mixed[i] = -32768;
403
+ } else {
404
+ mixed[i] = val;
394
405
  }
395
406
  }
396
407
 
@@ -5,12 +5,14 @@ import type { UnderlyingSource } from 'node:stream/web';
5
5
  import { AudioFrame } from './audio_frame.js';
6
6
  import type { FfiEvent } from './ffi_client.js';
7
7
  import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js';
8
+ import { FrameProcessor } from './frame_processor.js';
9
+ import { log } from './log.js';
8
10
  import type { NewAudioStreamResponse } from './proto/audio_frame_pb.js';
9
11
  import { AudioStreamType, NewAudioStreamRequest } from './proto/audio_frame_pb.js';
10
12
  import type { Track } from './track.js';
11
13
 
12
14
  export interface AudioStreamOptions {
13
- noiseCancellation?: NoiseCancellationOptions;
15
+ noiseCancellation?: NoiseCancellationOptions | FrameProcessor<AudioFrame>;
14
16
  sampleRate?: number;
15
17
  numChannels?: number;
16
18
  frameSizeMs?: number;
@@ -18,6 +20,7 @@ export interface AudioStreamOptions {
18
20
 
19
21
  export interface NoiseCancellationOptions {
20
22
  moduleId: string;
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
24
  options: Record<string, any>;
22
25
  }
23
26
 
@@ -26,7 +29,8 @@ class AudioStreamSource implements UnderlyingSource<AudioFrame> {
26
29
  private ffiHandle: FfiHandle;
27
30
  private sampleRate: number;
28
31
  private numChannels: number;
29
- private ncOptions?: NoiseCancellationOptions;
32
+ private legacyNcOptions?: NoiseCancellationOptions;
33
+ private frameProcessor?: FrameProcessor<AudioFrame>;
30
34
  private frameSizeMs?: number;
31
35
 
32
36
  constructor(
@@ -37,7 +41,11 @@ class AudioStreamSource implements UnderlyingSource<AudioFrame> {
37
41
  if (sampleRateOrOptions !== undefined && typeof sampleRateOrOptions !== 'number') {
38
42
  this.sampleRate = sampleRateOrOptions.sampleRate ?? 48000;
39
43
  this.numChannels = sampleRateOrOptions.numChannels ?? 1;
40
- this.ncOptions = sampleRateOrOptions.noiseCancellation;
44
+ if (sampleRateOrOptions.noiseCancellation instanceof FrameProcessor) {
45
+ this.frameProcessor = sampleRateOrOptions.noiseCancellation;
46
+ } else {
47
+ this.legacyNcOptions = sampleRateOrOptions.noiseCancellation;
48
+ }
41
49
  this.frameSizeMs = sampleRateOrOptions.frameSizeMs;
42
50
  } else {
43
51
  this.sampleRate = (sampleRateOrOptions as number) ?? 48000;
@@ -50,10 +58,10 @@ class AudioStreamSource implements UnderlyingSource<AudioFrame> {
50
58
  sampleRate: this.sampleRate,
51
59
  numChannels: this.numChannels,
52
60
  frameSizeMs: this.frameSizeMs,
53
- ...(this.ncOptions
61
+ ...(this.legacyNcOptions
54
62
  ? {
55
- audioFilterModuleId: this.ncOptions.moduleId,
56
- audioFilterOptions: JSON.stringify(this.ncOptions.options),
63
+ audioFilterModuleId: this.legacyNcOptions.moduleId,
64
+ audioFilterOptions: JSON.stringify(this.legacyNcOptions.options),
57
65
  }
58
66
  : {}),
59
67
  });
@@ -85,12 +93,20 @@ class AudioStreamSource implements UnderlyingSource<AudioFrame> {
85
93
  const streamEvent = ev.message.value.message;
86
94
  switch (streamEvent.case) {
87
95
  case 'frameReceived':
88
- const frame = AudioFrame.fromOwnedInfo(streamEvent.value.frame!);
96
+ let frame = AudioFrame.fromOwnedInfo(streamEvent.value.frame!);
97
+ if (this.frameProcessor && this.frameProcessor.isEnabled()) {
98
+ try {
99
+ frame = this.frameProcessor.process(frame);
100
+ } catch (err: unknown) {
101
+ log.warn(`Frame processing failed, passing through original frame: ${err}`);
102
+ }
103
+ }
89
104
  this.controller.enqueue(frame);
90
105
  break;
91
106
  case 'eos':
92
107
  FfiClient.instance.off(FfiClientEvent.FfiEvent, this.onEvent);
93
108
  this.controller.close();
109
+ this.frameProcessor?.close();
94
110
  break;
95
111
  }
96
112
  };
@@ -53,14 +53,14 @@ export class ByteStreamReader extends BaseStreamReader<ByteStreamInfo> {
53
53
  try {
54
54
  const { done, value } = await reader.read();
55
55
  if (done) {
56
- return { done: true, value: undefined as any };
56
+ return { done: true, value: undefined as unknown };
57
57
  } else {
58
58
  this.handleChunkReceived(value);
59
59
  return { done: false, value: value.content! };
60
60
  }
61
- } catch (error: any) {
61
+ } catch (error: unknown) {
62
62
  log.error('error processing stream update: %s', error);
63
- return { done: true, value: undefined };
63
+ return { done: true, value: undefined as unknown };
64
64
  }
65
65
  },
66
66
 
@@ -135,7 +135,7 @@ export class TextStreamReader extends BaseStreamReader<TextStreamInfo> {
135
135
  value: decoder.decode(value.content!),
136
136
  };
137
137
  }
138
- } catch (error: any) {
138
+ } catch (error: unknown) {
139
139
  log.error('error processing stream update: %s', error);
140
140
  return { done: true, value: undefined };
141
141
  }
@@ -0,0 +1,29 @@
1
+ // SPDX-FileCopyrightText: 2025 LiveKit, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { type AudioFrame } from './audio_frame.js';
5
+ import { type VideoFrame } from './video_frame.js';
6
+
7
+ export type FrameProcessorStreamInfo = {
8
+ roomName: string;
9
+ participantIdentity: string;
10
+ publicationSid: string;
11
+ };
12
+
13
+ export type FrameProcessorCredentials = {
14
+ token: string;
15
+ url: string;
16
+ };
17
+
18
+ export abstract class FrameProcessor<Frame extends VideoFrame | AudioFrame> {
19
+ abstract isEnabled(): boolean;
20
+ abstract setEnabled(enabled: boolean): void;
21
+
22
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
23
+ onStreamInfoUpdated(_info: FrameProcessorStreamInfo): void {}
24
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
25
+ onCredentialsUpdated(_credentials: FrameProcessorCredentials): void {}
26
+
27
+ abstract process(frame: Frame): Frame;
28
+ abstract close(): void;
29
+ }
package/src/index.ts CHANGED
@@ -50,3 +50,8 @@ export type { ChatMessage } from './types.js';
50
50
  export { VideoFrame } from './video_frame.js';
51
51
  export { VideoSource } from './video_source.js';
52
52
  export { VideoStream, type VideoFrameEvent } from './video_stream.js';
53
+ export {
54
+ FrameProcessor,
55
+ type FrameProcessorStreamInfo,
56
+ type FrameProcessorCredentials,
57
+ } from './frame_processor.js';
package/src/log.ts CHANGED
@@ -8,17 +8,21 @@ const isProduction = process.env.NODE_ENV === 'production';
8
8
 
9
9
  const defaultOptions: LoggerOptions = { name: 'lk-rtc' };
10
10
 
11
- const devOptions: LoggerOptions = {
12
- ...defaultOptions,
13
- transport: {
14
- target: 'pino-pretty',
15
- options: {
16
- colorize: true,
17
- },
18
- },
19
- };
11
+ /**
12
+ * temporarily disabling the transport option as there might be a memory leak in some corner cases related to it
13
+ * see https://github.com/pinojs/pino/issues/2370
14
+ */
15
+ // const devOptions: LoggerOptions = {
16
+ // ...defaultOptions,
17
+ // transport: {
18
+ // target: 'pino-pretty',
19
+ // options: {
20
+ // colorize: true,
21
+ // },
22
+ // },
23
+ // };
20
24
 
21
- const log = pino(isProduction ? defaultOptions : devOptions);
25
+ const log = pino(defaultOptions);
22
26
  log.level = isProduction ? 'info' : 'debug';
23
27
 
24
28
  export type LogLevel = LevelWithSilent;
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ import { CaptureVideoFrameRequest, CaptureVideoFrameResponse, NewVideoSourceRequ
25
25
  import { ApmProcessReverseStreamRequest, ApmProcessReverseStreamResponse, ApmProcessStreamRequest, ApmProcessStreamResponse, ApmSetStreamDelayRequest, ApmSetStreamDelayResponse, AudioStreamEvent, AudioStreamFromParticipantRequest, AudioStreamFromParticipantResponse, CaptureAudioFrameCallback, CaptureAudioFrameRequest, CaptureAudioFrameResponse, ClearAudioBufferRequest, ClearAudioBufferResponse, FlushSoxResamplerRequest, FlushSoxResamplerResponse, LoadAudioFilterPluginRequest, LoadAudioFilterPluginResponse, NewApmRequest, NewApmResponse, NewAudioResamplerRequest, NewAudioResamplerResponse, NewAudioSourceRequest, NewAudioSourceResponse, NewAudioStreamRequest, NewAudioStreamResponse, NewSoxResamplerRequest, NewSoxResamplerResponse, PushSoxResamplerRequest, PushSoxResamplerResponse, RemixAndResampleRequest, RemixAndResampleResponse } from "./audio_frame_pb.js";
26
26
  import { E2eeRequest, E2eeResponse } from "./e2ee_pb.js";
27
27
  import { PerformRpcCallback, PerformRpcRequest, PerformRpcResponse, RegisterRpcMethodRequest, RegisterRpcMethodResponse, RpcMethodInvocationEvent, RpcMethodInvocationResponseRequest, RpcMethodInvocationResponseResponse, UnregisterRpcMethodRequest, UnregisterRpcMethodResponse } from "./rpc_pb.js";
28
- import { EnableRemoteTrackPublicationRequest, EnableRemoteTrackPublicationResponse, UpdateRemoteTrackPublicationDimensionRequest, UpdateRemoteTrackPublicationDimensionResponse } from "./track_publication_pb.js";
28
+ import { EnableRemoteTrackPublicationRequest, EnableRemoteTrackPublicationResponse, SetRemoteTrackPublicationQualityRequest, SetRemoteTrackPublicationQualityResponse, UpdateRemoteTrackPublicationDimensionRequest, UpdateRemoteTrackPublicationDimensionResponse } from "./track_publication_pb.js";
29
29
  import { ByteStreamOpenCallback, ByteStreamOpenRequest, ByteStreamOpenResponse, ByteStreamReaderEvent, ByteStreamReaderReadAllCallback, ByteStreamReaderReadAllRequest, ByteStreamReaderReadAllResponse, ByteStreamReaderReadIncrementalRequest, ByteStreamReaderReadIncrementalResponse, ByteStreamReaderWriteToFileCallback, ByteStreamReaderWriteToFileRequest, ByteStreamReaderWriteToFileResponse, ByteStreamWriterCloseCallback, ByteStreamWriterCloseRequest, ByteStreamWriterCloseResponse, ByteStreamWriterWriteCallback, ByteStreamWriterWriteRequest, ByteStreamWriterWriteResponse, StreamSendBytesCallback, StreamSendBytesRequest, StreamSendBytesResponse, StreamSendFileCallback, StreamSendFileRequest, StreamSendFileResponse, StreamSendTextCallback, StreamSendTextRequest, StreamSendTextResponse, TextStreamOpenCallback, TextStreamOpenRequest, TextStreamOpenResponse, TextStreamReaderEvent, TextStreamReaderReadAllCallback, TextStreamReaderReadAllRequest, TextStreamReaderReadAllResponse, TextStreamReaderReadIncrementalRequest, TextStreamReaderReadIncrementalResponse, TextStreamWriterCloseCallback, TextStreamWriterCloseRequest, TextStreamWriterCloseResponse, TextStreamWriterWriteCallback, TextStreamWriterWriteRequest, TextStreamWriterWriteResponse } from "./data_stream_pb.js";
30
30
 
31
31
  /**
@@ -492,6 +492,12 @@ export class FfiRequest extends Message<FfiRequest> {
492
492
  */
493
493
  value: StreamSendBytesRequest;
494
494
  case: "sendBytes";
495
+ } | {
496
+ /**
497
+ * @generated from field: livekit.proto.SetRemoteTrackPublicationQualityRequest set_remote_track_publication_quality = 68;
498
+ */
499
+ value: SetRemoteTrackPublicationQualityRequest;
500
+ case: "setRemoteTrackPublicationQuality";
495
501
  } | { case: undefined; value?: undefined } = { case: undefined };
496
502
 
497
503
  constructor(data?: PartialMessage<FfiRequest>) {
@@ -568,6 +574,7 @@ export class FfiRequest extends Message<FfiRequest> {
568
574
  { no: 65, name: "text_stream_write", kind: "message", T: TextStreamWriterWriteRequest, oneof: "message" },
569
575
  { no: 66, name: "text_stream_close", kind: "message", T: TextStreamWriterCloseRequest, oneof: "message" },
570
576
  { no: 67, name: "send_bytes", kind: "message", T: StreamSendBytesRequest, oneof: "message" },
577
+ { no: 68, name: "set_remote_track_publication_quality", kind: "message", T: SetRemoteTrackPublicationQualityRequest, oneof: "message" },
571
578
  ]);
572
579
 
573
580
  static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): FfiRequest {
@@ -1006,6 +1013,12 @@ export class FfiResponse extends Message<FfiResponse> {
1006
1013
  */
1007
1014
  value: StreamSendBytesResponse;
1008
1015
  case: "sendBytes";
1016
+ } | {
1017
+ /**
1018
+ * @generated from field: livekit.proto.SetRemoteTrackPublicationQualityResponse set_remote_track_publication_quality = 67;
1019
+ */
1020
+ value: SetRemoteTrackPublicationQualityResponse;
1021
+ case: "setRemoteTrackPublicationQuality";
1009
1022
  } | { case: undefined; value?: undefined } = { case: undefined };
1010
1023
 
1011
1024
  constructor(data?: PartialMessage<FfiResponse>) {
@@ -1081,6 +1094,7 @@ export class FfiResponse extends Message<FfiResponse> {
1081
1094
  { no: 64, name: "text_stream_write", kind: "message", T: TextStreamWriterWriteResponse, oneof: "message" },
1082
1095
  { no: 65, name: "text_stream_close", kind: "message", T: TextStreamWriterCloseResponse, oneof: "message" },
1083
1096
  { no: 66, name: "send_bytes", kind: "message", T: StreamSendBytesResponse, oneof: "message" },
1097
+ { no: 67, name: "set_remote_track_publication_quality", kind: "message", T: SetRemoteTrackPublicationQualityResponse, oneof: "message" },
1084
1098
  ]);
1085
1099
 
1086
1100
  static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): FfiResponse {
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -49,6 +49,11 @@ export enum ParticipantKind {
49
49
  * @generated from enum value: PARTICIPANT_KIND_AGENT = 4;
50
50
  */
51
51
  AGENT = 4,
52
+
53
+ /**
54
+ * @generated from enum value: PARTICIPANT_KIND_CONNECTOR = 5;
55
+ */
56
+ CONNECTOR = 5,
52
57
  }
53
58
  // Retrieve enum metadata with: proto2.getEnumType(ParticipantKind)
54
59
  proto2.util.setEnumType(ParticipantKind, "livekit.proto.ParticipantKind", [
@@ -57,6 +62,39 @@ proto2.util.setEnumType(ParticipantKind, "livekit.proto.ParticipantKind", [
57
62
  { no: 2, name: "PARTICIPANT_KIND_EGRESS" },
58
63
  { no: 3, name: "PARTICIPANT_KIND_SIP" },
59
64
  { no: 4, name: "PARTICIPANT_KIND_AGENT" },
65
+ { no: 5, name: "PARTICIPANT_KIND_CONNECTOR" },
66
+ ]);
67
+
68
+ /**
69
+ * @generated from enum livekit.proto.ParticipantKindDetail
70
+ */
71
+ export enum ParticipantKindDetail {
72
+ /**
73
+ * @generated from enum value: PARTICIPANT_KIND_DETAIL_CLOUD_AGENT = 0;
74
+ */
75
+ CLOUD_AGENT = 0,
76
+
77
+ /**
78
+ * @generated from enum value: PARTICIPANT_KIND_DETAIL_FORWARDED = 1;
79
+ */
80
+ FORWARDED = 1,
81
+
82
+ /**
83
+ * @generated from enum value: PARTICIPANT_KIND_DETAIL_CONNECTOR_WHATSAPP = 2;
84
+ */
85
+ CONNECTOR_WHATSAPP = 2,
86
+
87
+ /**
88
+ * @generated from enum value: PARTICIPANT_KIND_DETAIL_CONNECTOR_TWILIO = 3;
89
+ */
90
+ CONNECTOR_TWILIO = 3,
91
+ }
92
+ // Retrieve enum metadata with: proto2.getEnumType(ParticipantKindDetail)
93
+ proto2.util.setEnumType(ParticipantKindDetail, "livekit.proto.ParticipantKindDetail", [
94
+ { no: 0, name: "PARTICIPANT_KIND_DETAIL_CLOUD_AGENT" },
95
+ { no: 1, name: "PARTICIPANT_KIND_DETAIL_FORWARDED" },
96
+ { no: 2, name: "PARTICIPANT_KIND_DETAIL_CONNECTOR_WHATSAPP" },
97
+ { no: 3, name: "PARTICIPANT_KIND_DETAIL_CONNECTOR_TWILIO" },
60
98
  ]);
61
99
 
62
100
  /**
@@ -228,6 +266,11 @@ export class ParticipantInfo extends Message<ParticipantInfo> {
228
266
  */
229
267
  disconnectReason?: DisconnectReason;
230
268
 
269
+ /**
270
+ * @generated from field: repeated livekit.proto.ParticipantKindDetail kind_details = 8;
271
+ */
272
+ kindDetails: ParticipantKindDetail[] = [];
273
+
231
274
  constructor(data?: PartialMessage<ParticipantInfo>) {
232
275
  super();
233
276
  proto2.util.initPartial(data, this);
@@ -243,6 +286,7 @@ export class ParticipantInfo extends Message<ParticipantInfo> {
243
286
  { no: 5, name: "attributes", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "scalar", T: 9 /* ScalarType.STRING */} },
244
287
  { no: 6, name: "kind", kind: "enum", T: proto2.getEnumType(ParticipantKind), req: true },
245
288
  { no: 7, name: "disconnect_reason", kind: "enum", T: proto2.getEnumType(DisconnectReason), req: true },
289
+ { no: 8, name: "kind_details", kind: "enum", T: proto2.getEnumType(ParticipantKindDetail), repeated: true },
246
290
  ]);
247
291
 
248
292
  static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): ParticipantInfo {
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -2700,12 +2700,6 @@ export class RoomEvent extends Message<RoomEvent> {
2700
2700
  */
2701
2701
  value: ParticipantAttributesChanged;
2702
2702
  case: "participantAttributesChanged";
2703
- } | {
2704
- /**
2705
- * @generated from field: livekit.proto.ParticipantEncryptionStatusChanged participant_encryption_status_changed = 39;
2706
- */
2707
- value: ParticipantEncryptionStatusChanged;
2708
- case: "participantEncryptionStatusChanged";
2709
2703
  } | {
2710
2704
  /**
2711
2705
  * @generated from field: livekit.proto.ConnectionQualityChanged connection_quality_changed = 20;
@@ -2834,6 +2828,18 @@ export class RoomEvent extends Message<RoomEvent> {
2834
2828
  */
2835
2829
  value: ParticipantsUpdated;
2836
2830
  case: "participantsUpdated";
2831
+ } | {
2832
+ /**
2833
+ * @generated from field: livekit.proto.ParticipantEncryptionStatusChanged participant_encryption_status_changed = 39;
2834
+ */
2835
+ value: ParticipantEncryptionStatusChanged;
2836
+ case: "participantEncryptionStatusChanged";
2837
+ } | {
2838
+ /**
2839
+ * @generated from field: livekit.proto.TokenRefreshed token_refreshed = 40;
2840
+ */
2841
+ value: TokenRefreshed;
2842
+ case: "tokenRefreshed";
2837
2843
  } | { case: undefined; value?: undefined } = { case: undefined };
2838
2844
 
2839
2845
  constructor(data?: PartialMessage<RoomEvent>) {
@@ -2863,7 +2869,6 @@ export class RoomEvent extends Message<RoomEvent> {
2863
2869
  { no: 17, name: "participant_metadata_changed", kind: "message", T: ParticipantMetadataChanged, oneof: "message" },
2864
2870
  { no: 18, name: "participant_name_changed", kind: "message", T: ParticipantNameChanged, oneof: "message" },
2865
2871
  { no: 19, name: "participant_attributes_changed", kind: "message", T: ParticipantAttributesChanged, oneof: "message" },
2866
- { no: 39, name: "participant_encryption_status_changed", kind: "message", T: ParticipantEncryptionStatusChanged, oneof: "message" },
2867
2872
  { no: 20, name: "connection_quality_changed", kind: "message", T: ConnectionQualityChanged, oneof: "message" },
2868
2873
  { no: 21, name: "connection_state_changed", kind: "message", T: ConnectionStateChanged, oneof: "message" },
2869
2874
  { no: 22, name: "disconnected", kind: "message", T: Disconnected, oneof: "message" },
@@ -2883,6 +2888,8 @@ export class RoomEvent extends Message<RoomEvent> {
2883
2888
  { no: 36, name: "room_updated", kind: "message", T: RoomInfo, oneof: "message" },
2884
2889
  { no: 37, name: "moved", kind: "message", T: RoomInfo, oneof: "message" },
2885
2890
  { no: 38, name: "participants_updated", kind: "message", T: ParticipantsUpdated, oneof: "message" },
2891
+ { no: 39, name: "participant_encryption_status_changed", kind: "message", T: ParticipantEncryptionStatusChanged, oneof: "message" },
2892
+ { no: 40, name: "token_refreshed", kind: "message", T: TokenRefreshed, oneof: "message" },
2886
2893
  ]);
2887
2894
 
2888
2895
  static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): RoomEvent {
@@ -4444,6 +4451,43 @@ export class Reconnected extends Message<Reconnected> {
4444
4451
  }
4445
4452
  }
4446
4453
 
4454
+ /**
4455
+ * @generated from message livekit.proto.TokenRefreshed
4456
+ */
4457
+ export class TokenRefreshed extends Message<TokenRefreshed> {
4458
+ /**
4459
+ * @generated from field: required string token = 1;
4460
+ */
4461
+ token?: string;
4462
+
4463
+ constructor(data?: PartialMessage<TokenRefreshed>) {
4464
+ super();
4465
+ proto2.util.initPartial(data, this);
4466
+ }
4467
+
4468
+ static readonly runtime: typeof proto2 = proto2;
4469
+ static readonly typeName = "livekit.proto.TokenRefreshed";
4470
+ static readonly fields: FieldList = proto2.util.newFieldList(() => [
4471
+ { no: 1, name: "token", kind: "scalar", T: 9 /* ScalarType.STRING */, req: true },
4472
+ ]);
4473
+
4474
+ static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): TokenRefreshed {
4475
+ return new TokenRefreshed().fromBinary(bytes, options);
4476
+ }
4477
+
4478
+ static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): TokenRefreshed {
4479
+ return new TokenRefreshed().fromJson(jsonValue, options);
4480
+ }
4481
+
4482
+ static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): TokenRefreshed {
4483
+ return new TokenRefreshed().fromJsonString(jsonString, options);
4484
+ }
4485
+
4486
+ static equals(a: TokenRefreshed | PlainMessage<TokenRefreshed> | undefined, b: TokenRefreshed | PlainMessage<TokenRefreshed> | undefined): boolean {
4487
+ return proto2.util.equals(TokenRefreshed, a, b);
4488
+ }
4489
+ }
4490
+
4447
4491
  /**
4448
4492
  * @generated from message livekit.proto.RoomEOS
4449
4493
  */
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -20,6 +20,34 @@
20
20
  import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
21
21
  import { Message, proto2 } from "@bufbuild/protobuf";
22
22
 
23
+ /**
24
+ * Video quality for simulcasted tracks.
25
+ *
26
+ * @generated from enum livekit.proto.VideoQuality
27
+ */
28
+ export enum VideoQuality {
29
+ /**
30
+ * @generated from enum value: VIDEO_QUALITY_LOW = 0;
31
+ */
32
+ LOW = 0,
33
+
34
+ /**
35
+ * @generated from enum value: VIDEO_QUALITY_MEDIUM = 1;
36
+ */
37
+ MEDIUM = 1,
38
+
39
+ /**
40
+ * @generated from enum value: VIDEO_QUALITY_HIGH = 2;
41
+ */
42
+ HIGH = 2,
43
+ }
44
+ // Retrieve enum metadata with: proto2.getEnumType(VideoQuality)
45
+ proto2.util.setEnumType(VideoQuality, "livekit.proto.VideoQuality", [
46
+ { no: 0, name: "VIDEO_QUALITY_LOW" },
47
+ { no: 1, name: "VIDEO_QUALITY_MEDIUM" },
48
+ { no: 2, name: "VIDEO_QUALITY_HIGH" },
49
+ ]);
50
+
23
51
  /**
24
52
  * Enable/Disable a remote track publication
25
53
  *
@@ -178,3 +206,79 @@ export class UpdateRemoteTrackPublicationDimensionResponse extends Message<Updat
178
206
  }
179
207
  }
180
208
 
209
+ /**
210
+ * For tracks that support simulcasting, adjust subscribed quality.
211
+ *
212
+ * @generated from message livekit.proto.SetRemoteTrackPublicationQualityRequest
213
+ */
214
+ export class SetRemoteTrackPublicationQualityRequest extends Message<SetRemoteTrackPublicationQualityRequest> {
215
+ /**
216
+ * @generated from field: required uint64 track_publication_handle = 1;
217
+ */
218
+ trackPublicationHandle?: bigint;
219
+
220
+ /**
221
+ * @generated from field: required livekit.proto.VideoQuality quality = 2;
222
+ */
223
+ quality?: VideoQuality;
224
+
225
+ constructor(data?: PartialMessage<SetRemoteTrackPublicationQualityRequest>) {
226
+ super();
227
+ proto2.util.initPartial(data, this);
228
+ }
229
+
230
+ static readonly runtime: typeof proto2 = proto2;
231
+ static readonly typeName = "livekit.proto.SetRemoteTrackPublicationQualityRequest";
232
+ static readonly fields: FieldList = proto2.util.newFieldList(() => [
233
+ { no: 1, name: "track_publication_handle", kind: "scalar", T: 4 /* ScalarType.UINT64 */, req: true },
234
+ { no: 2, name: "quality", kind: "enum", T: proto2.getEnumType(VideoQuality), req: true },
235
+ ]);
236
+
237
+ static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): SetRemoteTrackPublicationQualityRequest {
238
+ return new SetRemoteTrackPublicationQualityRequest().fromBinary(bytes, options);
239
+ }
240
+
241
+ static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): SetRemoteTrackPublicationQualityRequest {
242
+ return new SetRemoteTrackPublicationQualityRequest().fromJson(jsonValue, options);
243
+ }
244
+
245
+ static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): SetRemoteTrackPublicationQualityRequest {
246
+ return new SetRemoteTrackPublicationQualityRequest().fromJsonString(jsonString, options);
247
+ }
248
+
249
+ static equals(a: SetRemoteTrackPublicationQualityRequest | PlainMessage<SetRemoteTrackPublicationQualityRequest> | undefined, b: SetRemoteTrackPublicationQualityRequest | PlainMessage<SetRemoteTrackPublicationQualityRequest> | undefined): boolean {
250
+ return proto2.util.equals(SetRemoteTrackPublicationQualityRequest, a, b);
251
+ }
252
+ }
253
+
254
+ /**
255
+ * @generated from message livekit.proto.SetRemoteTrackPublicationQualityResponse
256
+ */
257
+ export class SetRemoteTrackPublicationQualityResponse extends Message<SetRemoteTrackPublicationQualityResponse> {
258
+ constructor(data?: PartialMessage<SetRemoteTrackPublicationQualityResponse>) {
259
+ super();
260
+ proto2.util.initPartial(data, this);
261
+ }
262
+
263
+ static readonly runtime: typeof proto2 = proto2;
264
+ static readonly typeName = "livekit.proto.SetRemoteTrackPublicationQualityResponse";
265
+ static readonly fields: FieldList = proto2.util.newFieldList(() => [
266
+ ]);
267
+
268
+ static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): SetRemoteTrackPublicationQualityResponse {
269
+ return new SetRemoteTrackPublicationQualityResponse().fromBinary(bytes, options);
270
+ }
271
+
272
+ static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): SetRemoteTrackPublicationQualityResponse {
273
+ return new SetRemoteTrackPublicationQualityResponse().fromJson(jsonValue, options);
274
+ }
275
+
276
+ static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): SetRemoteTrackPublicationQualityResponse {
277
+ return new SetRemoteTrackPublicationQualityResponse().fromJsonString(jsonString, options);
278
+ }
279
+
280
+ static equals(a: SetRemoteTrackPublicationQualityResponse | PlainMessage<SetRemoteTrackPublicationQualityResponse> | undefined, b: SetRemoteTrackPublicationQualityResponse | PlainMessage<SetRemoteTrackPublicationQualityResponse> | undefined): boolean {
281
+ return proto2.util.equals(SetRemoteTrackPublicationQualityResponse, a, b);
282
+ }
283
+ }
284
+
@@ -1,4 +1,4 @@
1
- // Copyright 2023 LiveKit, Inc.
1
+ // Copyright 2025 LiveKit, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -45,6 +45,11 @@ export enum VideoCodec {
45
45
  * @generated from enum value: VP9 = 3;
46
46
  */
47
47
  VP9 = 3,
48
+
49
+ /**
50
+ * @generated from enum value: H265 = 4;
51
+ */
52
+ H265 = 4,
48
53
  }
49
54
  // Retrieve enum metadata with: proto2.getEnumType(VideoCodec)
50
55
  proto2.util.setEnumType(VideoCodec, "livekit.proto.VideoCodec", [
@@ -52,6 +57,7 @@ proto2.util.setEnumType(VideoCodec, "livekit.proto.VideoCodec", [
52
57
  { no: 1, name: "H264" },
53
58
  { no: 2, name: "AV1" },
54
59
  { no: 3, name: "VP9" },
60
+ { no: 4, name: "H265" },
55
61
  ]);
56
62
 
57
63
  /**