livekit-client 2.5.10 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +54 -0
- package/dist/livekit-client.esm.mjs +418 -32
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +2 -0
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +56 -0
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/rpc.d.ts +96 -0
- package/dist/src/room/rpc.d.ts.map +1 -0
- package/dist/src/room/track/utils.d.ts +2 -2
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/ts4.2/src/index.d.ts +2 -0
- package/dist/ts4.2/src/room/PCTransport.d.ts +2 -0
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +56 -0
- package/dist/ts4.2/src/room/rpc.d.ts +96 -0
- package/dist/ts4.2/src/room/track/utils.d.ts +2 -2
- package/package.json +2 -2
- package/src/index.ts +2 -0
- package/src/room/PCTransport.ts +42 -29
- package/src/room/Room.ts +1 -0
- package/src/room/participant/LocalParticipant.test.ts +304 -0
- package/src/room/participant/LocalParticipant.ts +340 -1
- package/src/room/rpc.ts +172 -0
- package/src/room/track/utils.ts +1 -6
package/README.md
CHANGED
@@ -304,12 +304,66 @@ setLogExtension((level: LogLevel, msg: string, context: object) => {
|
|
304
304
|
});
|
305
305
|
```
|
306
306
|
|
307
|
+
### RPC
|
308
|
+
|
309
|
+
Perform your own predefined method calls from one participant to another.
|
310
|
+
|
311
|
+
This feature is especially powerful when used with [Agents](https://docs.livekit.io/agents), for instance to forward LLM function calls to your client application.
|
312
|
+
|
313
|
+
#### Registering an RPC method
|
314
|
+
|
315
|
+
The participant who implements the method and will receive its calls must first register support:
|
316
|
+
|
317
|
+
```typescript
|
318
|
+
room.localParticipant?.registerRpcMethod(
|
319
|
+
// method name - can be any string that makes sense for your application
|
320
|
+
'greet',
|
321
|
+
|
322
|
+
// method handler - will be called when the method is invoked by a RemoteParticipant
|
323
|
+
async (data: RpcInvocationData) => {
|
324
|
+
console.log(`Received greeting from ${data.callerIdentity}: ${data.payload}`);
|
325
|
+
return `Hello, ${data.callerIdentity}!`;
|
326
|
+
}
|
327
|
+
);
|
328
|
+
```
|
329
|
+
|
330
|
+
In addition to the payload, your handler will also receive `responseTimeout`, which informs you the maximum time available to return a response. If you are unable to respond in time, the call will result in an error on the caller's side.
|
331
|
+
|
332
|
+
#### Performing an RPC request
|
333
|
+
|
334
|
+
The caller may then initiate an RPC call like so:
|
335
|
+
|
336
|
+
```typescript
|
337
|
+
try {
|
338
|
+
const response = await room.localParticipant!.performRpc({
|
339
|
+
destinationIdentity: 'recipient-identity',
|
340
|
+
method: 'greet',
|
341
|
+
payload: 'Hello from RPC!',
|
342
|
+
});
|
343
|
+
console.log('RPC response:', response);
|
344
|
+
} catch (error) {
|
345
|
+
console.error('RPC call failed:', error);
|
346
|
+
}
|
347
|
+
```
|
348
|
+
|
349
|
+
You may find it useful to adjust the `responseTimeout` parameter, which indicates the amount of time you will wait for a response. We recommend keeping this value as low as possible while still satisfying the constraints of your application.
|
350
|
+
|
351
|
+
#### Errors
|
352
|
+
|
353
|
+
LiveKit is a dynamic realtime environment and calls can fail for various reasons.
|
354
|
+
|
355
|
+
You may throw errors of the type `RpcError` with a string `message` in an RPC method handler and they will be received on the caller's side with the message intact. Other errors will not be transmitted and will instead arrive to the caller as `1500` ("Application Error"). Other built-in errors are detailed in `RpcError`.
|
356
|
+
|
307
357
|
## Examples
|
308
358
|
|
309
359
|
### Demo App
|
310
360
|
|
311
361
|
[examples/demo](examples/demo/) contains a demo webapp that uses the SDK. Run it with `pnpm install && pnpm examples:demo`
|
312
362
|
|
363
|
+
### RPC Demo
|
364
|
+
|
365
|
+
[examples/rpc](examples/rpc/) contains a demo webapp that uses the SDK to showcase the RPC capabilities. Run it with `pnpm install && pnpm dev` from the `examples/rpc` directory.
|
366
|
+
|
313
367
|
## Browser Support
|
314
368
|
|
315
369
|
| Browser | Desktop OS | Mobile OS |
|
@@ -4746,14 +4746,14 @@ const RpcResponse = /*@__PURE__*/proto3.makeMessageType("livekit.RpcResponse", (
|
|
4746
4746
|
no: 3,
|
4747
4747
|
name: "error",
|
4748
4748
|
kind: "message",
|
4749
|
-
T: RpcError,
|
4749
|
+
T: RpcError$1,
|
4750
4750
|
oneof: "value"
|
4751
4751
|
}]);
|
4752
4752
|
|
4753
4753
|
/**
|
4754
4754
|
* @generated from message livekit.RpcError
|
4755
4755
|
*/
|
4756
|
-
const RpcError = /*@__PURE__*/proto3.makeMessageType("livekit.RpcError", () => [{
|
4756
|
+
const RpcError$1 = /*@__PURE__*/proto3.makeMessageType("livekit.RpcError", () => [{
|
4757
4757
|
no: 1,
|
4758
4758
|
name: "code",
|
4759
4759
|
kind: "scalar",
|
@@ -11176,7 +11176,7 @@ function getOSVersion(ua) {
|
|
11176
11176
|
return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
|
11177
11177
|
}
|
11178
11178
|
|
11179
|
-
var version$1 = "2.
|
11179
|
+
var version$1 = "2.6.0";
|
11180
11180
|
|
11181
11181
|
const version = version$1;
|
11182
11182
|
const protocolVersion = 15;
|
@@ -11836,11 +11836,7 @@ function screenCaptureToDisplayMediaStreamOptions(options) {
|
|
11836
11836
|
};
|
11837
11837
|
}
|
11838
11838
|
function mimeTypeToVideoCodecString(mimeType) {
|
11839
|
-
|
11840
|
-
if (!videoCodecs.includes(codec)) {
|
11841
|
-
throw Error("Video codec not supported: ".concat(codec));
|
11842
|
-
}
|
11843
|
-
return codec;
|
11839
|
+
return mimeType.split('/')[1].toLowerCase();
|
11844
11840
|
}
|
11845
11841
|
function getTrackPublicationInfo(tracks) {
|
11846
11842
|
const infos = [];
|
@@ -14673,6 +14669,7 @@ class PCTransport extends eventsExports.EventEmitter {
|
|
14673
14669
|
var _a;
|
14674
14670
|
super();
|
14675
14671
|
this.log = livekitLogger;
|
14672
|
+
this.ddExtID = 0;
|
14676
14673
|
this.pendingCandidates = [];
|
14677
14674
|
this.restartingIce = false;
|
14678
14675
|
this.renegotiate = false;
|
@@ -14894,7 +14891,7 @@ class PCTransport extends eventsExports.EventEmitter {
|
|
14894
14891
|
return true;
|
14895
14892
|
}
|
14896
14893
|
if (isSVCCodec(trackbr.codec)) {
|
14897
|
-
ensureVideoDDExtensionForSVC(media);
|
14894
|
+
this.ensureVideoDDExtensionForSVC(media, sdpParsed);
|
14898
14895
|
}
|
14899
14896
|
// TODO: av1 slow starting issue already fixed in chrome 124, clean this after some versions
|
14900
14897
|
// mung sdp for av1 bitrate setting that can't apply by sendEncoding
|
@@ -15081,6 +15078,36 @@ class PCTransport extends eventsExports.EventEmitter {
|
|
15081
15078
|
}
|
15082
15079
|
});
|
15083
15080
|
}
|
15081
|
+
ensureVideoDDExtensionForSVC(media, sdp) {
|
15082
|
+
var _a, _b;
|
15083
|
+
const ddFound = (_a = media.ext) === null || _a === void 0 ? void 0 : _a.some(ext => {
|
15084
|
+
if (ext.uri === ddExtensionURI) {
|
15085
|
+
return true;
|
15086
|
+
}
|
15087
|
+
return false;
|
15088
|
+
});
|
15089
|
+
if (!ddFound) {
|
15090
|
+
if (this.ddExtID === 0) {
|
15091
|
+
let maxID = 0;
|
15092
|
+
sdp.media.forEach(m => {
|
15093
|
+
var _a;
|
15094
|
+
if (m.type !== 'video') {
|
15095
|
+
return;
|
15096
|
+
}
|
15097
|
+
(_a = m.ext) === null || _a === void 0 ? void 0 : _a.forEach(ext => {
|
15098
|
+
if (ext.value > maxID) {
|
15099
|
+
maxID = ext.value;
|
15100
|
+
}
|
15101
|
+
});
|
15102
|
+
});
|
15103
|
+
this.ddExtID = maxID + 1;
|
15104
|
+
}
|
15105
|
+
(_b = media.ext) === null || _b === void 0 ? void 0 : _b.push({
|
15106
|
+
value: this.ddExtID,
|
15107
|
+
uri: ddExtensionURI
|
15108
|
+
});
|
15109
|
+
}
|
15110
|
+
}
|
15084
15111
|
}
|
15085
15112
|
function ensureAudioNackAndStereo(media, stereoMids, nackMids) {
|
15086
15113
|
// found opus codec to add nack fb
|
@@ -15116,25 +15143,6 @@ function ensureAudioNackAndStereo(media, stereoMids, nackMids) {
|
|
15116
15143
|
}
|
15117
15144
|
}
|
15118
15145
|
}
|
15119
|
-
function ensureVideoDDExtensionForSVC(media) {
|
15120
|
-
var _a, _b;
|
15121
|
-
let maxID = 0;
|
15122
|
-
const ddFound = (_a = media.ext) === null || _a === void 0 ? void 0 : _a.some(ext => {
|
15123
|
-
if (ext.uri === ddExtensionURI) {
|
15124
|
-
return true;
|
15125
|
-
}
|
15126
|
-
if (ext.value > maxID) {
|
15127
|
-
maxID = ext.value;
|
15128
|
-
}
|
15129
|
-
return false;
|
15130
|
-
});
|
15131
|
-
if (!ddFound) {
|
15132
|
-
(_b = media.ext) === null || _b === void 0 ? void 0 : _b.push({
|
15133
|
-
value: maxID + 1,
|
15134
|
-
uri: ddExtensionURI
|
15135
|
-
});
|
15136
|
-
}
|
15137
|
-
}
|
15138
15146
|
function extractStereoAndNackAudioFromOffer(offer) {
|
15139
15147
|
var _a;
|
15140
15148
|
const stereoMids = [];
|
@@ -17865,6 +17873,120 @@ function getCloudConfigUrl(serverUrl) {
|
|
17865
17873
|
return "".concat(serverUrl.protocol.replace('ws', 'http'), "//").concat(serverUrl.host, "/settings");
|
17866
17874
|
}
|
17867
17875
|
|
17876
|
+
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
17877
|
+
//
|
17878
|
+
// SPDX-License-Identifier: Apache-2.0
|
17879
|
+
/**
|
17880
|
+
* Specialized error handling for RPC methods.
|
17881
|
+
*
|
17882
|
+
* Instances of this type, when thrown in a method handler, will have their `message`
|
17883
|
+
* serialized and sent across the wire. The sender will receive an equivalent error on the other side.
|
17884
|
+
*
|
17885
|
+
* Built-in types are included but developers may use any string, with a max length of 256 bytes.
|
17886
|
+
*/
|
17887
|
+
class RpcError extends Error {
|
17888
|
+
/**
|
17889
|
+
* Creates an error object with the given code and message, plus an optional data payload.
|
17890
|
+
*
|
17891
|
+
* If thrown in an RPC method handler, the error will be sent back to the caller.
|
17892
|
+
*
|
17893
|
+
* Error codes 1001-1999 are reserved for built-in errors (see RpcError.ErrorCode for their meanings).
|
17894
|
+
*/
|
17895
|
+
constructor(code, message, data) {
|
17896
|
+
super(message);
|
17897
|
+
this.code = code;
|
17898
|
+
this.message = truncateBytes(message, RpcError.MAX_MESSAGE_BYTES);
|
17899
|
+
this.data = data ? truncateBytes(data, RpcError.MAX_DATA_BYTES) : undefined;
|
17900
|
+
}
|
17901
|
+
/**
|
17902
|
+
* @internal
|
17903
|
+
*/
|
17904
|
+
static fromProto(proto) {
|
17905
|
+
return new RpcError(proto.code, proto.message, proto.data);
|
17906
|
+
}
|
17907
|
+
/**
|
17908
|
+
* @internal
|
17909
|
+
*/
|
17910
|
+
toProto() {
|
17911
|
+
return new RpcError$1({
|
17912
|
+
code: this.code,
|
17913
|
+
message: this.message,
|
17914
|
+
data: this.data
|
17915
|
+
});
|
17916
|
+
}
|
17917
|
+
/**
|
17918
|
+
* Creates an error object from the code, with an auto-populated message.
|
17919
|
+
*
|
17920
|
+
* @internal
|
17921
|
+
*/
|
17922
|
+
static builtIn(key, data) {
|
17923
|
+
return new RpcError(RpcError.ErrorCode[key], RpcError.ErrorMessage[key], data);
|
17924
|
+
}
|
17925
|
+
}
|
17926
|
+
RpcError.MAX_MESSAGE_BYTES = 256;
|
17927
|
+
RpcError.MAX_DATA_BYTES = 15360; // 15 KB
|
17928
|
+
RpcError.ErrorCode = {
|
17929
|
+
APPLICATION_ERROR: 1500,
|
17930
|
+
CONNECTION_TIMEOUT: 1501,
|
17931
|
+
RESPONSE_TIMEOUT: 1502,
|
17932
|
+
RECIPIENT_DISCONNECTED: 1503,
|
17933
|
+
RESPONSE_PAYLOAD_TOO_LARGE: 1504,
|
17934
|
+
SEND_FAILED: 1505,
|
17935
|
+
UNSUPPORTED_METHOD: 1400,
|
17936
|
+
RECIPIENT_NOT_FOUND: 1401,
|
17937
|
+
REQUEST_PAYLOAD_TOO_LARGE: 1402,
|
17938
|
+
UNSUPPORTED_SERVER: 1403,
|
17939
|
+
UNSUPPORTED_VERSION: 1404
|
17940
|
+
};
|
17941
|
+
/**
|
17942
|
+
* @internal
|
17943
|
+
*/
|
17944
|
+
RpcError.ErrorMessage = {
|
17945
|
+
APPLICATION_ERROR: 'Application error in method handler',
|
17946
|
+
CONNECTION_TIMEOUT: 'Connection timeout',
|
17947
|
+
RESPONSE_TIMEOUT: 'Response timeout',
|
17948
|
+
RECIPIENT_DISCONNECTED: 'Recipient disconnected',
|
17949
|
+
RESPONSE_PAYLOAD_TOO_LARGE: 'Response payload too large',
|
17950
|
+
SEND_FAILED: 'Failed to send',
|
17951
|
+
UNSUPPORTED_METHOD: 'Method not supported at destination',
|
17952
|
+
RECIPIENT_NOT_FOUND: 'Recipient not found',
|
17953
|
+
REQUEST_PAYLOAD_TOO_LARGE: 'Request payload too large',
|
17954
|
+
UNSUPPORTED_SERVER: 'RPC not supported by server',
|
17955
|
+
UNSUPPORTED_VERSION: 'Unsupported RPC version'
|
17956
|
+
};
|
17957
|
+
/*
|
17958
|
+
* Maximum payload size for RPC requests and responses. If a payload exceeds this size,
|
17959
|
+
* the RPC call will fail with a REQUEST_PAYLOAD_TOO_LARGE(1402) or RESPONSE_PAYLOAD_TOO_LARGE(1504) error.
|
17960
|
+
*/
|
17961
|
+
const MAX_PAYLOAD_BYTES = 15360; // 15 KB
|
17962
|
+
/**
|
17963
|
+
* @internal
|
17964
|
+
*/
|
17965
|
+
function byteLength(str) {
|
17966
|
+
const encoder = new TextEncoder();
|
17967
|
+
return encoder.encode(str).length;
|
17968
|
+
}
|
17969
|
+
/**
|
17970
|
+
* @internal
|
17971
|
+
*/
|
17972
|
+
function truncateBytes(str, maxBytes) {
|
17973
|
+
if (byteLength(str) <= maxBytes) {
|
17974
|
+
return str;
|
17975
|
+
}
|
17976
|
+
let low = 0;
|
17977
|
+
let high = str.length;
|
17978
|
+
const encoder = new TextEncoder();
|
17979
|
+
while (low < high) {
|
17980
|
+
const mid = Math.floor((low + high + 1) / 2);
|
17981
|
+
if (encoder.encode(str.slice(0, mid)).length <= maxBytes) {
|
17982
|
+
low = mid;
|
17983
|
+
} else {
|
17984
|
+
high = mid - 1;
|
17985
|
+
}
|
17986
|
+
}
|
17987
|
+
return str.slice(0, low);
|
17988
|
+
}
|
17989
|
+
|
17868
17990
|
class RemoteTrack extends Track {
|
17869
17991
|
constructor(mediaTrack, sid, kind, receiver, loggerOptions) {
|
17870
17992
|
super(mediaTrack, kind, loggerOptions);
|
@@ -19100,6 +19222,9 @@ class LocalParticipant extends Participant {
|
|
19100
19222
|
this.allParticipantsAllowedToSubscribe = true;
|
19101
19223
|
this.encryptionType = Encryption_Type.NONE;
|
19102
19224
|
this.enabledPublishVideoCodecs = [];
|
19225
|
+
this.rpcHandlers = new Map();
|
19226
|
+
this.pendingAcks = new Map();
|
19227
|
+
this.pendingResponses = new Map();
|
19103
19228
|
this.handleReconnecting = () => {
|
19104
19229
|
if (!this.reconnectFuture) {
|
19105
19230
|
this.reconnectFuture = new Future();
|
@@ -19133,6 +19258,29 @@ class LocalParticipant extends Participant {
|
|
19133
19258
|
this.pendingSignalRequests.delete(requestId);
|
19134
19259
|
}
|
19135
19260
|
};
|
19261
|
+
this.handleDataPacket = packet => {
|
19262
|
+
switch (packet.value.case) {
|
19263
|
+
case 'rpcRequest':
|
19264
|
+
let rpcRequest = packet.value.value;
|
19265
|
+
this.handleIncomingRpcRequest(packet.participantIdentity, rpcRequest.id, rpcRequest.method, rpcRequest.payload, rpcRequest.responseTimeoutMs, rpcRequest.version);
|
19266
|
+
break;
|
19267
|
+
case 'rpcResponse':
|
19268
|
+
let rpcResponse = packet.value.value;
|
19269
|
+
let payload = null;
|
19270
|
+
let error = null;
|
19271
|
+
if (rpcResponse.value.case === 'payload') {
|
19272
|
+
payload = rpcResponse.value.value;
|
19273
|
+
} else if (rpcResponse.value.case === 'error') {
|
19274
|
+
error = RpcError.fromProto(rpcResponse.value.value);
|
19275
|
+
}
|
19276
|
+
this.handleIncomingRpcResponse(rpcResponse.requestId, payload, error);
|
19277
|
+
break;
|
19278
|
+
case 'rpcAck':
|
19279
|
+
let rpcAck = packet.value.value;
|
19280
|
+
this.handleIncomingRpcAck(rpcAck.requestId);
|
19281
|
+
break;
|
19282
|
+
}
|
19283
|
+
};
|
19136
19284
|
this.updateTrackSubscriptionPermissions = () => {
|
19137
19285
|
this.log.debug('updating track subscription permissions', Object.assign(Object.assign({}, this.logContext), {
|
19138
19286
|
allParticipantsAllowed: this.allParticipantsAllowedToSubscribe,
|
@@ -19320,7 +19468,7 @@ class LocalParticipant extends Participant {
|
|
19320
19468
|
pub.unmute();
|
19321
19469
|
}
|
19322
19470
|
});
|
19323
|
-
this.engine.on(EngineEvent.Connected, this.handleReconnected).on(EngineEvent.SignalRestarted, this.handleReconnected).on(EngineEvent.SignalResumed, this.handleReconnected).on(EngineEvent.Restarting, this.handleReconnecting).on(EngineEvent.Resuming, this.handleReconnecting).on(EngineEvent.LocalTrackUnpublished, this.handleLocalTrackUnpublished).on(EngineEvent.SubscribedQualityUpdate, this.handleSubscribedQualityUpdate).on(EngineEvent.Disconnected, this.handleDisconnected).on(EngineEvent.SignalRequestResponse, this.handleSignalRequestResponse);
|
19471
|
+
this.engine.on(EngineEvent.Connected, this.handleReconnected).on(EngineEvent.SignalRestarted, this.handleReconnected).on(EngineEvent.SignalResumed, this.handleReconnected).on(EngineEvent.Restarting, this.handleReconnecting).on(EngineEvent.Resuming, this.handleReconnecting).on(EngineEvent.LocalTrackUnpublished, this.handleLocalTrackUnpublished).on(EngineEvent.SubscribedQualityUpdate, this.handleSubscribedQualityUpdate).on(EngineEvent.Disconnected, this.handleDisconnected).on(EngineEvent.SignalRequestResponse, this.handleSignalRequestResponse).on(EngineEvent.DataPacketReceived, this.handleDataPacket);
|
19324
19472
|
}
|
19325
19473
|
/**
|
19326
19474
|
* Sets and updates the metadata of the local participant.
|
@@ -20309,6 +20457,108 @@ class LocalParticipant extends Participant {
|
|
20309
20457
|
return msg;
|
20310
20458
|
});
|
20311
20459
|
}
|
20460
|
+
/**
|
20461
|
+
* Initiate an RPC call to a remote participant
|
20462
|
+
* @param params - Parameters for initiating the RPC call, see {@link PerformRpcParams}
|
20463
|
+
* @returns A promise that resolves with the response payload or rejects with an error.
|
20464
|
+
* @throws Error on failure. Details in `message`.
|
20465
|
+
*/
|
20466
|
+
performRpc(_a) {
|
20467
|
+
return __awaiter(this, arguments, void 0, function (_ref3) {
|
20468
|
+
var _this5 = this;
|
20469
|
+
let {
|
20470
|
+
destinationIdentity,
|
20471
|
+
method,
|
20472
|
+
payload,
|
20473
|
+
responseTimeout = 10000
|
20474
|
+
} = _ref3;
|
20475
|
+
return function* () {
|
20476
|
+
const maxRoundTripLatency = 2000;
|
20477
|
+
return new Promise((resolve, reject) => __awaiter(_this5, void 0, void 0, function* () {
|
20478
|
+
var _a, _b, _c, _d;
|
20479
|
+
if (byteLength(payload) > MAX_PAYLOAD_BYTES) {
|
20480
|
+
reject(RpcError.builtIn('REQUEST_PAYLOAD_TOO_LARGE'));
|
20481
|
+
return;
|
20482
|
+
}
|
20483
|
+
if (((_b = (_a = this.engine.latestJoinResponse) === null || _a === void 0 ? void 0 : _a.serverInfo) === null || _b === void 0 ? void 0 : _b.version) && compareVersions((_d = (_c = this.engine.latestJoinResponse) === null || _c === void 0 ? void 0 : _c.serverInfo) === null || _d === void 0 ? void 0 : _d.version, '1.8.0') < 0) {
|
20484
|
+
reject(RpcError.builtIn('UNSUPPORTED_SERVER'));
|
20485
|
+
return;
|
20486
|
+
}
|
20487
|
+
const id = crypto.randomUUID();
|
20488
|
+
yield this.publishRpcRequest(destinationIdentity, id, method, payload, responseTimeout - maxRoundTripLatency);
|
20489
|
+
const ackTimeoutId = setTimeout(() => {
|
20490
|
+
this.pendingAcks.delete(id);
|
20491
|
+
reject(RpcError.builtIn('CONNECTION_TIMEOUT'));
|
20492
|
+
this.pendingResponses.delete(id);
|
20493
|
+
clearTimeout(responseTimeoutId);
|
20494
|
+
}, maxRoundTripLatency);
|
20495
|
+
this.pendingAcks.set(id, {
|
20496
|
+
resolve: () => {
|
20497
|
+
clearTimeout(ackTimeoutId);
|
20498
|
+
},
|
20499
|
+
participantIdentity: destinationIdentity
|
20500
|
+
});
|
20501
|
+
const responseTimeoutId = setTimeout(() => {
|
20502
|
+
this.pendingResponses.delete(id);
|
20503
|
+
reject(RpcError.builtIn('RESPONSE_TIMEOUT'));
|
20504
|
+
}, responseTimeout);
|
20505
|
+
this.pendingResponses.set(id, {
|
20506
|
+
resolve: (responsePayload, responseError) => {
|
20507
|
+
clearTimeout(responseTimeoutId);
|
20508
|
+
if (this.pendingAcks.has(id)) {
|
20509
|
+
console.warn('RPC response received before ack', id);
|
20510
|
+
this.pendingAcks.delete(id);
|
20511
|
+
clearTimeout(ackTimeoutId);
|
20512
|
+
}
|
20513
|
+
if (responseError) {
|
20514
|
+
reject(responseError);
|
20515
|
+
} else {
|
20516
|
+
resolve(responsePayload !== null && responsePayload !== void 0 ? responsePayload : '');
|
20517
|
+
}
|
20518
|
+
},
|
20519
|
+
participantIdentity: destinationIdentity
|
20520
|
+
});
|
20521
|
+
}));
|
20522
|
+
}();
|
20523
|
+
});
|
20524
|
+
}
|
20525
|
+
/**
|
20526
|
+
* Establishes the participant as a receiver for calls of the specified RPC method.
|
20527
|
+
* Will overwrite any existing callback for the same method.
|
20528
|
+
*
|
20529
|
+
* @param method - The name of the indicated RPC method
|
20530
|
+
* @param handler - Will be invoked when an RPC request for this method is received
|
20531
|
+
* @returns A promise that resolves when the method is successfully registered
|
20532
|
+
*
|
20533
|
+
* @example
|
20534
|
+
* ```typescript
|
20535
|
+
* room.localParticipant?.registerRpcMethod(
|
20536
|
+
* 'greet',
|
20537
|
+
* async (data: RpcInvocationData) => {
|
20538
|
+
* console.log(`Received greeting from ${data.callerIdentity}: ${data.payload}`);
|
20539
|
+
* return `Hello, ${data.callerIdentity}!`;
|
20540
|
+
* }
|
20541
|
+
* );
|
20542
|
+
* ```
|
20543
|
+
*
|
20544
|
+
* The handler should return a Promise that resolves to a string.
|
20545
|
+
* If unable to respond within `responseTimeout`, the request will result in an error on the caller's side.
|
20546
|
+
*
|
20547
|
+
* You may throw errors of type `RpcError` with a string `message` in the handler,
|
20548
|
+
* and they will be received on the caller's side with the message intact.
|
20549
|
+
* Other errors thrown in your handler will not be transmitted as-is, and will instead arrive to the caller as `1500` ("Application Error").
|
20550
|
+
*/
|
20551
|
+
registerRpcMethod(method, handler) {
|
20552
|
+
this.rpcHandlers.set(method, handler);
|
20553
|
+
}
|
20554
|
+
/**
|
20555
|
+
* Unregisters a previously registered RPC method.
|
20556
|
+
*
|
20557
|
+
* @param method - The name of the RPC method to unregister
|
20558
|
+
*/
|
20559
|
+
unregisterRpcMethod(method) {
|
20560
|
+
this.rpcHandlers.delete(method);
|
20561
|
+
}
|
20312
20562
|
/**
|
20313
20563
|
* Control who can subscribe to LocalParticipant's published tracks.
|
20314
20564
|
*
|
@@ -20334,6 +20584,140 @@ class LocalParticipant extends Participant {
|
|
20334
20584
|
this.updateTrackSubscriptionPermissions();
|
20335
20585
|
}
|
20336
20586
|
}
|
20587
|
+
handleIncomingRpcAck(requestId) {
|
20588
|
+
const handler = this.pendingAcks.get(requestId);
|
20589
|
+
if (handler) {
|
20590
|
+
handler.resolve();
|
20591
|
+
this.pendingAcks.delete(requestId);
|
20592
|
+
} else {
|
20593
|
+
console.error('Ack received for unexpected RPC request', requestId);
|
20594
|
+
}
|
20595
|
+
}
|
20596
|
+
handleIncomingRpcResponse(requestId, payload, error) {
|
20597
|
+
const handler = this.pendingResponses.get(requestId);
|
20598
|
+
if (handler) {
|
20599
|
+
handler.resolve(payload, error);
|
20600
|
+
this.pendingResponses.delete(requestId);
|
20601
|
+
} else {
|
20602
|
+
console.error('Response received for unexpected RPC request', requestId);
|
20603
|
+
}
|
20604
|
+
}
|
20605
|
+
handleIncomingRpcRequest(callerIdentity, requestId, method, payload, responseTimeout, version) {
|
20606
|
+
return __awaiter(this, void 0, void 0, function* () {
|
20607
|
+
yield this.publishRpcAck(callerIdentity, requestId);
|
20608
|
+
if (version !== 1) {
|
20609
|
+
yield this.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_VERSION'));
|
20610
|
+
return;
|
20611
|
+
}
|
20612
|
+
const handler = this.rpcHandlers.get(method);
|
20613
|
+
if (!handler) {
|
20614
|
+
yield this.publishRpcResponse(callerIdentity, requestId, null, RpcError.builtIn('UNSUPPORTED_METHOD'));
|
20615
|
+
return;
|
20616
|
+
}
|
20617
|
+
let responseError = null;
|
20618
|
+
let responsePayload = null;
|
20619
|
+
try {
|
20620
|
+
const response = yield handler({
|
20621
|
+
requestId,
|
20622
|
+
callerIdentity,
|
20623
|
+
payload,
|
20624
|
+
responseTimeout
|
20625
|
+
});
|
20626
|
+
if (byteLength(response) > MAX_PAYLOAD_BYTES) {
|
20627
|
+
responseError = RpcError.builtIn('RESPONSE_PAYLOAD_TOO_LARGE');
|
20628
|
+
console.warn("RPC Response payload too large for ".concat(method));
|
20629
|
+
} else {
|
20630
|
+
responsePayload = response;
|
20631
|
+
}
|
20632
|
+
} catch (error) {
|
20633
|
+
if (error instanceof RpcError) {
|
20634
|
+
responseError = error;
|
20635
|
+
} else {
|
20636
|
+
console.warn("Uncaught error returned by RPC handler for ".concat(method, ". Returning APPLICATION_ERROR instead."), error);
|
20637
|
+
responseError = RpcError.builtIn('APPLICATION_ERROR');
|
20638
|
+
}
|
20639
|
+
}
|
20640
|
+
yield this.publishRpcResponse(callerIdentity, requestId, responsePayload, responseError);
|
20641
|
+
});
|
20642
|
+
}
|
20643
|
+
/** @internal */
|
20644
|
+
publishRpcRequest(destinationIdentity, requestId, method, payload, responseTimeout) {
|
20645
|
+
return __awaiter(this, void 0, void 0, function* () {
|
20646
|
+
const packet = new DataPacket({
|
20647
|
+
destinationIdentities: [destinationIdentity],
|
20648
|
+
kind: DataPacket_Kind.RELIABLE,
|
20649
|
+
value: {
|
20650
|
+
case: 'rpcRequest',
|
20651
|
+
value: new RpcRequest({
|
20652
|
+
id: requestId,
|
20653
|
+
method,
|
20654
|
+
payload,
|
20655
|
+
responseTimeoutMs: responseTimeout,
|
20656
|
+
version: 1
|
20657
|
+
})
|
20658
|
+
}
|
20659
|
+
});
|
20660
|
+
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
20661
|
+
});
|
20662
|
+
}
|
20663
|
+
/** @internal */
|
20664
|
+
publishRpcResponse(destinationIdentity, requestId, payload, error) {
|
20665
|
+
return __awaiter(this, void 0, void 0, function* () {
|
20666
|
+
const packet = new DataPacket({
|
20667
|
+
destinationIdentities: [destinationIdentity],
|
20668
|
+
kind: DataPacket_Kind.RELIABLE,
|
20669
|
+
value: {
|
20670
|
+
case: 'rpcResponse',
|
20671
|
+
value: new RpcResponse({
|
20672
|
+
requestId,
|
20673
|
+
value: error ? {
|
20674
|
+
case: 'error',
|
20675
|
+
value: error.toProto()
|
20676
|
+
} : {
|
20677
|
+
case: 'payload',
|
20678
|
+
value: payload !== null && payload !== void 0 ? payload : ''
|
20679
|
+
}
|
20680
|
+
})
|
20681
|
+
}
|
20682
|
+
});
|
20683
|
+
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
20684
|
+
});
|
20685
|
+
}
|
20686
|
+
/** @internal */
|
20687
|
+
publishRpcAck(destinationIdentity, requestId) {
|
20688
|
+
return __awaiter(this, void 0, void 0, function* () {
|
20689
|
+
const packet = new DataPacket({
|
20690
|
+
destinationIdentities: [destinationIdentity],
|
20691
|
+
kind: DataPacket_Kind.RELIABLE,
|
20692
|
+
value: {
|
20693
|
+
case: 'rpcAck',
|
20694
|
+
value: new RpcAck({
|
20695
|
+
requestId
|
20696
|
+
})
|
20697
|
+
}
|
20698
|
+
});
|
20699
|
+
yield this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
|
20700
|
+
});
|
20701
|
+
}
|
20702
|
+
/** @internal */
|
20703
|
+
handleParticipantDisconnected(participantIdentity) {
|
20704
|
+
for (const [id, {
|
20705
|
+
participantIdentity: pendingIdentity
|
20706
|
+
}] of this.pendingAcks) {
|
20707
|
+
if (pendingIdentity === participantIdentity) {
|
20708
|
+
this.pendingAcks.delete(id);
|
20709
|
+
}
|
20710
|
+
}
|
20711
|
+
for (const [id, {
|
20712
|
+
participantIdentity: pendingIdentity,
|
20713
|
+
resolve
|
20714
|
+
}] of this.pendingResponses) {
|
20715
|
+
if (pendingIdentity === participantIdentity) {
|
20716
|
+
resolve(null, RpcError.builtIn('RECIPIENT_DISCONNECTED'));
|
20717
|
+
this.pendingResponses.delete(id);
|
20718
|
+
}
|
20719
|
+
}
|
20720
|
+
}
|
20337
20721
|
/** @internal */
|
20338
20722
|
setEnabledPublishCodecs(codecs) {
|
20339
20723
|
this.enabledPublishVideoCodecs = codecs.filter(c => c.mime.split('/')[0].toLowerCase() === 'video');
|
@@ -20388,8 +20772,8 @@ class LocalParticipant extends Participant {
|
|
20388
20772
|
}
|
20389
20773
|
waitForPendingPublicationOfSource(source) {
|
20390
20774
|
return __awaiter(this, void 0, void 0, function* () {
|
20391
|
-
const publishPromiseEntry = Array.from(this.pendingPublishPromises.entries()).find(
|
20392
|
-
let [pendingTrack] =
|
20775
|
+
const publishPromiseEntry = Array.from(this.pendingPublishPromises.entries()).find(_ref4 => {
|
20776
|
+
let [pendingTrack] = _ref4;
|
20393
20777
|
return pendingTrack.source === source;
|
20394
20778
|
});
|
20395
20779
|
if (publishPromiseEntry) {
|
@@ -22210,6 +22594,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22210
22594
|
}
|
22211
22595
|
}
|
22212
22596
|
handleParticipantDisconnected(identity, participant) {
|
22597
|
+
var _a;
|
22213
22598
|
// remove and send event
|
22214
22599
|
this.remoteParticipants.delete(identity);
|
22215
22600
|
if (!participant) {
|
@@ -22219,6 +22604,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22219
22604
|
participant.unpublishTrack(publication.trackSid, true);
|
22220
22605
|
});
|
22221
22606
|
this.emit(RoomEvent.ParticipantDisconnected, participant);
|
22607
|
+
(_a = this.localParticipant) === null || _a === void 0 ? void 0 : _a.handleParticipantDisconnected(participant.identity);
|
22222
22608
|
}
|
22223
22609
|
acquireAudioContext() {
|
22224
22610
|
return __awaiter(this, void 0, void 0, function* () {
|
@@ -23096,5 +23482,5 @@ function isFacingModeValue(item) {
|
|
23096
23482
|
return item === undefined || allowedValues.includes(item);
|
23097
23483
|
}
|
23098
23484
|
|
23099
|
-
export { AudioPresets, BaseKeyProvider, CheckStatus, Checker, ConnectionCheck, ConnectionError, ConnectionErrorReason, ConnectionQuality, ConnectionState, CriticalTimers, CryptorError, CryptorErrorReason, CryptorEvent, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, LoggerNames, MediaDeviceFailure, h as Mutex, NegotiationError, Participant, ParticipantEvent, ParticipantInfo_Kind as ParticipantKind, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, ScreenSharePresets, SignalRequestError, SubscriptionError, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, compareVersions, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, extractProcessorsFromOptions, facingModeFromDeviceLabel, facingModeFromLocalTrack, getBrowser, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isScriptTransformSupported, isVideoFrame, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
|
23485
|
+
export { AudioPresets, BaseKeyProvider, CheckStatus, Checker, ConnectionCheck, ConnectionError, ConnectionErrorReason, ConnectionQuality, ConnectionState, CriticalTimers, CryptorError, CryptorErrorReason, CryptorEvent, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EncryptionEvent, EngineEvent, ExternalE2EEKeyProvider, KeyHandlerEvent, KeyProviderEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, LoggerNames, MediaDeviceFailure, h as Mutex, NegotiationError, Participant, ParticipantEvent, ParticipantInfo_Kind as ParticipantKind, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, RpcError, ScreenSharePresets, SignalRequestError, SubscriptionError, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, compareVersions, createAudioAnalyser, createE2EEKey, createKeyMaterialFromBuffer, createKeyMaterialFromString, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, deriveKeys, detachTrack, extractProcessorsFromOptions, facingModeFromDeviceLabel, facingModeFromLocalTrack, getBrowser, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, getLogger, importKey, isBackupCodec, isBrowserSupported, isE2EESupported, isInsertableStreamSupported, isScriptTransformSupported, isVideoFrame, needsRbspUnescaping, parseRbsp, protocolVersion, ratchet, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, supportsVP9, version, videoCodecs, writeRbsp };
|
23100
23486
|
//# sourceMappingURL=livekit-client.esm.mjs.map
|