livekit-client 2.18.10 → 2.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  2. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  3. package/dist/livekit-client.esm.mjs +720 -430
  4. package/dist/livekit-client.esm.mjs.map +1 -1
  5. package/dist/livekit-client.pt.worker.js.map +1 -1
  6. package/dist/livekit-client.pt.worker.mjs.map +1 -1
  7. package/dist/livekit-client.umd.js +1 -1
  8. package/dist/livekit-client.umd.js.map +1 -1
  9. package/dist/src/room/RTCEngine.d.ts +0 -3
  10. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  11. package/dist/src/room/Room.d.ts +4 -2
  12. package/dist/src/room/Room.d.ts.map +1 -1
  13. package/dist/src/room/participant/LocalParticipant.d.ts +5 -13
  14. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  15. package/dist/src/room/participant/RemoteParticipant.d.ts +5 -1
  16. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  17. package/dist/src/room/rpc/client/RpcClientManager.d.ts +39 -0
  18. package/dist/src/room/rpc/client/RpcClientManager.d.ts.map +1 -0
  19. package/dist/src/room/rpc/client/events.d.ts +8 -0
  20. package/dist/src/room/rpc/client/events.d.ts.map +1 -0
  21. package/dist/src/room/rpc/index.d.ts +6 -0
  22. package/dist/src/room/rpc/index.d.ts.map +1 -0
  23. package/dist/src/room/rpc/server/RpcServerManager.d.ts +44 -0
  24. package/dist/src/room/rpc/server/RpcServerManager.d.ts.map +1 -0
  25. package/dist/src/room/rpc/server/events.d.ts +8 -0
  26. package/dist/src/room/rpc/server/events.d.ts.map +1 -0
  27. package/dist/src/room/{rpc.d.ts → rpc/utils.d.ts} +34 -4
  28. package/dist/src/room/rpc/utils.d.ts.map +1 -0
  29. package/dist/src/room/utils.d.ts.map +1 -1
  30. package/dist/src/version.d.ts +8 -0
  31. package/dist/src/version.d.ts.map +1 -1
  32. package/dist/ts4.2/room/RTCEngine.d.ts +0 -3
  33. package/dist/ts4.2/room/Room.d.ts +4 -2
  34. package/dist/ts4.2/room/participant/LocalParticipant.d.ts +5 -13
  35. package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +5 -1
  36. package/dist/ts4.2/room/rpc/client/RpcClientManager.d.ts +43 -0
  37. package/dist/ts4.2/room/rpc/client/events.d.ts +8 -0
  38. package/dist/ts4.2/room/rpc/index.d.ts +7 -0
  39. package/dist/ts4.2/room/rpc/server/RpcServerManager.d.ts +44 -0
  40. package/dist/ts4.2/room/rpc/server/events.d.ts +8 -0
  41. package/dist/ts4.2/room/{rpc.d.ts → rpc/utils.d.ts} +34 -4
  42. package/dist/ts4.2/version.d.ts +8 -0
  43. package/package.json +1 -1
  44. package/src/room/RTCEngine.ts +0 -26
  45. package/src/room/Room.ts +83 -81
  46. package/src/room/participant/LocalParticipant.ts +16 -180
  47. package/src/room/participant/RemoteParticipant.ts +9 -0
  48. package/src/room/rpc/client/RpcClientManager.test.ts +430 -0
  49. package/src/room/rpc/client/RpcClientManager.ts +269 -0
  50. package/src/room/rpc/client/events.ts +9 -0
  51. package/src/room/rpc/index.ts +14 -0
  52. package/src/room/rpc/server/RpcServerManager.test.ts +471 -0
  53. package/src/room/rpc/server/RpcServerManager.ts +293 -0
  54. package/src/room/rpc/server/events.ts +9 -0
  55. package/src/room/{rpc.ts → rpc/utils.ts} +49 -8
  56. package/src/room/utils.ts +2 -1
  57. package/src/version.ts +10 -0
  58. package/dist/src/room/rpc.d.ts.map +0 -1
  59. package/src/room/rpc.test.ts +0 -301
