livekit-client 2.3.1 → 2.4.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.
- package/dist/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +14 -7
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +325 -175
- 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/api/SignalClient.d.ts +5 -2
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/Checker.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
- package/dist/src/e2ee/errors.d.ts +2 -1
- package/dist/src/e2ee/errors.d.ts.map +1 -1
- package/dist/src/e2ee/index.d.ts +1 -0
- package/dist/src/e2ee/index.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +1 -2
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +2 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +1 -0
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/errors.d.ts +5 -0
- package/dist/src/room/errors.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +15 -2
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +14 -6
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +8 -0
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/timers.d.ts +4 -4
- package/dist/src/room/timers.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts +1 -0
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/ts4.2/src/api/SignalClient.d.ts +5 -2
- package/dist/ts4.2/src/e2ee/errors.d.ts +2 -1
- package/dist/ts4.2/src/e2ee/index.d.ts +1 -0
- package/dist/ts4.2/src/room/PCTransport.d.ts +1 -2
- package/dist/ts4.2/src/room/RTCEngine.d.ts +2 -1
- package/dist/ts4.2/src/room/Room.d.ts +1 -0
- package/dist/ts4.2/src/room/errors.d.ts +5 -0
- package/dist/ts4.2/src/room/events.d.ts +15 -2
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +14 -6
- package/dist/ts4.2/src/room/participant/Participant.d.ts +8 -0
- package/dist/ts4.2/src/room/timers.d.ts +4 -4
- package/dist/ts4.2/src/room/track/utils.d.ts +1 -0
- package/package.json +12 -12
- package/src/api/SignalClient.ts +24 -2
- package/src/e2ee/errors.ts +8 -1
- package/src/e2ee/index.ts +1 -0
- package/src/e2ee/worker/FrameCryptor.ts +18 -4
- package/src/e2ee/worker/e2ee.worker.ts +5 -1
- package/src/logger.ts +4 -3
- package/src/room/DeviceManager.ts +1 -1
- package/src/room/RTCEngine.ts +3 -0
- package/src/room/Room.ts +11 -3
- package/src/room/errors.ts +11 -0
- package/src/room/events.ts +15 -0
- package/src/room/participant/LocalParticipant.ts +102 -10
- package/src/room/participant/Participant.ts +23 -0
- package/src/room/track/Track.ts +1 -1
- package/src/room/track/utils.test.ts +35 -1
- package/src/room/track/utils.ts +22 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
import { AddTrackRequest, AudioTrackFeature, ConnectionQualityUpdate, JoinResponse, LeaveRequest, ParticipantInfo, ReconnectReason, ReconnectResponse, Room, SessionDescription, SignalRequest, SignalTarget, SimulateScenario, SpeakerInfo, StreamStateUpdate, SubscribedQualityUpdate, SubscriptionPermissionUpdate, SubscriptionResponse, SyncState, TrackPermission, TrackPublishedResponse, TrackUnpublishedResponse, UpdateSubscription, UpdateTrackSettings, VideoLayer } from '@livekit/protocol';
|
1
|
+
import { AddTrackRequest, AudioTrackFeature, ConnectionQualityUpdate, ErrorResponse, JoinResponse, LeaveRequest, ParticipantInfo, ReconnectReason, ReconnectResponse, Room, SessionDescription, SignalRequest, SignalTarget, SimulateScenario, SpeakerInfo, StreamStateUpdate, SubscribedQualityUpdate, SubscriptionPermissionUpdate, SubscriptionResponse, SyncState, TrackPermission, TrackPublishedResponse, TrackUnpublishedResponse, UpdateSubscription, UpdateTrackSettings, VideoLayer } from '@livekit/protocol';
|
2
2
|
import type { LoggerOptions } from '../room/types';
|
3
3
|
import { AsyncQueue } from '../utils/AsyncQueue';
|
4
4
|
interface ConnectOpts extends SignalOptions {
|
@@ -51,11 +51,13 @@ export declare class SignalClient {
|
|
51
51
|
onLocalTrackUnpublished?: (res: TrackUnpublishedResponse) => void;
|
52
52
|
onTokenRefresh?: (token: string) => void;
|
53
53
|
onLeave?: (leave: LeaveRequest) => void;
|
54
|
+
onErrorResponse?: (error: ErrorResponse) => void;
|
54
55
|
connectOptions?: ConnectOpts;
|
55
56
|
ws?: WebSocket;
|
56
57
|
get currentState(): SignalConnectionState;
|
57
58
|
get isDisconnected(): boolean;
|
58
59
|
private get isEstablishingConnection();
|
60
|
+
private getNextRequestId;
|
59
61
|
private options?;
|
60
62
|
private pingTimeout;
|
61
63
|
private pingTimeoutDuration;
|
@@ -66,6 +68,7 @@ export declare class SignalClient {
|
|
66
68
|
private connectionLock;
|
67
69
|
private log;
|
68
70
|
private loggerContextCb?;
|
71
|
+
private _requestId;
|
69
72
|
constructor(useJSON?: boolean, loggerOptions?: LoggerOptions);
|
70
73
|
private get logContext();
|
71
74
|
join(url: string, token: string, opts: SignalOptions, abortSignal?: AbortSignal): Promise<JoinResponse>;
|
@@ -79,7 +82,7 @@ export declare class SignalClient {
|
|
79
82
|
sendIceCandidate(candidate: RTCIceCandidateInit, target: SignalTarget): Promise<void>;
|
80
83
|
sendMuteTrack(trackSid: string, muted: boolean): Promise<void>;
|
81
84
|
sendAddTrack(req: AddTrackRequest): Promise<void>;
|
82
|
-
sendUpdateLocalMetadata(metadata: string, name: string): Promise<
|
85
|
+
sendUpdateLocalMetadata(metadata: string, name: string, attributes?: Record<string, string>): Promise<number>;
|
83
86
|
sendUpdateTrackSettings(settings: UpdateTrackSettings): void;
|
84
87
|
sendUpdateSubscription(sub: UpdateSubscription): Promise<void>;
|
85
88
|
sendSyncState(sync: SyncState): Promise<void>;
|
@@ -6,6 +6,7 @@ export declare enum CryptorErrorReason {
|
|
6
6
|
}
|
7
7
|
export declare class CryptorError extends LivekitError {
|
8
8
|
reason: CryptorErrorReason;
|
9
|
-
|
9
|
+
participantIdentity?: string;
|
10
|
+
constructor(message?: string, reason?: CryptorErrorReason, participantIdentity?: string);
|
10
11
|
}
|
11
12
|
//# sourceMappingURL=errors.d.ts.map
|
@@ -1,4 +1,3 @@
|
|
1
|
-
/// <reference types="node" />
|
2
1
|
import { EventEmitter } from 'events';
|
3
2
|
import type { LoggerOptions } from './types';
|
4
3
|
/** @internal */
|
@@ -43,7 +42,7 @@ export default class PCTransport extends EventEmitter {
|
|
43
42
|
negotiate: {
|
44
43
|
(this: unknown, ...args: [
|
45
44
|
onError?: ((e: Error) => void) | undefined
|
46
|
-
] & any[]): Promise<Promise<void
|
45
|
+
] & any[]): Promise<ReturnType<(onError?: (e: Error) => void) => Promise<void>>>;
|
47
46
|
cancel: (reason?: any) => void;
|
48
47
|
};
|
49
48
|
createAndSendOffer(options?: RTCOfferOptions): Promise<void>;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import type { AddTrackRequest, ConnectionQualityUpdate, JoinResponse, StreamStateUpdate, SubscriptionPermissionUpdate, SubscriptionResponse } from '@livekit/protocol';
|
2
|
-
import { DataPacket, DataPacket_Kind, DisconnectReason, ParticipantInfo, Room as RoomModel, SpeakerInfo, SubscribedQualityUpdate, TrackInfo, TrackUnpublishedResponse, Transcription } from '@livekit/protocol';
|
2
|
+
import { DataPacket, DataPacket_Kind, DisconnectReason, ErrorResponse, ParticipantInfo, Room as RoomModel, SpeakerInfo, SubscribedQualityUpdate, TrackInfo, TrackUnpublishedResponse, Transcription } from '@livekit/protocol';
|
3
3
|
import type TypedEventEmitter from 'typed-emitter';
|
4
4
|
import type { SignalOptions } from '../api/SignalClient';
|
5
5
|
import { SignalClient } from '../api/SignalClient';
|
@@ -156,6 +156,7 @@ export type EngineEventCallbacks = {
|
|
156
156
|
localTrackUnpublished: (unpublishedResponse: TrackUnpublishedResponse) => void;
|
157
157
|
remoteMute: (trackSid: string, muted: boolean) => void;
|
158
158
|
offline: () => void;
|
159
|
+
signalRequestError: (error: ErrorResponse) => void;
|
159
160
|
};
|
160
161
|
export {};
|
161
162
|
//# sourceMappingURL=RTCEngine.d.ts.map
|
@@ -244,6 +244,7 @@ export type RoomEventCallbacks = {
|
|
244
244
|
participantMetadataChanged: (metadata: string | undefined, participant: RemoteParticipant | LocalParticipant) => void;
|
245
245
|
participantNameChanged: (name: string, participant: RemoteParticipant | LocalParticipant) => void;
|
246
246
|
participantPermissionsChanged: (prevPermissions: ParticipantPermission | undefined, participant: RemoteParticipant | LocalParticipant) => void;
|
247
|
+
participantAttributesChanged: (changedAttributes: Record<string, string>, participant: RemoteParticipant | LocalParticipant) => void;
|
247
248
|
activeSpeakersChanged: (speakers: Array<Participant>) => void;
|
248
249
|
roomMetadataChanged: (metadata: string) => void;
|
249
250
|
dataReceived: (payload: Uint8Array, participant?: RemoteParticipant, kind?: DataPacket_Kind, topic?: string) => void;
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { ErrorResponse_Reason } from '@livekit/protocol';
|
1
2
|
export declare class LivekitError extends Error {
|
2
3
|
code: number;
|
3
4
|
constructor(code: number, message?: string);
|
@@ -32,6 +33,10 @@ export declare class NegotiationError extends LivekitError {
|
|
32
33
|
export declare class PublishDataError extends LivekitError {
|
33
34
|
constructor(message?: string);
|
34
35
|
}
|
36
|
+
export declare class SignalRequestError extends LivekitError {
|
37
|
+
reason: ErrorResponse_Reason;
|
38
|
+
constructor(message: string, reason?: ErrorResponse_Reason);
|
39
|
+
}
|
35
40
|
export declare enum MediaDeviceFailure {
|
36
41
|
PermissionDenied = "PermissionDenied",
|
37
42
|
NotFound = "NotFound",
|
@@ -162,6 +162,12 @@ export declare enum RoomEvent {
|
|
162
162
|
*
|
163
163
|
*/
|
164
164
|
ParticipantNameChanged = "participantNameChanged",
|
165
|
+
/**
|
166
|
+
* Participant attributes is an app-specific key value state to be pushed to
|
167
|
+
* all users.
|
168
|
+
* When a participant's attributes changed, this event will be emitted with the changed attributes and the participant
|
169
|
+
*/
|
170
|
+
ParticipantAttributesChanged = "participantAttributesChanged",
|
165
171
|
/**
|
166
172
|
* Room metadata is a simple way for app-specific state to be pushed to
|
167
173
|
* all users.
|
@@ -430,7 +436,13 @@ export declare enum ParticipantEvent {
|
|
430
436
|
*/
|
431
437
|
ParticipantPermissionsChanged = "participantPermissionsChanged",
|
432
438
|
/** @internal */
|
433
|
-
PCTrackAdded = "pcTrackAdded"
|
439
|
+
PCTrackAdded = "pcTrackAdded",
|
440
|
+
/**
|
441
|
+
* Participant attributes is an app-specific key value state to be pushed to
|
442
|
+
* all users.
|
443
|
+
* When a participant's attributes changed, this event will be emitted with the changed attributes
|
444
|
+
*/
|
445
|
+
AttributesChanged = "attributesChanged"
|
434
446
|
}
|
435
447
|
/** @internal */
|
436
448
|
export declare enum EngineEvent {
|
@@ -459,7 +471,8 @@ export declare enum EngineEvent {
|
|
459
471
|
RemoteMute = "remoteMute",
|
460
472
|
SubscribedQualityUpdate = "subscribedQualityUpdate",
|
461
473
|
LocalTrackUnpublished = "localTrackUnpublished",
|
462
|
-
Offline = "offline"
|
474
|
+
Offline = "offline",
|
475
|
+
SignalRequestError = "signalRequestError"
|
463
476
|
}
|
464
477
|
export declare enum TrackEvent {
|
465
478
|
Message = "message",
|
@@ -26,6 +26,7 @@ export default class LocalParticipant extends Participant {
|
|
26
26
|
private roomOptions;
|
27
27
|
private encryptionType;
|
28
28
|
private reconnectFuture?;
|
29
|
+
private pendingSignalRequests;
|
29
30
|
/** @internal */
|
30
31
|
constructor(sid: string, identity: string, engine: RTCEngine, options: InternalRoomOptions);
|
31
32
|
get lastCameraError(): Error | undefined;
|
@@ -40,22 +41,29 @@ export default class LocalParticipant extends Participant {
|
|
40
41
|
private handleReconnecting;
|
41
42
|
private handleReconnected;
|
42
43
|
private handleDisconnected;
|
44
|
+
private handleSignalRequestError;
|
43
45
|
/**
|
44
46
|
* Sets and updates the metadata of the local participant.
|
45
|
-
* The change does not take immediate effect.
|
46
|
-
* If successful, a `ParticipantEvent.MetadataChanged` event will be emitted on the local participant.
|
47
47
|
* Note: this requires `canUpdateOwnMetadata` permission.
|
48
|
+
* method will throw if the user doesn't have the required permissions
|
48
49
|
* @param metadata
|
49
50
|
*/
|
50
|
-
setMetadata(metadata: string): void
|
51
|
+
setMetadata(metadata: string): Promise<void>;
|
51
52
|
/**
|
52
53
|
* Sets and updates the name of the local participant.
|
53
|
-
* The change does not take immediate effect.
|
54
|
-
* If successful, a `ParticipantEvent.ParticipantNameChanged` event will be emitted on the local participant.
|
55
54
|
* Note: this requires `canUpdateOwnMetadata` permission.
|
55
|
+
* method will throw if the user doesn't have the required permissions
|
56
56
|
* @param metadata
|
57
57
|
*/
|
58
|
-
setName(name: string): void
|
58
|
+
setName(name: string): Promise<void>;
|
59
|
+
/**
|
60
|
+
* Set or update participant attributes. It will make updates only to keys that
|
61
|
+
* are present in `attributes`, and will not override others.
|
62
|
+
* Note: this requires `canUpdateOwnMetadata` permission.
|
63
|
+
* @param attributes attributes to update
|
64
|
+
*/
|
65
|
+
setAttributes(attributes: Record<string, string>): Promise<void>;
|
66
|
+
private requestMetadataUpdate;
|
59
67
|
/**
|
60
68
|
* Enable or disable a participant's camera track.
|
61
69
|
*
|
@@ -39,6 +39,7 @@ export default class Participant extends Participant_base {
|
|
39
39
|
name?: string;
|
40
40
|
/** client metadata, opaque to livekit */
|
41
41
|
metadata?: string;
|
42
|
+
private _attributes;
|
42
43
|
lastSpokeAt?: Date | undefined;
|
43
44
|
permissions?: ParticipantPermission;
|
44
45
|
protected _kind: ParticipantKind;
|
@@ -52,6 +53,8 @@ export default class Participant extends Participant_base {
|
|
52
53
|
get isEncrypted(): boolean;
|
53
54
|
get isAgent(): boolean;
|
54
55
|
get kind(): ParticipantKind;
|
56
|
+
/** participant attributes, similar to metadata, but as a key/value map */
|
57
|
+
get attributes(): Readonly<Record<string, string>>;
|
55
58
|
/** @internal */
|
56
59
|
constructor(sid: string, identity: string, name?: string, metadata?: string, loggerOptions?: LoggerOptions, kind?: ParticipantKind);
|
57
60
|
getTrackPublications(): TrackPublication[];
|
@@ -78,6 +81,10 @@ export default class Participant extends Participant_base {
|
|
78
81
|
**/
|
79
82
|
private _setMetadata;
|
80
83
|
private _setName;
|
84
|
+
/**
|
85
|
+
* Updates metadata from server
|
86
|
+
**/
|
87
|
+
private _setAttributes;
|
81
88
|
/** @internal */
|
82
89
|
setPermissions(permissions: ParticipantPermission): boolean;
|
83
90
|
/** @internal */
|
@@ -113,5 +120,6 @@ export type ParticipantEventCallbacks = {
|
|
113
120
|
audioStreamAcquired: () => void;
|
114
121
|
participantPermissionsChanged: (prevPermissions?: ParticipantPermission) => void;
|
115
122
|
trackSubscriptionStatusChanged: (publication: RemoteTrackPublication, status: TrackPublication.SubscriptionStatus) => void;
|
123
|
+
attributesChanged: (changedAttributes: Record<string, string>) => void;
|
116
124
|
};
|
117
125
|
//# sourceMappingURL=Participant.d.ts.map
|
@@ -4,9 +4,9 @@
|
|
4
4
|
* that the timer fires on time.
|
5
5
|
*/
|
6
6
|
export default class CriticalTimers {
|
7
|
-
static setTimeout: (
|
8
|
-
static setInterval: (
|
9
|
-
static clearTimeout: (
|
10
|
-
static clearInterval: (
|
7
|
+
static setTimeout: (callback: (args: void) => void, ms?: number | undefined) => NodeJS.Timeout;
|
8
|
+
static setInterval: (callback: (args: void) => void, ms?: number | undefined) => NodeJS.Timeout;
|
9
|
+
static clearTimeout: (timeoutId: string | number | NodeJS.Timeout | undefined) => void;
|
10
|
+
static clearInterval: (intervalId: string | number | NodeJS.Timeout | undefined) => void;
|
11
11
|
}
|
12
12
|
//# sourceMappingURL=timers.d.ts.map
|
@@ -30,4 +30,5 @@ export declare function mimeTypeToVideoCodecString(mimeType: string): "vp8" | "h
|
|
30
30
|
export declare function getTrackPublicationInfo<T extends TrackPublication>(tracks: T[]): TrackPublishedResponse[];
|
31
31
|
export declare function getLogContextFromTrack(track: Track | TrackPublication): Record<string, unknown>;
|
32
32
|
export declare function supportsSynchronizationSources(): boolean;
|
33
|
+
export declare function diffAttributes(oldValues: Record<string, string> | undefined, newValues: Record<string, string> | undefined): Record<string, string>;
|
33
34
|
//# sourceMappingURL=utils.d.ts.map
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "livekit-client",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.4.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",
|
@@ -36,20 +36,20 @@
|
|
36
36
|
"author": "David Zhao <david@davidzhao.com>",
|
37
37
|
"license": "Apache-2.0",
|
38
38
|
"dependencies": {
|
39
|
-
"@livekit/protocol": "1.
|
39
|
+
"@livekit/protocol": "1.19.1",
|
40
40
|
"events": "^3.3.0",
|
41
41
|
"loglevel": "^1.8.0",
|
42
42
|
"sdp-transform": "^2.14.1",
|
43
43
|
"ts-debounce": "^4.0.0",
|
44
|
-
"tslib": "2.6.
|
44
|
+
"tslib": "2.6.3",
|
45
45
|
"typed-emitter": "^2.1.0",
|
46
|
-
"webrtc-adapter": "^
|
46
|
+
"webrtc-adapter": "^9.0.0"
|
47
47
|
},
|
48
48
|
"devDependencies": {
|
49
|
-
"@babel/core": "7.24.
|
50
|
-
"@babel/preset-env": "7.24.
|
49
|
+
"@babel/core": "7.24.7",
|
50
|
+
"@babel/preset-env": "7.24.7",
|
51
51
|
"@bufbuild/protoc-gen-es": "^1.3.0",
|
52
|
-
"@changesets/cli": "2.27.
|
52
|
+
"@changesets/cli": "2.27.7",
|
53
53
|
"@livekit/changesets-changelog-github": "^0.0.4",
|
54
54
|
"@rollup/plugin-babel": "6.0.4",
|
55
55
|
"@rollup/plugin-commonjs": "25.0.8",
|
@@ -62,8 +62,8 @@
|
|
62
62
|
"@types/events": "^3.0.0",
|
63
63
|
"@types/sdp-transform": "2.4.9",
|
64
64
|
"@types/ua-parser-js": "0.7.39",
|
65
|
-
"@typescript-eslint/eslint-plugin": "7.
|
66
|
-
"@typescript-eslint/parser": "7.
|
65
|
+
"@typescript-eslint/eslint-plugin": "7.15.0",
|
66
|
+
"@typescript-eslint/parser": "7.15.0",
|
67
67
|
"downlevel-dts": "^0.11.0",
|
68
68
|
"eslint": "8.57.0",
|
69
69
|
"eslint-config-airbnb-typescript": "18.0.0",
|
@@ -78,10 +78,10 @@
|
|
78
78
|
"rollup-plugin-re": "1.0.7",
|
79
79
|
"rollup-plugin-typescript2": "0.36.0",
|
80
80
|
"size-limit": "^8.2.4",
|
81
|
-
"typedoc": "0.
|
81
|
+
"typedoc": "0.26.3",
|
82
82
|
"typedoc-plugin-no-inherit": "1.4.0",
|
83
|
-
"typescript": "5.
|
84
|
-
"vite": "5.2
|
83
|
+
"typescript": "5.5.3",
|
84
|
+
"vite": "5.3.2",
|
85
85
|
"vitest": "^1.0.0"
|
86
86
|
},
|
87
87
|
"scripts": {
|
package/src/api/SignalClient.ts
CHANGED
@@ -4,6 +4,7 @@ import {
|
|
4
4
|
ClientInfo,
|
5
5
|
ConnectionQualityUpdate,
|
6
6
|
DisconnectReason,
|
7
|
+
ErrorResponse,
|
7
8
|
JoinResponse,
|
8
9
|
LeaveRequest,
|
9
10
|
LeaveRequest_Action,
|
@@ -141,6 +142,8 @@ export class SignalClient {
|
|
141
142
|
|
142
143
|
onLeave?: (leave: LeaveRequest) => void;
|
143
144
|
|
145
|
+
onErrorResponse?: (error: ErrorResponse) => void;
|
146
|
+
|
144
147
|
connectOptions?: ConnectOpts;
|
145
148
|
|
146
149
|
ws?: WebSocket;
|
@@ -163,6 +166,11 @@ export class SignalClient {
|
|
163
166
|
);
|
164
167
|
}
|
165
168
|
|
169
|
+
private getNextRequestId() {
|
170
|
+
this._requestId += 1;
|
171
|
+
return this._requestId;
|
172
|
+
}
|
173
|
+
|
166
174
|
private options?: SignalOptions;
|
167
175
|
|
168
176
|
private pingTimeout: ReturnType<typeof setTimeout> | undefined;
|
@@ -183,6 +191,8 @@ export class SignalClient {
|
|
183
191
|
|
184
192
|
private loggerContextCb?: LoggerOptions['loggerContextCb'];
|
185
193
|
|
194
|
+
private _requestId = 0;
|
195
|
+
|
186
196
|
constructor(useJSON: boolean = false, loggerOptions: LoggerOptions = {}) {
|
187
197
|
this.log = getLogger(loggerOptions.loggerName ?? LoggerNames.Signal);
|
188
198
|
this.loggerContextCb = loggerOptions.loggerContextCb;
|
@@ -511,14 +521,22 @@ export class SignalClient {
|
|
511
521
|
});
|
512
522
|
}
|
513
523
|
|
514
|
-
sendUpdateLocalMetadata(
|
515
|
-
|
524
|
+
async sendUpdateLocalMetadata(
|
525
|
+
metadata: string,
|
526
|
+
name: string,
|
527
|
+
attributes: Record<string, string> = {},
|
528
|
+
) {
|
529
|
+
const requestId = this.getNextRequestId();
|
530
|
+
await this.sendRequest({
|
516
531
|
case: 'updateMetadata',
|
517
532
|
value: new UpdateParticipantMetadata({
|
533
|
+
requestId,
|
518
534
|
metadata,
|
519
535
|
name,
|
536
|
+
attributes,
|
520
537
|
}),
|
521
538
|
});
|
539
|
+
return requestId;
|
522
540
|
}
|
523
541
|
|
524
542
|
sendUpdateTrackSettings(settings: UpdateTrackSettings) {
|
@@ -721,6 +739,10 @@ export class SignalClient {
|
|
721
739
|
this.rtt = Date.now() - Number.parseInt(msg.value.lastPingTimestamp.toString());
|
722
740
|
this.resetPingTimeout();
|
723
741
|
pingHandled = true;
|
742
|
+
} else if (msg.case === 'errorResponse') {
|
743
|
+
if (this.onErrorResponse) {
|
744
|
+
this.onErrorResponse(msg.value);
|
745
|
+
}
|
724
746
|
} else {
|
725
747
|
this.log.debug('unsupported message', { ...this.logContext, msgCase: msg.case });
|
726
748
|
}
|
package/src/e2ee/errors.ts
CHANGED
@@ -9,8 +9,15 @@ export enum CryptorErrorReason {
|
|
9
9
|
export class CryptorError extends LivekitError {
|
10
10
|
reason: CryptorErrorReason;
|
11
11
|
|
12
|
-
|
12
|
+
participantIdentity?: string;
|
13
|
+
|
14
|
+
constructor(
|
15
|
+
message?: string,
|
16
|
+
reason: CryptorErrorReason = CryptorErrorReason.InternalError,
|
17
|
+
participantIdentity?: string,
|
18
|
+
) {
|
13
19
|
super(40, message);
|
14
20
|
this.reason = reason;
|
21
|
+
this.participantIdentity = participantIdentity;
|
15
22
|
}
|
16
23
|
}
|
package/src/e2ee/index.ts
CHANGED
@@ -183,7 +183,12 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
183
183
|
.pipeTo(writable)
|
184
184
|
.catch((e) => {
|
185
185
|
workerLogger.warn(e);
|
186
|
-
this.emit(
|
186
|
+
this.emit(
|
187
|
+
CryptorEvent.Error,
|
188
|
+
e instanceof CryptorError
|
189
|
+
? e
|
190
|
+
: new CryptorError(e.message, undefined, this.participantIdentity),
|
191
|
+
);
|
187
192
|
});
|
188
193
|
this.trackId = trackId;
|
189
194
|
}
|
@@ -294,10 +299,14 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
294
299
|
workerLogger.error(e);
|
295
300
|
}
|
296
301
|
} else {
|
297
|
-
workerLogger.debug('failed to
|
302
|
+
workerLogger.debug('failed to encrypt, emitting error', this.logContext);
|
298
303
|
this.emit(
|
299
304
|
CryptorEvent.Error,
|
300
|
-
new CryptorError(
|
305
|
+
new CryptorError(
|
306
|
+
`encryption key missing for encoding`,
|
307
|
+
CryptorErrorReason.MissingKey,
|
308
|
+
this.participantIdentity,
|
309
|
+
),
|
301
310
|
);
|
302
311
|
}
|
303
312
|
}
|
@@ -367,6 +376,7 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
367
376
|
new CryptorError(
|
368
377
|
`missing key at index ${keyIndex} for participant ${this.participantIdentity}`,
|
369
378
|
CryptorErrorReason.MissingKey,
|
379
|
+
this.participantIdentity,
|
370
380
|
),
|
371
381
|
);
|
372
382
|
}
|
@@ -487,12 +497,14 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
487
497
|
throw new CryptorError(
|
488
498
|
`valid key missing for participant ${this.participantIdentity}`,
|
489
499
|
CryptorErrorReason.InvalidKey,
|
500
|
+
this.participantIdentity,
|
490
501
|
);
|
491
502
|
}
|
492
503
|
} else {
|
493
504
|
throw new CryptorError(
|
494
505
|
`Decryption failed: ${error.message}`,
|
495
506
|
CryptorErrorReason.InvalidKey,
|
507
|
+
this.participantIdentity,
|
496
508
|
);
|
497
509
|
}
|
498
510
|
}
|
@@ -554,12 +566,14 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
554
566
|
this.detectedCodec = detectedCodec;
|
555
567
|
}
|
556
568
|
|
557
|
-
if (detectedCodec === 'av1'
|
569
|
+
if (detectedCodec === 'av1') {
|
558
570
|
throw new Error(`${detectedCodec} is not yet supported for end to end encryption`);
|
559
571
|
}
|
560
572
|
|
561
573
|
if (detectedCodec === 'vp8') {
|
562
574
|
frameInfo.unencryptedBytes = UNENCRYPTED_BYTES[frame.type];
|
575
|
+
} else if (detectedCodec === 'vp9') {
|
576
|
+
frameInfo.unencryptedBytes = 0;
|
563
577
|
return frameInfo;
|
564
578
|
}
|
565
579
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { workerLogger } from '../../logger';
|
2
|
+
import { VideoCodec } from '../../room/track/options';
|
2
3
|
import { KEY_PROVIDER_DEFAULTS } from '../constants';
|
3
4
|
import { CryptorErrorReason } from '../errors';
|
4
5
|
import { CryptorEvent, KeyHandlerEvent } from '../events';
|
@@ -25,6 +26,8 @@ let sifTrailer: Uint8Array | undefined;
|
|
25
26
|
|
26
27
|
let keyProviderOptions: KeyProviderOptions = KEY_PROVIDER_DEFAULTS;
|
27
28
|
|
29
|
+
let rtpMap: Map<number, VideoCodec> = new Map();
|
30
|
+
|
28
31
|
workerLogger.setDefaultLevel('info');
|
29
32
|
|
30
33
|
onmessage = (ev) => {
|
@@ -91,6 +94,7 @@ onmessage = (ev) => {
|
|
91
94
|
break;
|
92
95
|
case 'setRTPMap':
|
93
96
|
// this is only used for the local participant
|
97
|
+
rtpMap = data.map;
|
94
98
|
participantCryptors.forEach((cr) => {
|
95
99
|
if (cr.getParticipantIdentity() === data.participantIdentity) {
|
96
100
|
cr.setRtpMap(data.map);
|
@@ -149,7 +153,7 @@ function getTrackCryptor(participantIdentity: string, trackId: string) {
|
|
149
153
|
keyProviderOptions,
|
150
154
|
sifTrailer,
|
151
155
|
});
|
152
|
-
|
156
|
+
cryptor.setRtpMap(rtpMap);
|
153
157
|
setupCryptorErrorEvents(cryptor);
|
154
158
|
participantCryptors.push(cryptor);
|
155
159
|
} else if (participantIdentity !== cryptor.getParticipantIdentity()) {
|
package/src/logger.ts
CHANGED
@@ -54,9 +54,10 @@ export function getLogger(name: string) {
|
|
54
54
|
export function setLogLevel(level: LogLevel | LogLevelString, loggerName?: LoggerNames) {
|
55
55
|
if (loggerName) {
|
56
56
|
log.getLogger(loggerName).setLevel(level);
|
57
|
-
}
|
58
|
-
|
59
|
-
|
57
|
+
} else {
|
58
|
+
for (const logger of livekitLoggers) {
|
59
|
+
logger.setLevel(level);
|
60
|
+
}
|
60
61
|
}
|
61
62
|
}
|
62
63
|
|
@@ -41,7 +41,7 @@ export default class DeviceManager {
|
|
41
41
|
!(isSafari() && this.hasDeviceInUse(kind))
|
42
42
|
) {
|
43
43
|
const isDummyDeviceOrEmpty =
|
44
|
-
devices.length === 0 ||
|
44
|
+
devices.filter((d) => d.kind === kind).length === 0 ||
|
45
45
|
devices.some((device) => {
|
46
46
|
const noLabel = device.label === '';
|
47
47
|
const isRelevant = kind ? device.kind === kind : true;
|
package/src/room/RTCEngine.ts
CHANGED
@@ -7,6 +7,7 @@ import {
|
|
7
7
|
DataPacket,
|
8
8
|
DataPacket_Kind,
|
9
9
|
DisconnectReason,
|
10
|
+
ErrorResponse,
|
10
11
|
type JoinResponse,
|
11
12
|
type LeaveRequest,
|
12
13
|
LeaveRequest_Action,
|
@@ -193,6 +194,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
193
194
|
this.emit(EngineEvent.SubscriptionPermissionUpdate, update);
|
194
195
|
this.client.onSpeakersChanged = (update) => this.emit(EngineEvent.SpeakersChanged, update);
|
195
196
|
this.client.onStreamStateUpdate = (update) => this.emit(EngineEvent.StreamStateChanged, update);
|
197
|
+
this.client.onErrorResponse = (error) => this.emit(EngineEvent.SignalRequestError, error);
|
196
198
|
}
|
197
199
|
|
198
200
|
/** @internal */
|
@@ -1412,6 +1414,7 @@ export type EngineEventCallbacks = {
|
|
1412
1414
|
localTrackUnpublished: (unpublishedResponse: TrackUnpublishedResponse) => void;
|
1413
1415
|
remoteMute: (trackSid: string, muted: boolean) => void;
|
1414
1416
|
offline: () => void;
|
1417
|
+
signalRequestError: (error: ErrorResponse) => void;
|
1415
1418
|
};
|
1416
1419
|
|
1417
1420
|
function supportOptionalDatachannel(protocol: number | undefined): boolean {
|
package/src/room/Room.ts
CHANGED
@@ -1407,6 +1407,10 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1407
1407
|
private handleSpeakersChanged = (speakerUpdates: SpeakerInfo[]) => {
|
1408
1408
|
const lastSpeakers = new Map<string, Participant>();
|
1409
1409
|
this.activeSpeakers.forEach((p) => {
|
1410
|
+
const remoteParticipant = this.remoteParticipants.get(p.identity);
|
1411
|
+
if (remoteParticipant && remoteParticipant.sid !== p.sid) {
|
1412
|
+
return;
|
1413
|
+
}
|
1410
1414
|
lastSpeakers.set(p.sid, p);
|
1411
1415
|
});
|
1412
1416
|
speakerUpdates.forEach((speaker) => {
|
@@ -1514,14 +1518,14 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1514
1518
|
bufferedSegments: Map<string, TranscriptionSegmentModel> = new Map();
|
1515
1519
|
|
1516
1520
|
private handleTranscription = (
|
1517
|
-
|
1521
|
+
_remoteParticipant: RemoteParticipant | undefined,
|
1518
1522
|
transcription: TranscriptionModel,
|
1519
1523
|
) => {
|
1520
1524
|
// find the participant
|
1521
1525
|
const participant =
|
1522
|
-
transcription.
|
1526
|
+
transcription.transcribedParticipantIdentity === this.localParticipant.identity
|
1523
1527
|
? this.localParticipant
|
1524
|
-
:
|
1528
|
+
: this.getParticipantByIdentity(transcription.transcribedParticipantIdentity);
|
1525
1529
|
const publication = participant?.trackPublications.get(transcription.trackId);
|
1526
1530
|
|
1527
1531
|
const segments = extractTranscriptionSegments(transcription);
|
@@ -2127,6 +2131,10 @@ export type RoomEventCallbacks = {
|
|
2127
2131
|
prevPermissions: ParticipantPermission | undefined,
|
2128
2132
|
participant: RemoteParticipant | LocalParticipant,
|
2129
2133
|
) => void;
|
2134
|
+
participantAttributesChanged: (
|
2135
|
+
changedAttributes: Record<string, string>,
|
2136
|
+
participant: RemoteParticipant | LocalParticipant,
|
2137
|
+
) => void;
|
2130
2138
|
activeSpeakersChanged: (speakers: Array<Participant>) => void;
|
2131
2139
|
roomMetadataChanged: (metadata: string) => void;
|
2132
2140
|
dataReceived: (
|
package/src/room/errors.ts
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import { ErrorResponse_Reason } from '@livekit/protocol';
|
2
|
+
|
1
3
|
export class LivekitError extends Error {
|
2
4
|
code: number;
|
3
5
|
|
@@ -63,6 +65,15 @@ export class PublishDataError extends LivekitError {
|
|
63
65
|
}
|
64
66
|
}
|
65
67
|
|
68
|
+
export class SignalRequestError extends LivekitError {
|
69
|
+
reason: ErrorResponse_Reason;
|
70
|
+
|
71
|
+
constructor(message: string, reason: ErrorResponse_Reason = ErrorResponse_Reason.UNKNOWN) {
|
72
|
+
super(15, message);
|
73
|
+
this.reason = reason;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
66
77
|
export enum MediaDeviceFailure {
|
67
78
|
// user rejected permissions
|
68
79
|
PermissionDenied = 'PermissionDenied',
|
package/src/room/events.ts
CHANGED
@@ -185,6 +185,13 @@ export enum RoomEvent {
|
|
185
185
|
*/
|
186
186
|
ParticipantNameChanged = 'participantNameChanged',
|
187
187
|
|
188
|
+
/**
|
189
|
+
* Participant attributes is an app-specific key value state to be pushed to
|
190
|
+
* all users.
|
191
|
+
* When a participant's attributes changed, this event will be emitted with the changed attributes and the participant
|
192
|
+
*/
|
193
|
+
ParticipantAttributesChanged = 'participantAttributesChanged',
|
194
|
+
|
188
195
|
/**
|
189
196
|
* Room metadata is a simple way for app-specific state to be pushed to
|
190
197
|
* all users.
|
@@ -495,6 +502,13 @@ export enum ParticipantEvent {
|
|
495
502
|
|
496
503
|
/** @internal */
|
497
504
|
PCTrackAdded = 'pcTrackAdded',
|
505
|
+
|
506
|
+
/**
|
507
|
+
* Participant attributes is an app-specific key value state to be pushed to
|
508
|
+
* all users.
|
509
|
+
* When a participant's attributes changed, this event will be emitted with the changed attributes
|
510
|
+
*/
|
511
|
+
AttributesChanged = 'attributesChanged',
|
498
512
|
}
|
499
513
|
|
500
514
|
/** @internal */
|
@@ -525,6 +539,7 @@ export enum EngineEvent {
|
|
525
539
|
SubscribedQualityUpdate = 'subscribedQualityUpdate',
|
526
540
|
LocalTrackUnpublished = 'localTrackUnpublished',
|
527
541
|
Offline = 'offline',
|
542
|
+
SignalRequestError = 'signalRequestError',
|
528
543
|
}
|
529
544
|
|
530
545
|
export enum TrackEvent {
|