livekit-client 2.4.2 → 2.5.1
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/README.md +8 -4
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +374 -102
- 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 +3 -2
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/publishAudio.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/publishVideo.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +1 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +4 -3
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +5 -0
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/errors.d.ts +4 -3
- package/dist/src/room/errors.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +12 -3
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +5 -2
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +1 -0
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +1 -1
- package/dist/src/room/participant/RemoteParticipant.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/RemoteAudioTrack.d.ts +1 -1
- package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrack.d.ts +12 -2
- package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +1 -1
- package/dist/src/room/types.d.ts +2 -0
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +1 -1
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/ts4.2/src/api/SignalClient.d.ts +3 -2
- package/dist/ts4.2/src/room/PCTransport.d.ts +1 -1
- package/dist/ts4.2/src/room/RTCEngine.d.ts +4 -3
- package/dist/ts4.2/src/room/Room.d.ts +5 -0
- package/dist/ts4.2/src/room/errors.d.ts +4 -3
- package/dist/ts4.2/src/room/events.d.ts +12 -3
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +5 -2
- package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -0
- package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +1 -1
- package/dist/ts4.2/src/room/timers.d.ts +4 -4
- package/dist/ts4.2/src/room/track/RemoteAudioTrack.d.ts +1 -1
- package/dist/ts4.2/src/room/track/RemoteTrack.d.ts +12 -2
- package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +1 -1
- package/dist/ts4.2/src/room/track/options.d.ts +1 -1
- package/dist/ts4.2/src/room/types.d.ts +2 -0
- package/dist/ts4.2/src/room/utils.d.ts +1 -1
- package/dist/ts4.2/src/version.d.ts +1 -1
- package/package.json +10 -10
- package/src/api/SignalClient.ts +12 -6
- package/src/connectionHelper/checks/publishAudio.ts +4 -1
- package/src/connectionHelper/checks/publishVideo.ts +6 -3
- package/src/room/PCTransport.ts +4 -1
- package/src/room/RTCEngine.ts +11 -5
- package/src/room/Room.ts +42 -5
- package/src/room/errors.ts +7 -3
- package/src/room/events.ts +12 -1
- package/src/room/participant/LocalParticipant.ts +125 -84
- package/src/room/participant/Participant.ts +1 -0
- package/src/room/participant/RemoteParticipant.ts +1 -1
- package/src/room/timers.ts +15 -6
- package/src/room/track/LocalVideoTrack.test.ts +60 -0
- package/src/room/track/LocalVideoTrack.ts +1 -1
- package/src/room/track/RemoteAudioTrack.ts +1 -1
- package/src/room/track/RemoteTrack.ts +38 -2
- package/src/room/track/RemoteVideoTrack.ts +2 -2
- package/src/room/track/options.ts +1 -1
- package/src/room/types.ts +2 -0
- package/src/room/utils.ts +10 -0
- package/src/version.ts +1 -1
@@ -1,5 +1,5 @@
|
|
1
1
|
import type { AddTrackRequest, ConnectionQualityUpdate, JoinResponse, StreamStateUpdate, SubscriptionPermissionUpdate, SubscriptionResponse } from '@livekit/protocol';
|
2
|
-
import { DataPacket, DataPacket_Kind, DisconnectReason,
|
2
|
+
import { DataPacket, DataPacket_Kind, DisconnectReason, ParticipantInfo, RequestResponse, 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';
|
@@ -136,7 +136,7 @@ export type EngineEventCallbacks = {
|
|
136
136
|
signalResumed: () => void;
|
137
137
|
signalRestarted: (joinResp: JoinResponse) => void;
|
138
138
|
closing: () => void;
|
139
|
-
mediaTrackAdded: (track: MediaStreamTrack, streams: MediaStream, receiver
|
139
|
+
mediaTrackAdded: (track: MediaStreamTrack, streams: MediaStream, receiver: RTCRtpReceiver) => void;
|
140
140
|
activeSpeakersUpdate: (speakers: Array<SpeakerInfo>) => void;
|
141
141
|
dataPacketReceived: (packet: DataPacket) => void;
|
142
142
|
transcriptionReceived: (transcription: Transcription) => void;
|
@@ -154,9 +154,10 @@ export type EngineEventCallbacks = {
|
|
154
154
|
subscriptionPermissionUpdate: (update: SubscriptionPermissionUpdate) => void;
|
155
155
|
subscribedQualityUpdate: (update: SubscribedQualityUpdate) => void;
|
156
156
|
localTrackUnpublished: (unpublishedResponse: TrackUnpublishedResponse) => void;
|
157
|
+
localTrackSubscribed: (trackSid: string) => void;
|
157
158
|
remoteMute: (trackSid: string, muted: boolean) => void;
|
158
159
|
offline: () => void;
|
159
|
-
|
160
|
+
signalRequestResponse: (response: RequestResponse) => void;
|
160
161
|
};
|
161
162
|
export {};
|
162
163
|
//# sourceMappingURL=RTCEngine.d.ts.map
|
@@ -67,6 +67,10 @@ declare class Room extends Room_base {
|
|
67
67
|
private log;
|
68
68
|
private bufferedEvents;
|
69
69
|
private isResuming;
|
70
|
+
/**
|
71
|
+
* map to store first point in time when a particular transcription segment was received
|
72
|
+
*/
|
73
|
+
private transcriptionReceivedTimes;
|
70
74
|
/**
|
71
75
|
* Creates a new Room, the primary construct for a LiveKit session.
|
72
76
|
* @param options
|
@@ -264,5 +268,6 @@ export type RoomEventCallbacks = {
|
|
264
268
|
encryptionError: (error: Error) => void;
|
265
269
|
dcBufferStatusChanged: (isLow: boolean, kind: DataPacket_Kind) => void;
|
266
270
|
activeDeviceChanged: (kind: MediaDeviceKind, deviceId: string) => void;
|
271
|
+
localTrackSubscribed: (publication: LocalTrackPublication, participant: LocalParticipant) => void;
|
267
272
|
};
|
268
273
|
//# sourceMappingURL=Room.d.ts.map
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { RequestResponse_Reason } from '@livekit/protocol';
|
2
2
|
export declare class LivekitError extends Error {
|
3
3
|
code: number;
|
4
4
|
constructor(code: number, message?: string);
|
@@ -33,9 +33,10 @@ export declare class NegotiationError extends LivekitError {
|
|
33
33
|
export declare class PublishDataError extends LivekitError {
|
34
34
|
constructor(message?: string);
|
35
35
|
}
|
36
|
+
export type RequestErrorReason = Exclude<RequestResponse_Reason, RequestResponse_Reason.OK> | 'TimeoutError';
|
36
37
|
export declare class SignalRequestError extends LivekitError {
|
37
|
-
reason:
|
38
|
-
constructor(message: string, reason
|
38
|
+
reason: RequestErrorReason;
|
39
|
+
constructor(message: string, reason: RequestErrorReason);
|
39
40
|
}
|
40
41
|
export declare enum MediaDeviceFailure {
|
41
42
|
PermissionDenied = "PermissionDenied",
|
@@ -282,7 +282,11 @@ export declare enum RoomEvent {
|
|
282
282
|
* Triggered by a call to room.switchActiveDevice
|
283
283
|
* args: (kind: MediaDeviceKind, deviceId: string)
|
284
284
|
*/
|
285
|
-
ActiveDeviceChanged = "activeDeviceChanged"
|
285
|
+
ActiveDeviceChanged = "activeDeviceChanged",
|
286
|
+
/**
|
287
|
+
* fired when the first remote participant has subscribed to the localParticipant's track
|
288
|
+
*/
|
289
|
+
LocalTrackSubscribed = "localTrackSubscribed"
|
286
290
|
}
|
287
291
|
export declare enum ParticipantEvent {
|
288
292
|
/**
|
@@ -442,7 +446,11 @@ export declare enum ParticipantEvent {
|
|
442
446
|
* all users.
|
443
447
|
* When a participant's attributes changed, this event will be emitted with the changed attributes
|
444
448
|
*/
|
445
|
-
AttributesChanged = "attributesChanged"
|
449
|
+
AttributesChanged = "attributesChanged",
|
450
|
+
/**
|
451
|
+
* fired on local participant only, when the first remote participant has subscribed to the track specified in the payload
|
452
|
+
*/
|
453
|
+
LocalTrackSubscribed = "localTrackSubscribed"
|
446
454
|
}
|
447
455
|
/** @internal */
|
448
456
|
export declare enum EngineEvent {
|
@@ -471,8 +479,9 @@ export declare enum EngineEvent {
|
|
471
479
|
RemoteMute = "remoteMute",
|
472
480
|
SubscribedQualityUpdate = "subscribedQualityUpdate",
|
473
481
|
LocalTrackUnpublished = "localTrackUnpublished",
|
482
|
+
LocalTrackSubscribed = "localTrackSubscribed",
|
474
483
|
Offline = "offline",
|
475
|
-
|
484
|
+
SignalRequestResponse = "signalRequestResponse"
|
476
485
|
}
|
477
486
|
export declare enum TrackEvent {
|
478
487
|
Message = "message",
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ParticipantInfo, ParticipantPermission } from '@livekit/protocol';
|
1
|
+
import { Codec, ParticipantInfo, ParticipantPermission } from '@livekit/protocol';
|
2
2
|
import type { InternalRoomOptions } from '../../options';
|
3
3
|
import type RTCEngine from '../RTCEngine';
|
4
4
|
import LocalTrack from '../track/LocalTrack';
|
@@ -27,6 +27,7 @@ export default class LocalParticipant extends Participant {
|
|
27
27
|
private encryptionType;
|
28
28
|
private reconnectFuture?;
|
29
29
|
private pendingSignalRequests;
|
30
|
+
private enabledPublishVideoCodecs;
|
30
31
|
/** @internal */
|
31
32
|
constructor(sid: string, identity: string, engine: RTCEngine, options: InternalRoomOptions);
|
32
33
|
get lastCameraError(): Error | undefined;
|
@@ -41,7 +42,7 @@ export default class LocalParticipant extends Participant {
|
|
41
42
|
private handleReconnecting;
|
42
43
|
private handleReconnected;
|
43
44
|
private handleDisconnected;
|
44
|
-
private
|
45
|
+
private handleSignalRequestResponse;
|
45
46
|
/**
|
46
47
|
* Sets and updates the metadata of the local participant.
|
47
48
|
* Note: this requires `canUpdateOwnMetadata` permission.
|
@@ -152,6 +153,8 @@ export default class LocalParticipant extends Participant {
|
|
152
153
|
*/
|
153
154
|
setTrackSubscriptionPermissions(allParticipantsAllowed: boolean, participantTrackPermissions?: ParticipantTrackPermission[]): void;
|
154
155
|
/** @internal */
|
156
|
+
setEnabledPublishCodecs(codecs: Codec[]): void;
|
157
|
+
/** @internal */
|
155
158
|
updateInfo(info: ParticipantInfo): boolean;
|
156
159
|
private updateTrackSubscriptionPermissions;
|
157
160
|
/** @internal */
|
@@ -121,5 +121,6 @@ export type ParticipantEventCallbacks = {
|
|
121
121
|
participantPermissionsChanged: (prevPermissions?: ParticipantPermission) => void;
|
122
122
|
trackSubscriptionStatusChanged: (publication: RemoteTrackPublication, status: TrackPublication.SubscriptionStatus) => void;
|
123
123
|
attributesChanged: (changedAttributes: Record<string, string>) => void;
|
124
|
+
localTrackSubscribed: (trackPublication: LocalTrackPublication) => void;
|
124
125
|
};
|
125
126
|
//# sourceMappingURL=Participant.d.ts.map
|
@@ -37,7 +37,7 @@ export default class RemoteParticipant extends Participant {
|
|
37
37
|
*/
|
38
38
|
getVolume(source?: Track.Source.Microphone | Track.Source.ScreenShareAudio): number | undefined;
|
39
39
|
/** @internal */
|
40
|
-
addSubscribedMediaTrack(mediaTrack: MediaStreamTrack, sid: Track.SID, mediaStream: MediaStream, receiver
|
40
|
+
addSubscribedMediaTrack(mediaTrack: MediaStreamTrack, sid: Track.SID, mediaStream: MediaStream, receiver: RTCRtpReceiver, adaptiveStreamSettings?: AdaptiveStreamSettings, triesLeft?: number): RemoteTrackPublication | undefined;
|
41
41
|
/** @internal */
|
42
42
|
get hasMetadata(): boolean;
|
43
43
|
/**
|
@@ -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: (...args: Parameters<typeof setTimeout>) => ReturnType<typeof setTimeout>;
|
8
|
+
static setInterval: (...args: Parameters<typeof setInterval>) => ReturnType<typeof setInterval>;
|
9
|
+
static clearTimeout: (...args: Parameters<typeof clearTimeout>) => ReturnType<typeof clearTimeout>;
|
10
|
+
static clearInterval: (...args: Parameters<typeof clearInterval>) => ReturnType<typeof clearInterval>;
|
11
11
|
}
|
12
12
|
//# sourceMappingURL=timers.d.ts.map
|
@@ -11,7 +11,7 @@ export default class RemoteAudioTrack extends RemoteTrack<Track.Kind.Audio> {
|
|
11
11
|
private sourceNode?;
|
12
12
|
private webAudioPluginNodes;
|
13
13
|
private sinkId?;
|
14
|
-
constructor(mediaTrack: MediaStreamTrack, sid: string, receiver
|
14
|
+
constructor(mediaTrack: MediaStreamTrack, sid: string, receiver: RTCRtpReceiver, audioContext?: AudioContext, audioOutput?: AudioOutputOptions, loggerOptions?: LoggerOptions);
|
15
15
|
/**
|
16
16
|
* sets the volume for all attached audio elements
|
17
17
|
*/
|
@@ -2,8 +2,8 @@ import type { LoggerOptions } from '../types';
|
|
2
2
|
import { Track } from './Track';
|
3
3
|
export default abstract class RemoteTrack<TrackKind extends Track.Kind = Track.Kind> extends Track<TrackKind> {
|
4
4
|
/** @internal */
|
5
|
-
receiver
|
6
|
-
constructor(mediaTrack: MediaStreamTrack, sid: string, kind: TrackKind, receiver
|
5
|
+
receiver: RTCRtpReceiver | undefined;
|
6
|
+
constructor(mediaTrack: MediaStreamTrack, sid: string, kind: TrackKind, receiver: RTCRtpReceiver, loggerOptions?: LoggerOptions);
|
7
7
|
/** @internal */
|
8
8
|
setMuted(muted: boolean): void;
|
9
9
|
/** @internal */
|
@@ -17,6 +17,16 @@ export default abstract class RemoteTrack<TrackKind extends Track.Kind = Track.K
|
|
17
17
|
* @returns Promise<RTCStatsReport> | undefined
|
18
18
|
*/
|
19
19
|
getRTCStatsReport(): Promise<RTCStatsReport | undefined>;
|
20
|
+
/**
|
21
|
+
* Allows to set a playout delay (in seconds) for this track.
|
22
|
+
* A higher value allows for more buffering of the track in the browser
|
23
|
+
* and will result in a delay of media being played back of `delayInSeconds`
|
24
|
+
*/
|
25
|
+
setPlayoutDelay(delayInSeconds: number): void;
|
26
|
+
/**
|
27
|
+
* Returns the current playout delay (in seconds) of this track.
|
28
|
+
*/
|
29
|
+
getPlayoutDelay(): number;
|
20
30
|
startMonitor(): void;
|
21
31
|
protected abstract monitorReceiver(): void;
|
22
32
|
registerTimeSyncUpdate(): void;
|
@@ -8,7 +8,7 @@ export default class RemoteVideoTrack extends RemoteTrack<Track.Kind.Video> {
|
|
8
8
|
private adaptiveStreamSettings?;
|
9
9
|
private lastVisible?;
|
10
10
|
private lastDimensions?;
|
11
|
-
constructor(mediaTrack: MediaStreamTrack, sid: string, receiver
|
11
|
+
constructor(mediaTrack: MediaStreamTrack, sid: string, receiver: RTCRtpReceiver, adaptiveStreamSettings?: AdaptiveStreamSettings, loggerOptions?: LoggerOptions);
|
12
12
|
get isAdaptiveStream(): boolean;
|
13
13
|
/**
|
14
14
|
* Note: When using adaptiveStream, you need to use remoteVideoTrack.attach() to add the track to a HTMLVideoElement, otherwise your video tracks might never start
|
@@ -53,7 +53,7 @@ export interface TrackPublishDefaults {
|
|
53
53
|
*/
|
54
54
|
simulcast?: boolean;
|
55
55
|
/**
|
56
|
-
* scalability mode for svc codecs, defaults to '
|
56
|
+
* scalability mode for svc codecs, defaults to 'L3T3_KEY'.
|
57
57
|
* for svc codecs, simulcast is disabled.
|
58
58
|
*/
|
59
59
|
scalabilityMode?: ScalabilityMode;
|
@@ -95,5 +95,5 @@ export declare function unwrapConstraint(constraint: ConstrainDOMString): string
|
|
95
95
|
export declare function unwrapConstraint(constraint: ConstrainULong): number;
|
96
96
|
export declare function toWebsocketUrl(url: string): string;
|
97
97
|
export declare function toHttpUrl(url: string): string;
|
98
|
-
export declare function extractTranscriptionSegments(transcription: TranscriptionModel): TranscriptionSegment[];
|
98
|
+
export declare function extractTranscriptionSegments(transcription: TranscriptionModel, firstReceivedTimesMap: Map<string, number>): TranscriptionSegment[];
|
99
99
|
//# 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.5.1",
|
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,7 +36,7 @@
|
|
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.20.1",
|
40
40
|
"events": "^3.3.0",
|
41
41
|
"loglevel": "^1.8.0",
|
42
42
|
"sdp-transform": "^2.14.1",
|
@@ -46,8 +46,8 @@
|
|
46
46
|
"webrtc-adapter": "^9.0.0"
|
47
47
|
},
|
48
48
|
"devDependencies": {
|
49
|
-
"@babel/core": "7.
|
50
|
-
"@babel/preset-env": "7.
|
49
|
+
"@babel/core": "7.25.2",
|
50
|
+
"@babel/preset-env": "7.25.3",
|
51
51
|
"@bufbuild/protoc-gen-es": "^1.3.0",
|
52
52
|
"@changesets/cli": "2.27.7",
|
53
53
|
"@livekit/changesets-changelog-github": "^0.0.4",
|
@@ -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.18.0",
|
66
|
+
"@typescript-eslint/parser": "7.18.0",
|
67
67
|
"downlevel-dts": "^0.11.0",
|
68
68
|
"eslint": "8.57.0",
|
69
69
|
"eslint-config-airbnb-typescript": "18.0.0",
|
@@ -73,15 +73,15 @@
|
|
73
73
|
"gh-pages": "6.1.1",
|
74
74
|
"jsdom": "^24.0.0",
|
75
75
|
"prettier": "^3.0.0",
|
76
|
-
"rollup": "4.
|
76
|
+
"rollup": "4.19.2",
|
77
77
|
"rollup-plugin-delete": "^2.0.0",
|
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.26.
|
81
|
+
"typedoc": "0.26.5",
|
82
82
|
"typedoc-plugin-no-inherit": "1.4.0",
|
83
|
-
"typescript": "5.5.
|
84
|
-
"vite": "5.3.
|
83
|
+
"typescript": "5.5.4",
|
84
|
+
"vite": "5.3.5",
|
85
85
|
"vitest": "^1.0.0"
|
86
86
|
},
|
87
87
|
"scripts": {
|
package/src/api/SignalClient.ts
CHANGED
@@ -4,7 +4,6 @@ import {
|
|
4
4
|
ClientInfo,
|
5
5
|
ConnectionQualityUpdate,
|
6
6
|
DisconnectReason,
|
7
|
-
ErrorResponse,
|
8
7
|
JoinResponse,
|
9
8
|
LeaveRequest,
|
10
9
|
LeaveRequest_Action,
|
@@ -13,6 +12,7 @@ import {
|
|
13
12
|
Ping,
|
14
13
|
ReconnectReason,
|
15
14
|
ReconnectResponse,
|
15
|
+
RequestResponse,
|
16
16
|
Room,
|
17
17
|
SessionDescription,
|
18
18
|
SignalRequest,
|
@@ -142,7 +142,9 @@ export class SignalClient {
|
|
142
142
|
|
143
143
|
onLeave?: (leave: LeaveRequest) => void;
|
144
144
|
|
145
|
-
|
145
|
+
onRequestResponse?: (response: RequestResponse) => void;
|
146
|
+
|
147
|
+
onLocalTrackSubscribed?: (trackSid: string) => void;
|
146
148
|
|
147
149
|
connectOptions?: ConnectOpts;
|
148
150
|
|
@@ -440,6 +442,7 @@ export class SignalClient {
|
|
440
442
|
async close(updateState: boolean = true) {
|
441
443
|
const unlock = await this.closingLock.lock();
|
442
444
|
try {
|
445
|
+
this.clearPingInterval();
|
443
446
|
if (updateState) {
|
444
447
|
this.state = SignalConnectionState.DISCONNECTING;
|
445
448
|
}
|
@@ -470,7 +473,6 @@ export class SignalClient {
|
|
470
473
|
if (updateState) {
|
471
474
|
this.state = SignalConnectionState.DISCONNECTED;
|
472
475
|
}
|
473
|
-
this.clearPingInterval();
|
474
476
|
unlock();
|
475
477
|
}
|
476
478
|
}
|
@@ -739,9 +741,13 @@ export class SignalClient {
|
|
739
741
|
this.rtt = Date.now() - Number.parseInt(msg.value.lastPingTimestamp.toString());
|
740
742
|
this.resetPingTimeout();
|
741
743
|
pingHandled = true;
|
742
|
-
} else if (msg.case === '
|
743
|
-
if (this.
|
744
|
-
this.
|
744
|
+
} else if (msg.case === 'requestResponse') {
|
745
|
+
if (this.onRequestResponse) {
|
746
|
+
this.onRequestResponse(msg.value);
|
747
|
+
}
|
748
|
+
} else if (msg.case === 'trackSubscribed') {
|
749
|
+
if (this.onLocalTrackSubscribed) {
|
750
|
+
this.onLocalTrackSubscribed(msg.value.trackSid);
|
745
751
|
}
|
746
752
|
} else {
|
747
753
|
this.log.debug('unsupported message', { ...this.logContext, msgCase: msg.case });
|
@@ -21,7 +21,10 @@ export class PublishAudioCheck extends Checker {
|
|
21
21
|
}
|
22
22
|
let numPackets = 0;
|
23
23
|
stats.forEach((stat) => {
|
24
|
-
if (
|
24
|
+
if (
|
25
|
+
stat.type === 'outbound-rtp' &&
|
26
|
+
(stat.kind === 'audio' || (!stat.kind && stat.mediaType === 'audio'))
|
27
|
+
) {
|
25
28
|
numPackets = stat.packetsSent;
|
26
29
|
}
|
27
30
|
});
|
@@ -12,7 +12,7 @@ export class PublishVideoCheck extends Checker {
|
|
12
12
|
const track = await createLocalVideoTrack();
|
13
13
|
room.localParticipant.publishTrack(track);
|
14
14
|
// wait for a few seconds to publish
|
15
|
-
await new Promise((resolve) => setTimeout(resolve,
|
15
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
16
16
|
|
17
17
|
// verify RTC stats that it's publishing
|
18
18
|
const stats = await track.sender?.getStats();
|
@@ -21,8 +21,11 @@ export class PublishVideoCheck extends Checker {
|
|
21
21
|
}
|
22
22
|
let numPackets = 0;
|
23
23
|
stats.forEach((stat) => {
|
24
|
-
if (
|
25
|
-
|
24
|
+
if (
|
25
|
+
stat.type === 'outbound-rtp' &&
|
26
|
+
(stat.kind === 'video' || (!stat.kind && stat.mediaType === 'video'))
|
27
|
+
) {
|
28
|
+
numPackets += stat.packetsSent;
|
26
29
|
}
|
27
30
|
});
|
28
31
|
if (numPackets === 0) {
|
package/src/room/PCTransport.ts
CHANGED
@@ -23,6 +23,8 @@ eliminate this issue.
|
|
23
23
|
*/
|
24
24
|
const startBitrateForSVC = 0.7;
|
25
25
|
|
26
|
+
const debounceInterval = 20;
|
27
|
+
|
26
28
|
export const PCEvents = {
|
27
29
|
NegotiationStarted: 'negotiationStarted',
|
28
30
|
NegotiationComplete: 'negotiationComplete',
|
@@ -228,7 +230,7 @@ export default class PCTransport extends EventEmitter {
|
|
228
230
|
throw e;
|
229
231
|
}
|
230
232
|
}
|
231
|
-
},
|
233
|
+
}, debounceInterval);
|
232
234
|
|
233
235
|
async createAndSendOffer(options?: RTCOfferOptions) {
|
234
236
|
if (this.onOffer === undefined) {
|
@@ -260,6 +262,7 @@ export default class PCTransport extends EventEmitter {
|
|
260
262
|
// actually negotiate
|
261
263
|
this.log.debug('starting to negotiate', this.logContext);
|
262
264
|
const offer = await this.pc.createOffer(options);
|
265
|
+
this.log.debug('original offer', { sdp: offer.sdp, ...this.logContext });
|
263
266
|
|
264
267
|
const sdpParsed = parse(offer.sdp ?? '');
|
265
268
|
sdpParsed.media.forEach((media) => {
|
package/src/room/RTCEngine.ts
CHANGED
@@ -7,13 +7,13 @@ import {
|
|
7
7
|
DataPacket,
|
8
8
|
DataPacket_Kind,
|
9
9
|
DisconnectReason,
|
10
|
-
ErrorResponse,
|
11
10
|
type JoinResponse,
|
12
11
|
type LeaveRequest,
|
13
12
|
LeaveRequest_Action,
|
14
13
|
ParticipantInfo,
|
15
14
|
ReconnectReason,
|
16
15
|
type ReconnectResponse,
|
16
|
+
RequestResponse,
|
17
17
|
Room as RoomModel,
|
18
18
|
SignalTarget,
|
19
19
|
SpeakerInfo,
|
@@ -194,7 +194,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
194
194
|
this.emit(EngineEvent.SubscriptionPermissionUpdate, update);
|
195
195
|
this.client.onSpeakersChanged = (update) => this.emit(EngineEvent.SpeakersChanged, update);
|
196
196
|
this.client.onStreamStateUpdate = (update) => this.emit(EngineEvent.StreamStateChanged, update);
|
197
|
-
this.client.
|
197
|
+
this.client.onRequestResponse = (response) =>
|
198
|
+
this.emit(EngineEvent.SignalRequestResponse, response);
|
198
199
|
}
|
199
200
|
|
200
201
|
/** @internal */
|
@@ -231,7 +232,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
231
232
|
}
|
232
233
|
|
233
234
|
// create offer
|
234
|
-
if (!this.subscriberPrimary) {
|
235
|
+
if (!this.subscriberPrimary || joinResponse.fastPublish) {
|
235
236
|
this.negotiate();
|
236
237
|
}
|
237
238
|
|
@@ -493,6 +494,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
493
494
|
this.emit(EngineEvent.LocalTrackUnpublished, response);
|
494
495
|
};
|
495
496
|
|
497
|
+
this.client.onLocalTrackSubscribed = (trackSid: string) => {
|
498
|
+
this.emit(EngineEvent.LocalTrackSubscribed, trackSid);
|
499
|
+
};
|
500
|
+
|
496
501
|
this.client.onTokenRefresh = (token: string) => {
|
497
502
|
this.token = token;
|
498
503
|
};
|
@@ -1393,7 +1398,7 @@ export type EngineEventCallbacks = {
|
|
1393
1398
|
mediaTrackAdded: (
|
1394
1399
|
track: MediaStreamTrack,
|
1395
1400
|
streams: MediaStream,
|
1396
|
-
receiver
|
1401
|
+
receiver: RTCRtpReceiver,
|
1397
1402
|
) => void;
|
1398
1403
|
activeSpeakersUpdate: (speakers: Array<SpeakerInfo>) => void;
|
1399
1404
|
dataPacketReceived: (packet: DataPacket) => void;
|
@@ -1412,9 +1417,10 @@ export type EngineEventCallbacks = {
|
|
1412
1417
|
subscriptionPermissionUpdate: (update: SubscriptionPermissionUpdate) => void;
|
1413
1418
|
subscribedQualityUpdate: (update: SubscribedQualityUpdate) => void;
|
1414
1419
|
localTrackUnpublished: (unpublishedResponse: TrackUnpublishedResponse) => void;
|
1420
|
+
localTrackSubscribed: (trackSid: string) => void;
|
1415
1421
|
remoteMute: (trackSid: string, muted: boolean) => void;
|
1416
1422
|
offline: () => void;
|
1417
|
-
|
1423
|
+
signalRequestResponse: (response: RequestResponse) => void;
|
1418
1424
|
};
|
1419
1425
|
|
1420
1426
|
function supportOptionalDatachannel(protocol: number | undefined): boolean {
|
package/src/room/Room.ts
CHANGED
@@ -162,6 +162,11 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
162
162
|
|
163
163
|
private isResuming: boolean = false;
|
164
164
|
|
165
|
+
/**
|
166
|
+
* map to store first point in time when a particular transcription segment was received
|
167
|
+
*/
|
168
|
+
private transcriptionReceivedTimes: Map<string, number>;
|
169
|
+
|
165
170
|
/**
|
166
171
|
* Creates a new Room, the primary construct for a LiveKit session.
|
167
172
|
* @param options
|
@@ -174,6 +179,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
174
179
|
this.options = { ...roomOptionDefaults, ...options };
|
175
180
|
|
176
181
|
this.log = getLogger(this.options.loggerName ?? LoggerNames.Room);
|
182
|
+
this.transcriptionReceivedTimes = new Map();
|
177
183
|
|
178
184
|
this.options.audioCaptureDefaults = {
|
179
185
|
...audioDefaults,
|
@@ -328,7 +334,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
328
334
|
.on(EngineEvent.SubscriptionPermissionUpdate, this.handleSubscriptionPermissionUpdate)
|
329
335
|
.on(
|
330
336
|
EngineEvent.MediaTrackAdded,
|
331
|
-
(mediaTrack: MediaStreamTrack, stream: MediaStream, receiver
|
337
|
+
(mediaTrack: MediaStreamTrack, stream: MediaStream, receiver: RTCRtpReceiver) => {
|
332
338
|
this.onTrackAdded(mediaTrack, stream, receiver);
|
333
339
|
},
|
334
340
|
)
|
@@ -370,6 +376,24 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
370
376
|
})
|
371
377
|
.on(EngineEvent.DCBufferStatusChanged, (status, kind) => {
|
372
378
|
this.emit(RoomEvent.DCBufferStatusChanged, status, kind);
|
379
|
+
})
|
380
|
+
.on(EngineEvent.LocalTrackSubscribed, (subscribedSid) => {
|
381
|
+
const trackPublication = this.localParticipant
|
382
|
+
.getTrackPublications()
|
383
|
+
.find(({ trackSid }) => trackSid === subscribedSid) as LocalTrackPublication | undefined;
|
384
|
+
if (!trackPublication) {
|
385
|
+
this.log.warn(
|
386
|
+
'could not find local track subscription for subscribed event',
|
387
|
+
this.logContext,
|
388
|
+
);
|
389
|
+
return;
|
390
|
+
}
|
391
|
+
this.localParticipant.emit(ParticipantEvent.LocalTrackSubscribed, trackPublication);
|
392
|
+
this.emitWhenConnected(
|
393
|
+
RoomEvent.LocalTrackSubscribed,
|
394
|
+
trackPublication,
|
395
|
+
this.localParticipant,
|
396
|
+
);
|
373
397
|
});
|
374
398
|
|
375
399
|
if (this.localParticipant) {
|
@@ -608,6 +632,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
608
632
|
|
609
633
|
this.localParticipant.sid = pi.sid;
|
610
634
|
this.localParticipant.identity = pi.identity;
|
635
|
+
this.localParticipant.setEnabledPublishCodecs(joinResponse.enabledPublishCodecs);
|
611
636
|
|
612
637
|
if (this.options.e2ee && this.e2eeManager) {
|
613
638
|
try {
|
@@ -1152,7 +1177,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1152
1177
|
private onTrackAdded(
|
1153
1178
|
mediaTrack: MediaStreamTrack,
|
1154
1179
|
stream: MediaStream,
|
1155
|
-
receiver
|
1180
|
+
receiver: RTCRtpReceiver,
|
1156
1181
|
) {
|
1157
1182
|
// don't fire onSubscribed when connecting
|
1158
1183
|
// WebRTC fires onTrack as soon as setRemoteDescription is called on the offer
|
@@ -1274,6 +1299,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1274
1299
|
this.clearConnectionReconcile();
|
1275
1300
|
this.isResuming = false;
|
1276
1301
|
this.bufferedEvents = [];
|
1302
|
+
this.transcriptionReceivedTimes.clear();
|
1277
1303
|
if (this.state === ConnectionState.Disconnected) {
|
1278
1304
|
return;
|
1279
1305
|
}
|
@@ -1535,7 +1561,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1535
1561
|
: this.getParticipantByIdentity(transcription.transcribedParticipantIdentity);
|
1536
1562
|
const publication = participant?.trackPublications.get(transcription.trackId);
|
1537
1563
|
|
1538
|
-
const segments = extractTranscriptionSegments(transcription);
|
1564
|
+
const segments = extractTranscriptionSegments(transcription, this.transcriptionReceivedTimes);
|
1539
1565
|
|
1540
1566
|
publication?.emit(TrackEvent.TranscriptionReceived, segments);
|
1541
1567
|
participant?.emit(ParticipantEvent.TranscriptionReceived, segments, publication);
|
@@ -2055,7 +2081,12 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
2055
2081
|
sid: Math.floor(Math.random() * 10_000).toString(),
|
2056
2082
|
type: TrackType.AUDIO,
|
2057
2083
|
});
|
2058
|
-
p.addSubscribedMediaTrack(
|
2084
|
+
p.addSubscribedMediaTrack(
|
2085
|
+
dummyVideo,
|
2086
|
+
videoTrack.sid,
|
2087
|
+
new MediaStream([dummyVideo]),
|
2088
|
+
new RTCRtpReceiver(),
|
2089
|
+
);
|
2059
2090
|
info.tracks = [...info.tracks, videoTrack];
|
2060
2091
|
}
|
2061
2092
|
if (participantOptions.audio) {
|
@@ -2065,7 +2096,12 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
2065
2096
|
sid: Math.floor(Math.random() * 10_000).toString(),
|
2066
2097
|
type: TrackType.AUDIO,
|
2067
2098
|
});
|
2068
|
-
p.addSubscribedMediaTrack(
|
2099
|
+
p.addSubscribedMediaTrack(
|
2100
|
+
dummyTrack,
|
2101
|
+
audioTrack.sid,
|
2102
|
+
new MediaStream([dummyTrack]),
|
2103
|
+
new RTCRtpReceiver(),
|
2104
|
+
);
|
2069
2105
|
info.tracks = [...info.tracks, audioTrack];
|
2070
2106
|
}
|
2071
2107
|
|
@@ -2192,4 +2228,5 @@ export type RoomEventCallbacks = {
|
|
2192
2228
|
encryptionError: (error: Error) => void;
|
2193
2229
|
dcBufferStatusChanged: (isLow: boolean, kind: DataPacket_Kind) => void;
|
2194
2230
|
activeDeviceChanged: (kind: MediaDeviceKind, deviceId: string) => void;
|
2231
|
+
localTrackSubscribed: (publication: LocalTrackPublication, participant: LocalParticipant) => void;
|
2195
2232
|
};
|
package/src/room/errors.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { RequestResponse_Reason } from '@livekit/protocol';
|
2
2
|
|
3
3
|
export class LivekitError extends Error {
|
4
4
|
code: number;
|
@@ -65,10 +65,14 @@ export class PublishDataError extends LivekitError {
|
|
65
65
|
}
|
66
66
|
}
|
67
67
|
|
68
|
+
export type RequestErrorReason =
|
69
|
+
| Exclude<RequestResponse_Reason, RequestResponse_Reason.OK>
|
70
|
+
| 'TimeoutError';
|
71
|
+
|
68
72
|
export class SignalRequestError extends LivekitError {
|
69
|
-
reason:
|
73
|
+
reason: RequestErrorReason;
|
70
74
|
|
71
|
-
constructor(message: string, reason:
|
75
|
+
constructor(message: string, reason: RequestErrorReason) {
|
72
76
|
super(15, message);
|
73
77
|
this.reason = reason;
|
74
78
|
}
|