@@ -22,6 +22,10 @@ export default class RemoteParticipant extends Participant {
22
22
  * const track = await remoteParticipant.dataTracks.getDeferred("data track name"); */
23
23
  dataTracks: DeferrableMap<RemoteDataTrack['info']['name'], RemoteDataTrack>;
24
24
  signalClient: SignalClient;
25
+ /** A version number indicating the set of features that the report participant's client supports.
26
+ * @internal
27
+ **/
28
+ clientProtocol: number;
25
29
  private volumeMap;
26
30
  private audioOutput?;
27
31
  /** @internal */
@@ -31,7 +35,7 @@ export default class RemoteParticipant extends Participant {
31
35
  remoteParticipant: string;
32
36
  };
33
37
  /** @internal */
34
- constructor(signalClient: SignalClient, sid: string, identity?: string, name?: string, metadata?: string, attributes?: Record<string, string>, loggerOptions?: LoggerOptions, kind?: ParticipantKind, remoteDataTracks?: Array<RemoteDataTrack>);
38
+ constructor(signalClient: SignalClient, sid: string, identity?: string, name?: string, metadata?: string, attributes?: Record<string, string>, loggerOptions?: LoggerOptions, kind?: ParticipantKind, remoteDataTracks?: Array<RemoteDataTrack>, clientProtocol?: number);
35
39
  protected addTrackPublication(publication: RemoteTrackPublication): void;
36
40
  getTrackPublication(source: Track.Source): RemoteTrackPublication | undefined;
37
41
  getTrackPublicationByName(name: string): RemoteTrackPublication | undefined;
@@ -0,0 +1,43 @@
1
+ import type TypedEmitter from 'typed-emitter';
2
+ import type { StructuredLogger } from '../../../logger';
3
+ import type { TextStreamReader } from '../../data-stream/incoming/StreamReader';
4
+ import type OutgoingDataStreamManager from '../../data-stream/outgoing/OutgoingDataStreamManager';
5
+ import type Participant from '../../participant/Participant';
6
+ import type { PerformRpcParams } from '../utils';
7
+ import { RpcError } from '../utils';
8
+ import type { RpcClientManagerCallbacks } from './events';
9
+ declare const RpcClientManager_base: new () => TypedEmitter<RpcClientManagerCallbacks>;
10
+ /**
11
+ * Manages the client (caller) side of RPC: sending requests, tracking pending
12
+ * ack/response state, and handling incoming ack/response packets.
13
+ * @internal
14
+ */
15
+ export default class RpcClientManager extends RpcClientManager_base {
16
+ private log;
17
+ private outgoingDataStreamManager;
18
+ private getRemoteParticipantClientProtocol;
19
+ private getServerVersion;
20
+ private pendingAcks;
21
+ private pendingResponses;
22
+ constructor(log: StructuredLogger, outgoingDataStreamManager: OutgoingDataStreamManager, getRemoteParticipantClientProtocol: (identity: Participant['identity']) => number, getServerVersion: () => string | undefined);
23
+ performRpc({ destinationIdentity, method, payload, responseTimeout: responseTimeoutMs, }: PerformRpcParams): Promise<[
24
+ id: string,
25
+ completionPromise: Promise<string>
26
+ ]>;
27
+ private publishRpcRequest;
28
+ /**
29
+ * Handle an incoming data stream containing an RPC response payload.
30
+ * @internal
31
+ */
32
+ handleIncomingDataStream(reader: TextStreamReader, senderIdentity: Participant['identity'], attributes: Record<string, string>): Promise<void>;
33
+ /** @internal */
34
+ handleIncomingRpcResponseSuccess(requestId: string, payload: string): void;
35
+ /** @internal */
36
+ handleIncomingRpcResponseFailure(requestId: string, error: RpcError): void;
37
+ /** @internal */
38
+ handleIncomingRpcAck(requestId: string): void;
39
+ /** @internal */
40
+ handleParticipantDisconnected(participantIdentity: string): void;
41
+ }
42
+ export {};
43
+ //# sourceMappingURL=RpcClientManager.d.ts.map
@@ -0,0 +1,8 @@
1
+ import type { DataPacket } from '@livekit/protocol';
2
+ export type EventSendDataPacket = {
3
+ packet: DataPacket;
4
+ };
5
+ export type RpcClientManagerCallbacks = {
6
+ sendDataPacket: (event: EventSendDataPacket) => void;
7
+ };
8
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1,7 @@
1
+ export { default as RpcClientManager } from './client/RpcClientManager';
2
+ export type { RpcClientManagerCallbacks } from './client/events';
3
+ export { default as RpcServerManager } from './server/RpcServerManager';
4
+ export type { RpcServerManagerCallbacks } from './server/events';
5
+ export type { PerformRpcParams, RpcInvocationData } from './utils';
6
+ export { RPC_REQUEST_DATA_STREAM_TOPIC, RPC_RESPONSE_DATA_STREAM_TOPIC, RpcRequestAttrs, RpcError, byteLength, truncateBytes } from './utils';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,44 @@
1
+ import { RpcRequest } from '@livekit/protocol';
2
+ import type TypedEmitter from 'typed-emitter';
3
+ import type { StructuredLogger } from '../../../logger';
4
+ import type { TextStreamReader } from '../../data-stream/incoming/StreamReader';
5
+ import type OutgoingDataStreamManager from '../../data-stream/outgoing/OutgoingDataStreamManager';
6
+ import type Participant from '../../participant/Participant';
7
+ import type { RpcInvocationData } from '../utils';
8
+ import type { RpcServerManagerCallbacks } from './events';
9
+ declare const RpcServerManager_base: new () => TypedEmitter<RpcServerManagerCallbacks>;
10
+ /**
11
+ * Manages the server (handler) side of RPC: processing incoming requests,
12
+ * managing registered method handlers, and sending responses.
13
+ * @internal
14
+ */
15
+ export default class RpcServerManager extends RpcServerManager_base {
16
+ private log;
17
+ private outgoingDataStreamManager;
18
+ private getRemoteParticipantClientProtocol;
19
+ private rpcHandlers;
20
+ constructor(log: StructuredLogger, outgoingDataStreamManager: OutgoingDataStreamManager, getRemoteParticipantClientProtocol: (identity: Participant['identity']) => number);
21
+ registerRpcMethod(method: string, handler: (data: RpcInvocationData) => Promise<string>): void;
22
+ unregisterRpcMethod(method: string): void;
23
+ /**
24
+ * Handle an incoming RPCRequest message containing a payload.
25
+ * This handles "version 1" of rpc requests.
26
+ * @internal
27
+ */
28
+ handleIncomingRpcRequest(callerIdentity: string, rpcRequest: RpcRequest): Promise<void>;
29
+ /**
30
+ * Handle an incoming data stream containing a RPC request payload.
31
+ * This handles "version 2" of rpc requests.
32
+ * @internal
33
+ */
34
+ handleIncomingDataStream(reader: TextStreamReader, callerIdentity: Participant['identity'], dataStreamAttrs: Record<string, string>): Promise<void>;
35
+ private publishRpcAck;
36
+ private publishRpcResponsePacket;
37
+ /**
38
+ * Send a successful RPC response payload, choosing the transport based on
39
+ * the caller's client protocol version.
40
+ */
41
+ private publishRpcResponse;
42
+ }
43
+ export {};
44
+ //# sourceMappingURL=RpcServerManager.d.ts.map
@@ -0,0 +1,8 @@
1
+ import type { DataPacket } from '@livekit/protocol';
2
+ export type EventSendDataPacket = {
3
+ packet: DataPacket;
4
+ };
5
+ export type RpcServerManagerCallbacks = {
6
+ sendDataPacket: (event: EventSendDataPacket) => void;
7
+ };
8
+ //# sourceMappingURL=events.d.ts.map
@@ -49,6 +49,7 @@ export declare class RpcError extends Error {
49
49
  static MAX_DATA_BYTES: number;
50
50
  code: number;
51
51
  data?: string;
52
+ cause?: unknown;
52
53
  /**
53
54
  * Creates an error object with the given code and message, plus an optional data payload.
54
55
  *
@@ -56,7 +57,9 @@ export declare class RpcError extends Error {
56
57
  *
57
58
  * Error codes 1001-1999 are reserved for built-in errors (see RpcError.ErrorCode for their meanings).
58
59
  */
59
- constructor(code: number, message: string, data?: string);
60
+ constructor(code: number, message: string, data?: string, options?: {
61
+ cause?: unknown;
62
+ });
60
63
  /**
61
64
  * @internal
62
65
  */
@@ -87,9 +90,36 @@ export declare class RpcError extends Error {
87
90
  *
88
91
  * @internal
89
92
  */
90
- static builtIn(key: keyof typeof RpcError.ErrorCode, data?: string): RpcError;
93
+ static builtIn(key: keyof typeof RpcError.ErrorCode, data?: string, options?: {
94
+ cause?: unknown;
95
+ }): RpcError;
91
96
  }
92
- export declare const MAX_PAYLOAD_BYTES = 15360;
97
+ export declare const MAX_V1_PAYLOAD_BYTES = 15360;
98
+ /**
99
+ * Topic used for v2 RPC request data streams.
100
+ * @internal
101
+ */
102
+ export declare const RPC_REQUEST_DATA_STREAM_TOPIC = "lk.rpc_request";
103
+ /**
104
+ * Topic used for v2 RPC response data streams.
105
+ * @internal
106
+ */
107
+ export declare const RPC_RESPONSE_DATA_STREAM_TOPIC = "lk.rpc_response";
108
+ /** @internal */
109
+ export declare enum RpcRequestAttrs {
110
+ RPC_REQUEST_ID = "lk.rpc_request_id",
111
+ RPC_REQUEST_METHOD = "lk.rpc_request_method",
112
+ RPC_REQUEST_RESPONSE_TIMEOUT_MS = "lk.rpc_request_response_timeout_ms",
113
+ RPC_REQUEST_VERSION = "lk.rpc_request_version"
114
+ }
115
+ /** Initial version of rpc which uses RpcRequest / RpcResponse messages.
116
+ * @internal
117
+ **/
118
+ export declare const RPC_VERSION_V1 = 1;
119
+ /** Rpc version backed by data streams instead of RpcRequest / RpcResponse.
120
+ * @internal
121
+ **/
122
+ export declare const RPC_VERSION_V2 = 2;
93
123
  /**
94
124
  * @internal
95
125
  */
@@ -98,4 +128,4 @@ export declare function byteLength(str: string): number;
98
128
  * @internal
99
129
  */
100
130
  export declare function truncateBytes(str: string, maxBytes: number): string;
101
- //# sourceMappingURL=rpc.d.ts.map
131
+ //# sourceMappingURL=utils.d.ts.map
@@ -1,3 +1,11 @@
1
1
  export declare const version: string;
2
2
  export declare const protocolVersion = 17;
3
+ /** Initial client protocol. */
4
+ export declare const CLIENT_PROTOCOL_DEFAULT = 0;
5
+ /** Replaces RPC v1 protocol with a v2 data streams based one to support unlimited request /
6
+ * response payload length. */
7
+ export declare const CLIENT_PROTOCOL_DATA_STREAM_RPC = 1;
8
+ /** The client protocol version indicates what level of support that the client has for
9
+ * client <-> client api interactions. */
10
+ export declare const clientProtocol = 1;
3
11
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livekit-client",
3
- "version": "2.18.10",
3
+ "version": "2.19.0",
4
4
  "description": "JavaScript/TypeScript client SDK for LiveKit",
5
5
  "main": "./dist/livekit-client.umd.js",
6
6
  "unpkg": "./dist/livekit-client.umd.js",
@@ -26,7 +26,6 @@ import {
26
26
  Room as RoomModel,
27
27
  RoomMovedResponse,
28
28
  RpcAck,
29
- RpcResponse,
30
29
  ServerInfo,
31
30
  SessionDescription,
32
31
  SignalTarget,
@@ -79,7 +78,6 @@ import {
79
78
  UnexpectedConnectionState,
80
79
  } from './errors';
81
80
  import { EngineEvent } from './events';
82
- import { RpcError } from './rpc';
83
81
  import CriticalTimers from './timers';
84
82
  import type LocalTrack from './track/LocalTrack';
85
83
  import type LocalTrackPublication from './track/LocalTrackPublication';
@@ -1464,30 +1462,6 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1464
1462
  });
1465
1463
  };
