livekit-client 1.5.0 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/livekit-client.esm.mjs +2257 -5488
- 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/ConnectionCheck.d.ts +1 -1
- package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/Checker.d.ts +4 -4
- package/dist/src/connectionHelper/checks/Checker.d.ts.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/logger.d.ts +3 -3
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/options.d.ts +4 -1
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/proto/google/protobuf/timestamp.d.ts +4 -4
- package/dist/src/proto/google/protobuf/timestamp.d.ts.map +1 -1
- package/dist/src/proto/livekit_models.d.ts +4 -4
- package/dist/src/proto/livekit_models.d.ts.map +1 -1
- package/dist/src/proto/livekit_rtc.d.ts +4 -4
- package/dist/src/proto/livekit_rtc.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +7 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +10 -4
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +21 -4
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +5 -0
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +3 -2
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +1 -1
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +1 -0
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +2 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/TrackPublication.d.ts +1 -1
- package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +3 -3
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/types.d.ts +3 -3
- package/dist/src/room/track/types.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +13 -0
- package/dist/src/room/types.d.ts.map +1 -0
- package/dist/src/room/utils.d.ts +44 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/ts4.2/src/api/SignalClient.d.ts +3 -2
- package/dist/ts4.2/src/connectionHelper/ConnectionCheck.d.ts +1 -1
- package/dist/ts4.2/src/connectionHelper/checks/Checker.d.ts +4 -4
- package/dist/ts4.2/src/index.d.ts +3 -2
- package/dist/ts4.2/src/logger.d.ts +3 -3
- package/dist/ts4.2/src/options.d.ts +4 -1
- package/dist/ts4.2/src/proto/google/protobuf/timestamp.d.ts +4 -4
- package/dist/ts4.2/src/proto/livekit_models.d.ts +4 -4
- package/dist/ts4.2/src/proto/livekit_rtc.d.ts +4 -4
- package/dist/ts4.2/src/room/PCTransport.d.ts +7 -1
- package/dist/ts4.2/src/room/RTCEngine.d.ts +10 -4
- package/dist/ts4.2/src/room/Room.d.ts +21 -4
- package/dist/ts4.2/src/room/events.d.ts +5 -0
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +3 -2
- package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -1
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +1 -0
- package/dist/ts4.2/src/room/track/Track.d.ts +2 -1
- package/dist/ts4.2/src/room/track/TrackPublication.d.ts +1 -1
- package/dist/ts4.2/src/room/track/options.d.ts +3 -3
- package/dist/ts4.2/src/room/track/types.d.ts +3 -3
- package/dist/ts4.2/src/room/types.d.ts +13 -0
- package/dist/ts4.2/src/room/utils.d.ts +44 -0
- package/package.json +23 -23
- package/src/api/SignalClient.ts +40 -16
- package/src/connectionHelper/checks/turn.ts +1 -1
- package/src/connectionHelper/checks/websocket.ts +1 -1
- package/src/index.ts +5 -0
- package/src/options.ts +5 -1
- package/src/room/PCTransport.ts +11 -1
- package/src/room/RTCEngine.ts +111 -49
- package/src/room/Room.ts +234 -63
- package/src/room/events.ts +5 -0
- package/src/room/participant/LocalParticipant.ts +46 -22
- package/src/room/participant/RemoteParticipant.ts +5 -5
- package/src/room/participant/publishUtils.ts +1 -1
- package/src/room/track/LocalAudioTrack.ts +1 -1
- package/src/room/track/LocalTrack.ts +20 -1
- package/src/room/track/LocalVideoTrack.ts +1 -1
- package/src/room/track/RemoteVideoTrack.ts +4 -0
- package/src/room/track/Track.ts +22 -5
- package/src/room/types.ts +12 -0
- package/src/room/utils.ts +150 -12
@@ -44,9 +44,10 @@ export default class RTCEngine extends RTCEngine_base {
|
|
44
44
|
private joinAttempts;
|
45
45
|
/** specifies how often an initial join connection is allowed to retry */
|
46
46
|
private maxJoinAttempts;
|
47
|
+
private closingLock;
|
47
48
|
constructor(options: InternalRoomOptions);
|
48
49
|
join(url: string, token: string, opts: SignalOptions, abortSignal?: AbortSignal): Promise<JoinResponse>;
|
49
|
-
close(): void
|
50
|
+
close(): Promise<void>;
|
50
51
|
addTrack(req: AddTrackRequest): Promise<TrackInfo>;
|
51
52
|
removeTrack(sender: RTCRtpSender): void;
|
52
53
|
updateMuteStatus(trackSid: string, muted: boolean): void;
|
@@ -70,23 +71,28 @@ export default class RTCEngine extends RTCEngine_base {
|
|
70
71
|
private resumeConnection;
|
71
72
|
waitForPCConnected(): Promise<void>;
|
72
73
|
sendDataPacket(packet: DataPacket, kind: DataPacket_Kind): Promise<void>;
|
74
|
+
/**
|
75
|
+
* @internal
|
76
|
+
*/
|
77
|
+
ensureDataTransportConnected(kind: DataPacket_Kind, subscriber?: boolean): Promise<void>;
|
73
78
|
private ensurePublisherConnected;
|
74
79
|
/** @internal */
|
75
|
-
negotiate(): void
|
80
|
+
negotiate(): Promise<void>;
|
76
81
|
dataChannelForKind(kind: DataPacket_Kind, sub?: boolean): RTCDataChannel | undefined;
|
77
82
|
private clearPendingReconnect;
|
78
83
|
private handleBrowserOnLine;
|
79
84
|
private registerOnLineListener;
|
80
85
|
private deregisterOnLineListener;
|
81
86
|
}
|
82
|
-
export
|
83
|
-
connected: () => void;
|
87
|
+
export type EngineEventCallbacks = {
|
88
|
+
connected: (joinResp: JoinResponse) => void;
|
84
89
|
disconnected: (reason?: DisconnectReason) => void;
|
85
90
|
resuming: () => void;
|
86
91
|
resumed: () => void;
|
87
92
|
restarting: () => void;
|
88
93
|
restarted: (joinResp: JoinResponse) => void;
|
89
94
|
signalResumed: () => void;
|
95
|
+
closing: () => void;
|
90
96
|
mediaTrackAdded: (track: MediaStreamTrack, streams: MediaStream, receiver?: RTCRtpReceiver) => void;
|
91
97
|
activeSpeakersUpdate: (speakers: Array<SpeakerInfo>) => void;
|
92
98
|
dataPacketReceived: (userPacket: UserPacket, kind: DataPacket_Kind) => void;
|
@@ -6,11 +6,12 @@ import type Participant from './participant/Participant';
|
|
6
6
|
import type { ConnectionQuality } from './participant/Participant';
|
7
7
|
import RemoteParticipant from './participant/RemoteParticipant';
|
8
8
|
import RTCEngine from './RTCEngine';
|
9
|
-
import
|
9
|
+
import LocalTrackPublication from './track/LocalTrackPublication';
|
10
10
|
import type RemoteTrack from './track/RemoteTrack';
|
11
11
|
import RemoteTrackPublication from './track/RemoteTrackPublication';
|
12
12
|
import { Track } from './track/Track';
|
13
13
|
import type { TrackPublication } from './track/TrackPublication';
|
14
|
+
import type { SimulationOptions } from './types';
|
14
15
|
export declare enum ConnectionState {
|
15
16
|
Disconnected = "disconnected",
|
16
17
|
Connecting = "connecting",
|
@@ -59,6 +60,7 @@ declare class Room extends Room_base {
|
|
59
60
|
private abortController?;
|
60
61
|
/** future holding client initiated connection attempt */
|
61
62
|
private connectFuture?;
|
63
|
+
private disconnectLock;
|
62
64
|
/**
|
63
65
|
* Creates a new Room, the primary construct for a LiveKit session.
|
64
66
|
* @param options
|
@@ -102,7 +104,7 @@ declare class Room extends Room_base {
|
|
102
104
|
/**
|
103
105
|
* @internal for testing
|
104
106
|
*/
|
105
|
-
simulateScenario(scenario: string): void
|
107
|
+
simulateScenario(scenario: string): Promise<void>;
|
106
108
|
private onBeforeUnload;
|
107
109
|
/**
|
108
110
|
* Browsers have different policies regarding audio playback. Most requiring
|
@@ -117,7 +119,15 @@ declare class Room extends Room_base {
|
|
117
119
|
*/
|
118
120
|
get canPlaybackAudio(): boolean;
|
119
121
|
/**
|
120
|
-
*
|
122
|
+
* Returns the active audio output device used in this room.
|
123
|
+
*
|
124
|
+
* Note: to get the active `audioinput` or `videoinput` use [[LocalTrack.getDeviceId()]]
|
125
|
+
*
|
126
|
+
* @return the previously successfully set audio output device ID or an empty string if the default device is used.
|
127
|
+
*/
|
128
|
+
getActiveAudioOutputDevice(): string;
|
129
|
+
/**
|
130
|
+
* Switches all active devices used in this room to the given device.
|
121
131
|
*
|
122
132
|
* Note: setting AudioOutput is not supported on some browsers. See [setSinkId](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId#browser_compatibility)
|
123
133
|
*
|
@@ -127,6 +137,7 @@ declare class Room extends Room_base {
|
|
127
137
|
* @param deviceId
|
128
138
|
*/
|
129
139
|
switchActiveDevice(kind: MediaDeviceKind, deviceId: string): Promise<void>;
|
140
|
+
private setupLocalParticipantEvents;
|
130
141
|
private recreateEngine;
|
131
142
|
private onTrackAdded;
|
132
143
|
private handleRestarting;
|
@@ -163,10 +174,16 @@ declare class Room extends Room_base {
|
|
163
174
|
private onLocalConnectionQualityChanged;
|
164
175
|
private onMediaDevicesError;
|
165
176
|
private onLocalParticipantPermissionsChanged;
|
177
|
+
/**
|
178
|
+
* Allows to populate a room with simulated participants.
|
179
|
+
* No actual connection to a server will be established, all state is
|
180
|
+
* @experimental
|
181
|
+
*/
|
182
|
+
simulateParticipants(options: SimulationOptions): void;
|
166
183
|
emit<E extends keyof RoomEventCallbacks>(event: E, ...args: Parameters<RoomEventCallbacks[E]>): boolean;
|
167
184
|
}
|
168
185
|
export default Room;
|
169
|
-
export
|
186
|
+
export type RoomEventCallbacks = {
|
170
187
|
connected: () => void;
|
171
188
|
reconnecting: () => void;
|
172
189
|
reconnected: () => void;
|
@@ -367,6 +367,7 @@ export declare enum EngineEvent {
|
|
367
367
|
Restarting = "restarting",
|
368
368
|
Restarted = "restarted",
|
369
369
|
SignalResumed = "signalResumed",
|
370
|
+
Closing = "closing",
|
370
371
|
MediaTrackAdded = "mediaTrackAdded",
|
371
372
|
ActiveSpeakersUpdate = "activeSpeakersUpdate",
|
372
373
|
DataPacketReceived = "dataPacketReceived"
|
@@ -375,6 +376,10 @@ export declare enum TrackEvent {
|
|
375
376
|
Message = "message",
|
376
377
|
Muted = "muted",
|
377
378
|
Unmuted = "unmuted",
|
379
|
+
/**
|
380
|
+
* Only fires on LocalTracks
|
381
|
+
*/
|
382
|
+
Restarted = "restarted",
|
378
383
|
Ended = "ended",
|
379
384
|
Subscribed = "subscribed",
|
380
385
|
Unsubscribed = "unsubscribed",
|
@@ -88,8 +88,9 @@ export default class LocalParticipant extends Participant {
|
|
88
88
|
* publish additional codec to existing track
|
89
89
|
*/
|
90
90
|
publishAdditionalCodecForTrack(track: LocalTrack | MediaStreamTrack, videoCodec: BackupVideoCodec, options?: TrackPublishOptions): Promise<void>;
|
91
|
-
unpublishTrack(track: LocalTrack | MediaStreamTrack, stopOnUnpublish?: boolean): LocalTrackPublication | undefined
|
92
|
-
unpublishTracks(tracks: LocalTrack[] | MediaStreamTrack[]): LocalTrackPublication[]
|
91
|
+
unpublishTrack(track: LocalTrack | MediaStreamTrack, stopOnUnpublish?: boolean): Promise<LocalTrackPublication | undefined>;
|
92
|
+
unpublishTracks(tracks: LocalTrack[] | MediaStreamTrack[]): Promise<LocalTrackPublication[]>;
|
93
|
+
republishAllTracks(options?: TrackPublishOptions): Promise<void>;
|
93
94
|
/**
|
94
95
|
* Publish a new data payload to the room. Data will be forwarded to each
|
95
96
|
* participant in the room if the destination argument is empty
|
@@ -68,7 +68,7 @@ export default class Participant extends Participant_base {
|
|
68
68
|
setConnectionQuality(q: ProtoQuality): void;
|
69
69
|
protected addTrackPublication(publication: TrackPublication): void;
|
70
70
|
}
|
71
|
-
export
|
71
|
+
export type ParticipantEventCallbacks = {
|
72
72
|
trackPublished: (publication: RemoteTrackPublication) => void;
|
73
73
|
trackSubscribed: (track: RemoteTrack, publication: RemoteTrackPublication) => void;
|
74
74
|
trackSubscriptionFailed: (trackSid: string) => void;
|
@@ -23,6 +23,7 @@ export default abstract class LocalTrack extends Track {
|
|
23
23
|
private _isUpstreamPaused;
|
24
24
|
get isUpstreamPaused(): boolean;
|
25
25
|
get isUserProvided(): boolean;
|
26
|
+
waitForDimensions(timeout?: number): Promise<Track.Dimensions>;
|
26
27
|
/**
|
27
28
|
* @returns DeviceID of the device that is currently being used for this track
|
28
29
|
*/
|
@@ -100,10 +100,11 @@ export declare namespace Track {
|
|
100
100
|
/** @internal */
|
101
101
|
function streamStateFromProto(s: ProtoStreamState): StreamState;
|
102
102
|
}
|
103
|
-
export
|
103
|
+
export type TrackEventCallbacks = {
|
104
104
|
message: () => void;
|
105
105
|
muted: (track?: any) => void;
|
106
106
|
unmuted: (track?: any) => void;
|
107
|
+
restarted: (track?: any) => void;
|
107
108
|
ended: (track?: any) => void;
|
108
109
|
updateSettings: () => void;
|
109
110
|
updateSubscription: () => void;
|
@@ -53,7 +53,7 @@ export declare namespace TrackPublication {
|
|
53
53
|
NotAllowed = "not_allowed"
|
54
54
|
}
|
55
55
|
}
|
56
|
-
export
|
56
|
+
export type PublicationEventCallbacks = {
|
57
57
|
muted: () => void;
|
58
58
|
unmuted: () => void;
|
59
59
|
ended: (track?: Track) => void;
|
@@ -187,13 +187,13 @@ declare const backupCodecs: readonly [
|
|
187
187
|
"vp8",
|
188
188
|
"h264"
|
189
189
|
];
|
190
|
-
export
|
191
|
-
export
|
190
|
+
export type VideoCodec = typeof codecs[number];
|
191
|
+
export type BackupVideoCodec = typeof backupCodecs[number];
|
192
192
|
export declare function isBackupCodec(codec: string): codec is BackupVideoCodec;
|
193
193
|
/**
|
194
194
|
* scalability modes for svc, only supprot l3t3 now.
|
195
195
|
*/
|
196
|
-
export
|
196
|
+
export type ScalabilityMode = 'L3T3';
|
197
197
|
export declare namespace AudioPresets {
|
198
198
|
const telephone: AudioPreset;
|
199
199
|
const speech: AudioPreset;
|
@@ -2,9 +2,9 @@ import type LocalAudioTrack from './LocalAudioTrack';
|
|
2
2
|
import type LocalVideoTrack from './LocalVideoTrack';
|
3
3
|
import type RemoteAudioTrack from './RemoteAudioTrack';
|
4
4
|
import type RemoteVideoTrack from './RemoteVideoTrack';
|
5
|
-
export
|
6
|
-
export
|
7
|
-
export
|
5
|
+
export type AudioTrack = RemoteAudioTrack | LocalAudioTrack;
|
6
|
+
export type VideoTrack = RemoteVideoTrack | LocalVideoTrack;
|
7
|
+
export type AdaptiveStreamSettings = {
|
8
8
|
/**
|
9
9
|
* Set a custom pixel density, defaults to 1
|
10
10
|
* When streaming videos on a ultra high definition screen this setting
|
@@ -1,4 +1,6 @@
|
|
1
1
|
import { ClientInfo } from '../proto/livekit_models';
|
2
|
+
import type LocalAudioTrack from './track/LocalAudioTrack';
|
3
|
+
import type RemoteAudioTrack from './track/RemoteAudioTrack';
|
2
4
|
export declare function unpackStreamId(packed: string): string[];
|
3
5
|
export declare function sleep(duration: number): Promise<void>;
|
4
6
|
/** @internal */
|
@@ -24,6 +26,7 @@ export interface ObservableMediaElement extends HTMLMediaElement {
|
|
24
26
|
}
|
25
27
|
export declare function getClientInfo(): ClientInfo;
|
26
28
|
export declare function getEmptyVideoStreamTrack(): MediaStreamTrack;
|
29
|
+
export declare function createDummyVideoStreamTrack(width?: number, height?: number, enabled?: boolean, paintContent?: boolean): MediaStreamTrack;
|
27
30
|
export declare function getEmptyAudioStreamTrack(): MediaStreamTrack;
|
28
31
|
export declare class Future<T> {
|
29
32
|
promise: Promise<T>;
|
@@ -32,4 +35,45 @@ export declare class Future<T> {
|
|
32
35
|
onFinally?: () => void;
|
33
36
|
constructor(futureBase?: (resolve: (arg: T) => void, reject: (e: any) => void) => void, onFinally?: () => void);
|
34
37
|
}
|
38
|
+
export type AudioAnalyserOptions = {
|
39
|
+
/**
|
40
|
+
* If set to true, the analyser will use a cloned version of the underlying mediastreamtrack, which won't be impacted by muting the track.
|
41
|
+
* Useful for local tracks when implementing things like "seems like you're muted, but trying to speak".
|
42
|
+
* Defaults to false
|
43
|
+
*/
|
44
|
+
cloneTrack?: boolean;
|
45
|
+
/**
|
46
|
+
* see https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/fftSize
|
47
|
+
*/
|
48
|
+
fftSize?: number;
|
49
|
+
/**
|
50
|
+
* see https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/smoothingTimeConstant
|
51
|
+
*/
|
52
|
+
smoothingTimeConstant?: number;
|
53
|
+
/**
|
54
|
+
* see https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/minDecibels
|
55
|
+
*/
|
56
|
+
minDecibels?: number;
|
57
|
+
/**
|
58
|
+
* see https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/maxDecibels
|
59
|
+
*/
|
60
|
+
maxDecibels?: number;
|
61
|
+
};
|
62
|
+
/**
|
63
|
+
* Creates and returns an analyser web audio node that is attached to the provided track.
|
64
|
+
* Additionally returns a convenience method `calculateVolume` to perform instant volume readings on that track.
|
65
|
+
* Call the returned `cleanup` function to close the audioContext that has been created for the instance of this helper
|
66
|
+
*/
|
67
|
+
export declare function createAudioAnalyser(track: LocalAudioTrack | RemoteAudioTrack, options?: AudioAnalyserOptions): {
|
68
|
+
calculateVolume: () => number;
|
69
|
+
analyser: AnalyserNode;
|
70
|
+
cleanup: () => void;
|
71
|
+
};
|
72
|
+
export declare class Mutex {
|
73
|
+
private _locking;
|
74
|
+
private _locks;
|
75
|
+
constructor();
|
76
|
+
isLocked(): boolean;
|
77
|
+
lock(): Promise<() => void>;
|
78
|
+
}
|
35
79
|
//# sourceMappingURL=utils.d.ts.map
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "livekit-client",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.6.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",
|
@@ -26,7 +26,7 @@
|
|
26
26
|
"author": "David Zhao <david@davidzhao.com>",
|
27
27
|
"license": "Apache-2.0",
|
28
28
|
"scripts": {
|
29
|
-
"build": "rollup --config && yarn downlevel-dts",
|
29
|
+
"build": "rollup --config --bundleConfigAsCjs && yarn downlevel-dts",
|
30
30
|
"build:watch": "rollup --watch --config rollup.config.js",
|
31
31
|
"build-docs": "typedoc",
|
32
32
|
"proto": "protoc --plugin=node_modules/ts-proto/protoc-gen-ts_proto --ts_proto_opt=esModuleInterop=true --ts_proto_out=./src/proto --ts_proto_opt=outputClientImpl=false,useOptionals=messages,oneof=unions -I./protocol ./protocol/livekit_rtc.proto ./protocol/livekit_models.proto",
|
@@ -51,40 +51,40 @@
|
|
51
51
|
"webrtc-adapter": "^8.1.1"
|
52
52
|
},
|
53
53
|
"devDependencies": {
|
54
|
-
"@babel/core": "7.
|
55
|
-
"@babel/preset-env": "7.
|
56
|
-
"@changesets/changelog-github": "0.4.
|
57
|
-
"@changesets/cli": "2.
|
58
|
-
"@rollup/plugin-babel": "
|
59
|
-
"@rollup/plugin-commonjs": "
|
60
|
-
"@rollup/plugin-json": "
|
61
|
-
"@rollup/plugin-node-resolve": "
|
62
|
-
"@types/jest": "29.
|
54
|
+
"@babel/core": "7.20.7",
|
55
|
+
"@babel/preset-env": "7.20.2",
|
56
|
+
"@changesets/changelog-github": "0.4.8",
|
57
|
+
"@changesets/cli": "2.26.0",
|
58
|
+
"@rollup/plugin-babel": "6.0.3",
|
59
|
+
"@rollup/plugin-commonjs": "24.0.0",
|
60
|
+
"@rollup/plugin-json": "6.0.0",
|
61
|
+
"@rollup/plugin-node-resolve": "15.0.1",
|
62
|
+
"@types/jest": "29.2.5",
|
63
63
|
"@types/sdp-transform": "2.4.5",
|
64
64
|
"@types/ua-parser-js": "0.7.36",
|
65
|
-
"@types/ws": "8.5.
|
66
|
-
"@typescript-eslint/eslint-plugin": "5.
|
67
|
-
"@typescript-eslint/parser": "5.
|
65
|
+
"@types/ws": "8.5.4",
|
66
|
+
"@typescript-eslint/eslint-plugin": "5.47.1",
|
67
|
+
"@typescript-eslint/parser": "5.47.1",
|
68
68
|
"downlevel-dts": "^0.11.0",
|
69
|
-
"eslint": "8.
|
69
|
+
"eslint": "8.31.0",
|
70
70
|
"eslint-config-airbnb-typescript": "17.0.0",
|
71
71
|
"eslint-config-prettier": "8.5.0",
|
72
72
|
"eslint-plugin-import": "2.26.0",
|
73
73
|
"gh-pages": "4.0.0",
|
74
|
-
"jest": "29.1
|
75
|
-
"prettier": "2.
|
76
|
-
"rollup": "
|
74
|
+
"jest": "29.3.1",
|
75
|
+
"prettier": "2.8.1",
|
76
|
+
"rollup": "3.9.1",
|
77
77
|
"rollup-plugin-delete": "^2.0.0",
|
78
78
|
"rollup-plugin-filesize": "9.1.2",
|
79
79
|
"rollup-plugin-re": "1.0.7",
|
80
80
|
"rollup-plugin-terser": "7.0.2",
|
81
|
-
"rollup-plugin-typescript2": "0.34.
|
81
|
+
"rollup-plugin-typescript2": "0.34.1",
|
82
82
|
"ts-jest": "29.0.3",
|
83
|
-
"ts-proto": "1.
|
84
|
-
"typedoc": "0.23.
|
83
|
+
"ts-proto": "1.137.0",
|
84
|
+
"typedoc": "0.23.23",
|
85
85
|
"typedoc-plugin-no-inherit": "1.4.0",
|
86
|
-
"typescript": "4.
|
87
|
-
"vite": "
|
86
|
+
"typescript": "4.9.4",
|
87
|
+
"vite": "4.0.3"
|
88
88
|
},
|
89
89
|
"browserslist": [
|
90
90
|
"safari >= 11",
|
package/src/api/SignalClient.ts
CHANGED
@@ -30,7 +30,7 @@ import {
|
|
30
30
|
UpdateTrackSettings,
|
31
31
|
} from '../proto/livekit_rtc';
|
32
32
|
import { ConnectionError, ConnectionErrorReason } from '../room/errors';
|
33
|
-
import { getClientInfo, sleep } from '../room/utils';
|
33
|
+
import { getClientInfo, Mutex, sleep } from '../room/utils';
|
34
34
|
|
35
35
|
// internal options
|
36
36
|
interface ConnectOpts {
|
@@ -139,12 +139,15 @@ export class SignalClient {
|
|
139
139
|
|
140
140
|
private pingInterval: ReturnType<typeof setInterval> | undefined;
|
141
141
|
|
142
|
+
private closingLock: Mutex;
|
143
|
+
|
142
144
|
constructor(useJSON: boolean = false) {
|
143
145
|
this.isConnected = false;
|
144
146
|
this.isReconnecting = false;
|
145
147
|
this.useJSON = useJSON;
|
146
148
|
this.requestQueue = new Queue();
|
147
149
|
this.queuedRequests = [];
|
150
|
+
this.closingLock = new Mutex();
|
148
151
|
}
|
149
152
|
|
150
153
|
async join(
|
@@ -190,9 +193,9 @@ export class SignalClient {
|
|
190
193
|
const clientInfo = getClientInfo();
|
191
194
|
const params = createConnectionParams(token, clientInfo, opts);
|
192
195
|
|
193
|
-
return new Promise<JoinResponse | void>((resolve, reject) => {
|
194
|
-
const abortHandler = () => {
|
195
|
-
this.close();
|
196
|
+
return new Promise<JoinResponse | void>(async (resolve, reject) => {
|
197
|
+
const abortHandler = async () => {
|
198
|
+
await this.close();
|
196
199
|
reject(new ConnectionError('room connection has been cancelled'));
|
197
200
|
};
|
198
201
|
|
@@ -202,7 +205,7 @@ export class SignalClient {
|
|
202
205
|
abortSignal?.addEventListener('abort', abortHandler);
|
203
206
|
log.debug(`connecting to ${url + params}`);
|
204
207
|
if (this.ws) {
|
205
|
-
this.close();
|
208
|
+
await this.close();
|
206
209
|
}
|
207
210
|
this.ws = new WebSocket(url + params);
|
208
211
|
this.ws.binaryType = 'arraybuffer';
|
@@ -277,7 +280,11 @@ export class SignalClient {
|
|
277
280
|
}
|
278
281
|
resolve(resp.message.join);
|
279
282
|
} else {
|
280
|
-
reject(
|
283
|
+
reject(
|
284
|
+
new ConnectionError(
|
285
|
+
`did not receive join response, got ${resp.message?.$case} instead`,
|
286
|
+
),
|
287
|
+
);
|
281
288
|
}
|
282
289
|
return;
|
283
290
|
}
|
@@ -301,16 +308,33 @@ export class SignalClient {
|
|
301
308
|
});
|
302
309
|
}
|
303
310
|
|
304
|
-
close() {
|
305
|
-
|
306
|
-
|
307
|
-
this.
|
308
|
-
this.ws
|
309
|
-
|
310
|
-
|
311
|
+
async close() {
|
312
|
+
const unlock = await this.closingLock.lock();
|
313
|
+
try {
|
314
|
+
this.isConnected = false;
|
315
|
+
if (this.ws) {
|
316
|
+
this.ws.onclose = null;
|
317
|
+
this.ws.onmessage = null;
|
318
|
+
this.ws.onopen = null;
|
319
|
+
|
320
|
+
// calling `ws.close()` only starts the closing handshake (CLOSING state), prefer to wait until state is actually CLOSED
|
321
|
+
const closePromise = new Promise((resolve) => {
|
322
|
+
if (this.ws) {
|
323
|
+
this.ws.onclose = resolve;
|
324
|
+
} else {
|
325
|
+
resolve(true);
|
326
|
+
}
|
327
|
+
});
|
328
|
+
|
329
|
+
this.ws.close();
|
330
|
+
// 250ms grace period for ws to close gracefully
|
331
|
+
await Promise.race([closePromise, sleep(250)]);
|
332
|
+
}
|
333
|
+
this.ws = undefined;
|
334
|
+
this.clearPingInterval();
|
335
|
+
} finally {
|
336
|
+
unlock();
|
311
337
|
}
|
312
|
-
this.ws = undefined;
|
313
|
-
this.clearPingInterval();
|
314
338
|
}
|
315
339
|
|
316
340
|
// initial offer after joining
|
@@ -441,7 +465,7 @@ export class SignalClient {
|
|
441
465
|
if (this.signalLatency) {
|
442
466
|
await sleep(this.signalLatency);
|
443
467
|
}
|
444
|
-
if (!this.ws || this.ws.readyState
|
468
|
+
if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
|
445
469
|
log.error(`cannot send signal request before connected, type: ${message?.$case}`);
|
446
470
|
return;
|
447
471
|
}
|
@@ -37,7 +37,7 @@ export class TURNCheck extends Checker {
|
|
37
37
|
} else if (hasTURN && !hasTLS) {
|
38
38
|
this.appendWarning('TURN is configured server side, but TURN/TLS is unavailable.');
|
39
39
|
}
|
40
|
-
signalClient.close();
|
40
|
+
await signalClient.close();
|
41
41
|
if (this.connectOptions?.rtcConfig?.iceServers || hasTURN) {
|
42
42
|
await this.room!.connect(this.url, this.token, {
|
43
43
|
rtcConfig: {
|
package/src/index.ts
CHANGED
@@ -23,8 +23,11 @@ import {
|
|
23
23
|
supportsAdaptiveStream,
|
24
24
|
supportsAV1,
|
25
25
|
supportsDynacast,
|
26
|
+
createAudioAnalyser,
|
26
27
|
} from './room/utils';
|
27
28
|
|
29
|
+
import type { AudioAnalyserOptions } from './room/utils';
|
30
|
+
|
28
31
|
export * from './options';
|
29
32
|
export * from './room/errors';
|
30
33
|
export * from './room/events';
|
@@ -43,6 +46,8 @@ export {
|
|
43
46
|
supportsAdaptiveStream,
|
44
47
|
supportsDynacast,
|
45
48
|
supportsAV1,
|
49
|
+
createAudioAnalyser,
|
50
|
+
AudioAnalyserOptions,
|
46
51
|
LogLevel,
|
47
52
|
Room,
|
48
53
|
ConnectionState,
|
package/src/options.ts
CHANGED
@@ -7,6 +7,10 @@ import type {
|
|
7
7
|
} from './room/track/options';
|
8
8
|
import type { AdaptiveStreamSettings } from './room/track/types';
|
9
9
|
|
10
|
+
export interface WebAudioSettings {
|
11
|
+
audioContext: AudioContext;
|
12
|
+
}
|
13
|
+
|
10
14
|
/**
|
11
15
|
* @internal
|
12
16
|
*/
|
@@ -72,7 +76,7 @@ export interface InternalRoomOptions {
|
|
72
76
|
* experimental flag, mix all audio tracks in web audio
|
73
77
|
*/
|
74
78
|
|
75
|
-
expWebAudioMix: boolean;
|
79
|
+
expWebAudioMix: boolean | WebAudioSettings;
|
76
80
|
}
|
77
81
|
|
78
82
|
/**
|
package/src/room/PCTransport.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import EventEmitter from 'events';
|
1
2
|
import { MediaDescription, parse, write } from 'sdp-transform';
|
2
3
|
import { debounce } from 'ts-debounce';
|
3
4
|
import log from '../logger';
|
@@ -10,8 +11,13 @@ interface TrackBitrateInfo {
|
|
10
11
|
maxbr: number;
|
11
12
|
}
|
12
13
|
|
14
|
+
export const PCEvents = {
|
15
|
+
NegotiationStarted: 'negotiationStarted',
|
16
|
+
NegotiationComplete: 'negotiationComplete',
|
17
|
+
} as const;
|
18
|
+
|
13
19
|
/** @internal */
|
14
|
-
export default class PCTransport {
|
20
|
+
export default class PCTransport extends EventEmitter {
|
15
21
|
pc: RTCPeerConnection;
|
16
22
|
|
17
23
|
pendingCandidates: RTCIceCandidateInit[] = [];
|
@@ -27,6 +33,7 @@ export default class PCTransport {
|
|
27
33
|
onOffer?: (offer: RTCSessionDescriptionInit) => void;
|
28
34
|
|
29
35
|
constructor(config?: RTCConfiguration) {
|
36
|
+
super();
|
30
37
|
this.pc = new RTCPeerConnection(config);
|
31
38
|
}
|
32
39
|
|
@@ -56,11 +63,14 @@ export default class PCTransport {
|
|
56
63
|
if (this.renegotiate) {
|
57
64
|
this.renegotiate = false;
|
58
65
|
this.createAndSendOffer();
|
66
|
+
} else if (sd.type === 'answer') {
|
67
|
+
this.emit(PCEvents.NegotiationComplete);
|
59
68
|
}
|
60
69
|
}
|
61
70
|
|
62
71
|
// debounced negotiate interface
|
63
72
|
negotiate = debounce((onError?: (e: Error) => void) => {
|
73
|
+
this.emit(PCEvents.NegotiationStarted);
|
64
74
|
try {
|
65
75
|
this.createAndSendOffer();
|
66
76
|
} catch (e) {
|