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
@@ -13,9 +13,6 @@ import {
13
13
  ParticipantInfo,
14
14
  RequestResponse,
15
15
  RequestResponse_Reason,
16
- RpcAck,
17
- RpcRequest,
18
- RpcResponse,
19
16
  SimulcastCodec,
20
17
  SipDTMF,
21
18
  SubscribedQualityUpdate,
@@ -54,11 +51,11 @@ import {
54
51
  } from '../errors';
55
52
  import { EngineEvent, ParticipantEvent, TrackEvent } from '../events';
56
53
  import {
57
- MAX_PAYLOAD_BYTES,
58
54
  type PerformRpcParams,
55
+ RpcClientManager,
59
56
  RpcError,
60
57
  type RpcInvocationData,
61
- byteLength,
58
+ RpcServerManager,
62
59
  } from '../rpc';
63
60
  import LocalAudioTrack from '../track/LocalAudioTrack';
64
61
  import LocalTrack from '../track/LocalTrack';
@@ -94,7 +91,6 @@ import {
94
91
  } from '../types';
95
92
  import {
96
93
  Future,
97
- compareVersions,
98
94
  isAudioTrack,
99
95
  isE2EESimulcastSupported,
100
96
  isFireFox,
@@ -162,12 +158,14 @@ export default class LocalParticipant extends Participant {
162
158
 
163
159
  private firstActiveAgent?: RemoteParticipant;
164
160
 
165
- private rpcHandlers: Map<string, (data: RpcInvocationData) => Promise<string>>;
166
-
167
161
  private roomOutgoingDataStreamManager: OutgoingDataStreamManager;
168
162
 
169
163
  private roomOutgoingDataTrackManager: OutgoingDataTrackManager;
170
164
 
165
+ private rpcClientManager: RpcClientManager;
166
+
167
+ private rpcServerManager: RpcServerManager;
168
+
171
169
  private pendingSignalRequests: Map<
172
170
  number,
173
171
  {
@@ -179,25 +177,16 @@ export default class LocalParticipant extends Participant {
179
177
 
180
178
  private enabledPublishVideoCodecs: Codec[] = [];
181
179
 
182
- private pendingAcks = new Map<string, { resolve: () => void; participantIdentity: string }>();
183
-
184
- private pendingResponses = new Map<
185
- string,
186
- {
187
- resolve: (payload: string | null, error: RpcError | null) => void;
188
- participantIdentity: string;
189
- }
190
- >();
191
-
192
180
  /** @internal */
193
181
  constructor(
194
182
  sid: string,
195
183
  identity: string,
196
184
  engine: RTCEngine,
197
185
  options: InternalRoomOptions,
198
- roomRpcHandlers: Map<string, (data: RpcInvocationData) => Promise<string>>,
199
186
  roomOutgoingDataStreamManager: OutgoingDataStreamManager,
200
187
  roomOutgoingDataTrackManager: OutgoingDataTrackManager,
188
+ rpcClientManager: RpcClientManager,
189
+ rpcServerManager: RpcServerManager,
201
190
  ) {
202
191
  super(sid, identity, undefined, undefined, undefined, {
203
192
  loggerName: options.loggerName,
@@ -215,9 +204,10 @@ export default class LocalParticipant extends Participant {
215
204
  ['audiooutput', 'default'],
216
205
  ]);
217
206
  this.pendingSignalRequests = new Map();
218
- this.rpcHandlers = roomRpcHandlers;
219
207
  this.roomOutgoingDataStreamManager = roomOutgoingDataStreamManager;
220
208
  this.roomOutgoingDataTrackManager = roomOutgoingDataTrackManager;
209
+ this.rpcClientManager = rpcClientManager;
210
+ this.rpcServerManager = rpcServerManager;
221
211
  }
222
212
 
223
213
  get lastCameraError(): Error | undefined {
@@ -277,8 +267,7 @@ export default class LocalParticipant extends Participant {
277
267
  .on(EngineEvent.LocalTrackUnpublished, this.handleLocalTrackUnpublished)
278
268
  .on(EngineEvent.SubscribedQualityUpdate, this.handleSubscribedQualityUpdate)
279
269
  .on(EngineEvent.Closing, this.handleClosing)
280
- .on(EngineEvent.SignalRequestResponse, this.handleSignalRequestResponse)
281
- .on(EngineEvent.DataPacketReceived, this.handleDataPacket);
270
+ .on(EngineEvent.SignalRequestResponse, this.handleSignalRequestResponse);
282
271
  }
283
272
 
284
273
  private handleReconnecting = () => {
@@ -362,27 +351,6 @@ export default class LocalParticipant extends Participant {
362
351
  }
363
352
  };
364
353
 
365
- private handleDataPacket = (packet: DataPacket) => {
366
- switch (packet.value.case) {
367
- case 'rpcResponse':
368
- let rpcResponse = packet.value.value as RpcResponse;
369
- let payload: string | null = null;
370
- let error: RpcError | null = null;
371
-
372
- if (rpcResponse.value.case === 'payload') {
373
- payload = rpcResponse.value.value;
374
- } else if (rpcResponse.value.case === 'error') {
375
- error = RpcError.fromProto(rpcResponse.value.value);
376
- }
377
- this.handleIncomingRpcResponse(rpcResponse.requestId, payload, error);
378
- break;
379
- case 'rpcAck':
380
- let rpcAck = packet.value.value as RpcAck;
381
- this.handleIncomingRpcAck(rpcAck.requestId);
382
- break;
383
- }
384
- };
385
-
386
354
  /**
387
355
  * Sets and updates the metadata of the local participant.
388
356
  * Note: this requires `canUpdateOwnMetadata` permission.
@@ -1883,69 +1851,9 @@ export default class LocalParticipant extends Participant {
1883
1851
  * @returns A promise that resolves with the response payload or rejects with an error.
1884
1852
  * @throws Error on failure. Details in `message`.
1885
1853
  */
1886
- performRpc({
1887
- destinationIdentity,
1888
- method,
1889
- payload,
1890
- responseTimeout = 15000,
1891
- }: PerformRpcParams): TypedPromise<string, RpcError> {
1892
- const maxRoundTripLatency = 7000;
1893
- const minEffectiveTimeout = maxRoundTripLatency + 1000;
1894
-
1895
- return new TypedPromise<string, RpcError>(async (resolve, reject) => {
1896
- if (byteLength(payload) > MAX_PAYLOAD_BYTES) {
1897
- reject(RpcError.builtIn('REQUEST_PAYLOAD_TOO_LARGE'));
1898
- return;
1899
- }
1900
-
1901
- if (
1902
- this.engine.latestJoinResponse?.serverInfo?.version &&
1903
- compareVersions(this.engine.latestJoinResponse?.serverInfo?.version, '1.8.0') < 0
1904
- ) {
1905
- reject(RpcError.builtIn('UNSUPPORTED_SERVER'));
1906
- return;
1907
- }
1908
-
1909
- const effectiveTimeout = Math.max(responseTimeout, minEffectiveTimeout);
1910
- const id = crypto.randomUUID();
1911
- await this.publishRpcRequest(destinationIdentity, id, method, payload, effectiveTimeout);
1912
-
1913
- const ackTimeoutId = setTimeout(() => {
1914
- this.pendingAcks.delete(id);
1915
- reject(RpcError.builtIn('CONNECTION_TIMEOUT'));
1916
- this.pendingResponses.delete(id);
1917
- clearTimeout(responseTimeoutId);
1918
- }, maxRoundTripLatency);
1919
-
1920
- this.pendingAcks.set(id, {
1921
- resolve: () => {
1922
- clearTimeout(ackTimeoutId);
1923
- },
1924
- participantIdentity: destinationIdentity,
1925
- });
1926
-
1927
- const responseTimeoutId = setTimeout(() => {
1928
- this.pendingResponses.delete(id);
1929
- reject(RpcError.builtIn('RESPONSE_TIMEOUT'));
1930
- }, responseTimeout);
1931
-
1932
- this.pendingResponses.set(id, {
1933
- resolve: (responsePayload: string | null, responseError: RpcError | null) => {
1934
- clearTimeout(responseTimeoutId);
1935
- if (this.pendingAcks.has(id)) {
1936
- this.log.warn('RPC response received before ack', id);
1937
- this.pendingAcks.delete(id);
1938
- clearTimeout(ackTimeoutId);
1939
- }
1940
-
1941
- if (responseError) {
1942
- reject(responseError);
1943
- } else {
1944
- resolve(responsePayload ?? '');
1945
- }
1946
- },
1947
- participantIdentity: destinationIdentity,
1948
- });
1854
+ performRpc(params: PerformRpcParams): TypedPromise<string, RpcError> {
1855
+ return this.rpcClientManager.performRpc(params).then(([_id, completionPromise]) => {
1856
+ return completionPromise;
1949
1857
  });
1950
1858
  }
1951
1859
 
@@ -1953,20 +1861,14 @@ export default class LocalParticipant extends Participant {
1953
1861
  * @deprecated use `room.registerRpcMethod` instead
1954
1862
  */
1955
1863
  registerRpcMethod(method: string, handler: (data: RpcInvocationData) => Promise<string>) {
1956
- if (this.rpcHandlers.has(method)) {
1957
- this.log.warn(
1958
- `you're overriding the RPC handler for method ${method}, in the future this will throw an error`,
1959
- );
1960
- }
1961
-
1962
- this.rpcHandlers.set(method, handler);
1864
+ this.rpcServerManager.registerRpcMethod(method, handler);
1963
1865
  }
1964
1866
 
1965
1867
  /**
1966
1868
  * @deprecated use `room.unregisterRpcMethod` instead
1967
1869
  */
1968
1870
  unregisterRpcMethod(method: string) {
1969
- this.rpcHandlers.delete(method);
1871
+ this.rpcServerManager.unregisterRpcMethod(method);
1970
1872
  }
1971
1873
 
1972
1874
  /**
@@ -1997,72 +1899,6 @@ export default class LocalParticipant extends Participant {
1997
1899
  }
1998
1900
  }
1999
1901
 
2000
- private handleIncomingRpcAck(requestId: string) {
2001
- const handler = this.pendingAcks.get(requestId);
2002
- if (handler) {
2003
- handler.resolve();
2004
- this.pendingAcks.delete(requestId);
2005
- } else {
2006
- console.error('Ack received for unexpected RPC request', requestId);
2007
- }
2008
- }
2009
-
2010
- private handleIncomingRpcResponse(
2011
- requestId: string,
2012
- payload: string | null,
2013
- error: RpcError | null,
2014
- ) {
2015
- const handler = this.pendingResponses.get(requestId);
2016
- if (handler) {
2017
- handler.resolve(payload, error);
2018
- this.pendingResponses.delete(requestId);
2019
- } else {
2020
- console.error('Response received for unexpected RPC request', requestId);
2021
- }
2022
- }
2023
-
2024
- /** @internal */
2025
- private async publishRpcRequest(
2026
- destinationIdentity: string,
2027
- requestId: string,
2028
- method: string,
2029
- payload: string,
2030
- responseTimeout: number,
2031
- ) {
2032
- const packet = new DataPacket({
2033
- destinationIdentities: [destinationIdentity],
2034
- kind: DataPacket_Kind.RELIABLE,
2035
- value: {
2036
- case: 'rpcRequest',
2037
- value: new RpcRequest({
2038
- id: requestId,
2039
- method,
2040
- payload,
2041
- responseTimeoutMs: responseTimeout,
2042
- version: 1,
2043
- }),
2044
- },
2045
- });
2046
-
2047
- await this.engine.sendDataPacket(packet, DataChannelKind.RELIABLE);
2048
- }
2049
-
2050
- /** @internal */
2051
- handleParticipantDisconnected(participantIdentity: string) {
2052
- for (const [id, { participantIdentity: pendingIdentity }] of this.pendingAcks) {
2053
- if (pendingIdentity === participantIdentity) {
2054
- this.pendingAcks.delete(id);
2055
- }
2056
- }
2057
-
2058
- for (const [id, { participantIdentity: pendingIdentity, resolve }] of this.pendingResponses) {
2059
- if (pendingIdentity === participantIdentity) {
2060
- resolve(null, RpcError.builtIn('RECIPIENT_DISCONNECTED'));
2061
- this.pendingResponses.delete(id);
2062
- }
2063
- }
2064
- }
2065
-
2066
1902
  /** @internal */
2067
1903
  setEnabledPublishCodecs(codecs: Codec[]) {
2068
1904
  this.enabledPublishVideoCodecs = codecs.filter(
@@ -6,6 +6,7 @@ import type {
6
6
  } from '@livekit/protocol';
7
7
  import type { SignalClient } from '../../api/SignalClient';
8
8
  import { DeferrableMap } from '../../utils/deferrable-map';
9
+ import { CLIENT_PROTOCOL_DEFAULT } from '../../version';
9
10
  import RemoteDataTrack from '../data-track/RemoteDataTrack';
10
11
  import type IncomingDataTrackManager from '../data-track/incoming/IncomingDataTrackManager';
11
12
  import { DataTrackInfo } from '../data-track/types';
@@ -41,6 +42,11 @@ export default class RemoteParticipant extends Participant {
41
42
 
42
43
  signalClient: SignalClient;
43
44
 
45
+ /** A version number indicating the set of features that the report participant's client supports.
46
+ * @internal
47
+ **/
48
+ clientProtocol: number;
49
+
44
50
  private volumeMap: Map<Track.Source, number>;
45
51
 
46
52
  private audioOutput?: AudioOutputOptions;
@@ -65,6 +71,7 @@ export default class RemoteParticipant extends Participant {
65
71
  const info = DataTrackInfo.from(dti);
66
72
  return new RemoteDataTrack(info, manager, { publisherIdentity: pi.identity });
67
73
  }),
74
+ pi.clientProtocol,
68
75
  );
69
76
  }
70
77
 
@@ -87,6 +94,7 @@ export default class RemoteParticipant extends Participant {
87
94
  loggerOptions?: LoggerOptions,
88
95
  kind: ParticipantKind = ParticipantKind.STANDARD,
89
96
  remoteDataTracks: Array<RemoteDataTrack> = [],
97
+ clientProtocol: number = CLIENT_PROTOCOL_DEFAULT,
90
98
  ) {
91
99
  super(sid, identity || '', name, metadata, attributes, loggerOptions, kind);
92
100
  this.signalClient = signalClient;
@@ -99,6 +107,7 @@ export default class RemoteParticipant extends Participant {
99
107
  }),
100
108
  );
101
109
  this.volumeMap = new Map();
110
+ this.clientProtocol = clientProtocol;
102
111
  }
103
112
 
104
113
  protected addTrackPublication(publication: RemoteTrackPublication) {