1466
1464
 
1467
- /** @internal */
1468
- async publishRpcResponse(
1469
- destinationIdentity: string,
1470
- requestId: string,
1471
- payload: string | null,
1472
- error: RpcError | null,
1473
- ) {
1474
- const packet = new DataPacket({
1475
- destinationIdentities: [destinationIdentity],
1476
- kind: DataPacket_Kind.RELIABLE,
1477
- value: {
1478
- case: 'rpcResponse',
1479
- value: new RpcResponse({
1480
- requestId,
1481
- value: error
1482
- ? { case: 'error', value: error.toProto() }
1483
- : { case: 'payload', value: payload ?? '' },
1484
- }),
1485
- },
1486
- });
1487
-
1488
- await this.sendDataPacket(packet, DataChannelKind.RELIABLE);
1489
- }
1490
-
1491
1465
  /** @internal */
1492
1466
  async publishRpcAck(destinationIdentity: string, requestId: string) {
1493
1467
  const packet = new DataPacket({
package/src/room/Room.ts CHANGED
@@ -48,6 +48,7 @@ import { PacketTrailerManager } from '../packetTrailer/PacketTrailerManager';
48
48
  import { isPacketTrailerSupported } from '../packetTrailer/utils';
49
49
  import TypedPromise from '../utils/TypedPromise';
50
50
  import { getBrowser } from '../utils/browserParser';
51
+ import { CLIENT_PROTOCOL_DEFAULT } from '../version';
51
52
  import { BackOffStrategy } from './BackOffStrategy';
52
53
  import DeviceManager from './DeviceManager';
53
54
  import RTCEngine, { DataChannelKind, type RegionStrategy } from './RTCEngine';
@@ -81,7 +82,14 @@ import LocalParticipant from './participant/LocalParticipant';
81
82
  import Participant from './participant/Participant';
82
83
  import { type ConnectionQuality, ParticipantKind } from './participant/Participant';
83
84
  import RemoteParticipant from './participant/RemoteParticipant';
84
- import { MAX_PAYLOAD_BYTES, RpcError, type RpcInvocationData, byteLength } from './rpc';
85
+ import {
86
+ RPC_REQUEST_DATA_STREAM_TOPIC,
87
+ RPC_RESPONSE_DATA_STREAM_TOPIC,
88
+ RpcClientManager,
89
+ RpcError,
90
+ type RpcInvocationData,
91
+ RpcServerManager,
92
+ } from './rpc';
85
93
  import CriticalTimers from './timers';
86
94
  import LocalAudioTrack from './track/LocalAudioTrack';
87
95
  import type LocalTrack from './track/LocalTrack';
@@ -221,7 +229,9 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
221
229
 
222
230
  private outgoingDataTrackManager: OutgoingDataTrackManager;
223
231
 
224
- private rpcHandlers: Map<string, (data: RpcInvocationData) => Promise<string>> = new Map();
232
+ private rpcClientManager: RpcClientManager;
233
+
234
+ private rpcServerManager: RpcServerManager;
225
235
 
226
236
  get hasE2EESetup(): boolean {
227
237
  return this.e2eeManager !== undefined;
@@ -301,15 +311,36 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
301
311
  .finally(() => this.outgoingDataTrackManager.handlePacketSendComplete(handle));
302
312
  });
303
313
 
314
+ this.registerRpcDataStreamHandler();
315
+
316
+ this.rpcClientManager = new RpcClientManager(
317
+ this.log,
318
+ this.outgoingDataStreamManager,
319
+ this.getRemoteParticipantClientProtocol,
320
+ () => this.engine.latestJoinResponse?.serverInfo?.version,
321
+ );
322
+ this.rpcClientManager.on('sendDataPacket', ({ packet }) => {
323
+ this.engine?.sendDataPacket(packet, DataChannelKind.RELIABLE);
324
+ });
325
+ this.rpcServerManager = new RpcServerManager(
326
+ this.log,
327
+ this.outgoingDataStreamManager,
328
+ this.getRemoteParticipantClientProtocol,
329
+ );
330
+ this.rpcServerManager.on('sendDataPacket', ({ packet }) => {
331
+ this.engine?.sendDataPacket(packet, DataChannelKind.RELIABLE);
332
+ });
333
+
304
334
  this.disconnectLock = new Mutex();
305
335
  this.localParticipant = new LocalParticipant(
306
336
  '',
307
337
  '',
308
338
  this.engine,
309
339
  this.options,
310
- this.rpcHandlers,
311
340
  this.outgoingDataStreamManager,
312
341
  this.outgoingDataTrackManager,
342
+ this.rpcClientManager,
343
+ this.rpcServerManager,
313
344
  );
314
345
 
315
346
  this.setupPacketTrailer();
@@ -400,12 +431,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
400
431
  * Other errors thrown in your handler will not be transmitted as-is, and will instead arrive to the caller as `1500` ("Application Error").
401
432
  */
402
433
  registerRpcMethod(method: string, handler: (data: RpcInvocationData) => Promise<string>) {
403
- if (this.rpcHandlers.has(method)) {
404
- throw Error(
405
- `RPC handler already registered for method ${method}, unregisterRpcMethod before trying to register again`,
406
- );
407
- }
408
- this.rpcHandlers.set(method, handler);
434
+ this.rpcServerManager.registerRpcMethod(method, handler);
409
435
  }
410
436
 
411
437
  /**
@@ -414,7 +440,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
414
440
  * @param method - The name of the RPC method to unregister
415
441
  */
416
442
  unregisterRpcMethod(method: string) {
417
- this.rpcHandlers.delete(method);
443
+ this.rpcServerManager.unregisterRpcMethod(method);
418
444
  }
419
445
 
420
446
  /**
@@ -1873,7 +1899,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1873
1899
  });
1874
1900
  this.emit(RoomEvent.ParticipantDisconnected, participant);
1875
1901
  participant.setDisconnected();
1876
- this.localParticipant?.handleParticipantDisconnected(participant.identity);
1902
+ this.rpcClientManager.handleParticipantDisconnected(participant.identity);
1877
1903
  }
1878
1904
 
1879
1905
  // updates are sent only when there's a change to speaker ordering
@@ -2017,14 +2043,31 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
2017
2043
  this.handleDataStream(packet, encryptionType);
2018
2044
  } else if (packet.value.case === 'rpcRequest') {
2019
2045
  const rpc = packet.value.value;
2020
- this.handleIncomingRpcRequest(
2021
- packet.participantIdentity,
2022
- rpc.id,
2023
- rpc.method,
2024
- rpc.payload,
2025
- rpc.responseTimeoutMs,
2026
- rpc.version,
2027
- );
2046
+ this.rpcServerManager.handleIncomingRpcRequest(packet.participantIdentity, rpc);
2047
+ } else if (packet.value.case === 'rpcResponse') {
2048
+ const rpcResponse = packet.value.value;
2049
+ switch (rpcResponse.value.case) {
2050
+ case 'payload':
2051
+ this.rpcClientManager.handleIncomingRpcResponseSuccess(
2052
+ rpcResponse.requestId,
2053
+ rpcResponse.value.value,
2054
+ );
2055
+ break;
2056
+ case 'error':
2057
+ this.rpcClientManager.handleIncomingRpcResponseFailure(
2058
+ rpcResponse.requestId,
2059
+ RpcError.fromProto(rpcResponse.value.value),
2060
+ );
2061
+ break;
2062
+ default:
2063
+ this.log.warn(
2064
+ `Unknown rpcResponse.value.case: ${rpcResponse.value.case}`,
2065
+ this.logContext,
2066
+ );
2067
+ break;
2068
+ }
2069
+ } else if (packet.value.case === 'rpcAck') {
2070
+ this.rpcClientManager.handleIncomingRpcAck(packet.value.value.requestId);
2028
2071
  }
2029
2072
  };
2030
2073
 
@@ -2093,68 +2136,6 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
2093
2136
  this.incomingDataStreamManager.handleDataStreamPacket(packet, encryptionType);
2094
2137
  };
2095
2138
 
2096
- private async handleIncomingRpcRequest(
2097
- callerIdentity: string,
2098
- requestId: string,
2099
- method: string,
2100
- payload: string,
2101
- responseTimeout: number,
2102
- version: number,
2103
- ) {
2104
- await this.engine.publishRpcAck(callerIdentity, requestId);
2105
-
2106
- if (version !== 1) {
2107
- await this.engine.publishRpcResponse(
2108
- callerIdentity,
2109
- requestId,
2110
- null,
2111
- RpcError.builtIn('UNSUPPORTED_VERSION'),
2112
- );
2113
- return;
2114
- }
2115
-
2116
- const handler = this.rpcHandlers.get(method);
2117
-
2118
- if (!handler) {
2119
- await this.engine.publishRpcResponse(
2120
- callerIdentity,
2121
- requestId,
2122
- null,
2123
- RpcError.builtIn('UNSUPPORTED_METHOD'),
2124
- );
2125
- return;
2126
- }
2127
-
2128
- let responseError: RpcError | null = null;
2129
- let responsePayload: string | null = null;
2130
-
2131
- try {
2132
- const response = await handler({
2133
- requestId,
2134
- callerIdentity,
2135
- payload,
2136
- responseTimeout,
2137
- });
2138
- if (byteLength(response) > MAX_PAYLOAD_BYTES) {
2139
- responseError = RpcError.builtIn('RESPONSE_PAYLOAD_TOO_LARGE');
2140
- this.log.warn(`RPC Response payload too large for ${method}`);
2141
- } else {
2142
- responsePayload = response;
2143
- }
2144
- } catch (error) {
2145
- if (error instanceof RpcError) {
2146
- responseError = error;
2147
- } else {
2148
- this.log.warn(
2149
- `Uncaught error returned by RPC handler for ${method}. Returning APPLICATION_ERROR instead.`,
2150
- error,
2151
- );
2152
- responseError = RpcError.builtIn('APPLICATION_ERROR');
2153
- }
2154
- }
2155
- await this.engine.publishRpcResponse(callerIdentity, requestId, responsePayload, responseError);
2156
- }
2157
-
2158
2139
  bufferedSegments: Map<string, TranscriptionSegmentModel> = new Map();
2159
2140
 
2160
2141
  private handleAudioPlaybackStarted = () => {
@@ -2500,6 +2481,27 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
2500
2481
  }
2501
2482
  }
2502
2483
 
2484
+ private getRemoteParticipantClientProtocol = (identity: Participant['identity']) => {
2485
+ return this.remoteParticipants.get(identity)?.clientProtocol ?? CLIENT_PROTOCOL_DEFAULT;
2486
+ };
2487
+
2488
+ private registerRpcDataStreamHandler() {
2489
+ this.incomingDataStreamManager.registerTextStreamHandler(
2490
+ RPC_REQUEST_DATA_STREAM_TOPIC,
2491
+ async (reader, { identity }) => {
2492
+ const attributes = reader.info.attributes ?? {};
2493
+ await this.rpcServerManager.handleIncomingDataStream(reader, identity, attributes);
2494
+ },
2495
+ );
2496
+ this.incomingDataStreamManager.registerTextStreamHandler(
2497
+ RPC_RESPONSE_DATA_STREAM_TOPIC,
2498
+ async (reader, { identity }) => {
2499
+ const attributes = reader.info.attributes ?? {};
2500
+ await this.rpcClientManager.handleIncomingDataStream(reader, identity, attributes);
2501
+ },
2502
+ );
2503
+ }
2504
+
2503
2505
  private registerConnectionReconcile() {
2504
2506
  this.clearConnectionReconcile();
2505
2507
  let consecutiveFailures = 0;