livekit-client 1.14.4 → 1.15.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 +1 -1
- 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 +5488 -5230
- 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.map +1 -1
- package/dist/src/room/PCTransport.d.ts +10 -4
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts +51 -0
- package/dist/src/room/PCTransportManager.d.ts.map +1 -0
- package/dist/src/room/RTCEngine.d.ts +8 -5
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +9 -0
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +10 -0
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +0 -5
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +6 -2
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +2 -0
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts +3 -0
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/test/mocks.d.ts +1 -1
- package/dist/src/test/mocks.d.ts.map +1 -1
- package/dist/ts4.2/src/room/PCTransport.d.ts +10 -4
- package/dist/ts4.2/src/room/PCTransportManager.d.ts +51 -0
- package/dist/ts4.2/src/room/RTCEngine.d.ts +8 -5
- package/dist/ts4.2/src/room/Room.d.ts +9 -0
- package/dist/ts4.2/src/room/events.d.ts +10 -0
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +0 -5
- package/dist/ts4.2/src/room/track/Track.d.ts +6 -2
- package/dist/ts4.2/src/room/track/options.d.ts +2 -0
- package/dist/ts4.2/src/room/track/utils.d.ts +3 -0
- package/dist/ts4.2/src/test/mocks.d.ts +1 -1
- package/package.json +20 -19
- package/src/api/SignalClient.ts +7 -1
- package/src/connectionHelper/checks/webrtc.ts +2 -2
- package/src/room/PCTransport.ts +66 -29
- package/src/room/PCTransportManager.ts +336 -0
- package/src/room/RTCEngine.ts +178 -246
- package/src/room/Room.ts +49 -46
- package/src/room/defaults.ts +1 -1
- package/src/room/events.ts +11 -0
- package/src/room/participant/LocalParticipant.ts +9 -51
- package/src/room/track/LocalTrack.ts +2 -0
- package/src/room/track/Track.ts +30 -9
- package/src/room/track/options.ts +2 -0
- package/src/room/track/utils.ts +19 -0
- package/src/room/utils.ts +2 -1
- package/src/test/mocks.ts +5 -1
@@ -0,0 +1,51 @@
|
|
1
|
+
import { SignalTarget } from '../proto/livekit_rtc_pb';
|
2
|
+
import PCTransport from './PCTransport';
|
3
|
+
export declare enum PCTransportState {
|
4
|
+
NEW = 0,
|
5
|
+
CONNECTING = 1,
|
6
|
+
CONNECTED = 2,
|
7
|
+
FAILED = 3,
|
8
|
+
CLOSING = 4,
|
9
|
+
CLOSED = 5
|
10
|
+
}
|
11
|
+
export declare class PCTransportManager {
|
12
|
+
publisher: PCTransport;
|
13
|
+
subscriber: PCTransport;
|
14
|
+
peerConnectionTimeout: number;
|
15
|
+
get needsPublisher(): boolean;
|
16
|
+
get needsSubscriber(): boolean;
|
17
|
+
get currentState(): PCTransportState;
|
18
|
+
onStateChange?: (state: PCTransportState, pubState: RTCPeerConnectionState, subState: RTCPeerConnectionState) => void;
|
19
|
+
onIceCandidate?: (ev: RTCIceCandidate, target: SignalTarget) => void;
|
20
|
+
onDataChannel?: (ev: RTCDataChannelEvent) => void;
|
21
|
+
onTrack?: (ev: RTCTrackEvent) => void;
|
22
|
+
onPublisherOffer?: (offer: RTCSessionDescriptionInit) => void;
|
23
|
+
private isPublisherConnectionRequired;
|
24
|
+
private isSubscriberConnectionRequired;
|
25
|
+
private state;
|
26
|
+
private connectionLock;
|
27
|
+
constructor(rtcConfig: RTCConfiguration, subscriberPrimary: boolean);
|
28
|
+
requirePublisher(require?: boolean): void;
|
29
|
+
requireSubscriber(require?: boolean): void;
|
30
|
+
createAndSendPublisherOffer(options?: RTCOfferOptions): Promise<void>;
|
31
|
+
setPublisherAnswer(sd: RTCSessionDescriptionInit): Promise<void>;
|
32
|
+
removeTrack(sender: RTCRtpSender): void | undefined;
|
33
|
+
close(): Promise<void>;
|
34
|
+
triggerIceRestart(): Promise<void>;
|
35
|
+
addIceCandidate(candidate: RTCIceCandidateInit, target: SignalTarget): Promise<void>;
|
36
|
+
createSubscriberAnswerFromOffer(sd: RTCSessionDescriptionInit): Promise<RTCSessionDescriptionInit>;
|
37
|
+
updateConfiguration(config: RTCConfiguration, iceRestart?: boolean): void;
|
38
|
+
ensurePCTransportConnection(abortController?: AbortController, timeout?: number): Promise<void>;
|
39
|
+
negotiate(abortController: AbortController): Promise<void>;
|
40
|
+
addPublisherTransceiver(track: MediaStreamTrack, transceiverInit: RTCRtpTransceiverInit): RTCRtpTransceiver;
|
41
|
+
addPublisherTrack(track: MediaStreamTrack): RTCRtpSender;
|
42
|
+
createPublisherDataChannel(label: string, dataChannelDict: RTCDataChannelInit): RTCDataChannel;
|
43
|
+
/**
|
44
|
+
* Returns the first required transport's address if no explicit target is specified
|
45
|
+
*/
|
46
|
+
getConnectedAddress(target?: SignalTarget): Promise<string | undefined>;
|
47
|
+
private get requiredTransports();
|
48
|
+
private updateState;
|
49
|
+
private ensureTransportConnected;
|
50
|
+
}
|
51
|
+
//# sourceMappingURL=PCTransportManager.d.ts.map
|
@@ -3,24 +3,26 @@ import type { SignalOptions } from '../api/SignalClient';
|
|
3
3
|
import { SignalClient } from '../api/SignalClient';
|
4
4
|
import type { InternalRoomOptions } from '../options';
|
5
5
|
import { DataPacket, DataPacket_Kind, DisconnectReason, ParticipantInfo, Room as RoomModel, SpeakerInfo, TrackInfo, UserPacket } from '../proto/livekit_models_pb';
|
6
|
-
import { AddTrackRequest, ConnectionQualityUpdate, JoinResponse, StreamStateUpdate, SubscriptionPermissionUpdate, SubscriptionResponse } from '../proto/livekit_rtc_pb';
|
6
|
+
import type { AddTrackRequest, ConnectionQualityUpdate, JoinResponse, StreamStateUpdate, SubscriptionPermissionUpdate, SubscriptionResponse } from '../proto/livekit_rtc_pb';
|
7
7
|
import PCTransport from './PCTransport';
|
8
|
+
import { PCTransportManager } from './PCTransportManager';
|
8
9
|
import type { RegionUrlProvider } from './RegionUrlProvider';
|
9
10
|
import type LocalTrack from './track/LocalTrack';
|
11
|
+
import type LocalTrackPublication from './track/LocalTrackPublication';
|
10
12
|
import type LocalVideoTrack from './track/LocalVideoTrack';
|
11
13
|
import type { SimulcastTrackInfo } from './track/LocalVideoTrack';
|
14
|
+
import type RemoteTrackPublication from './track/RemoteTrackPublication';
|
12
15
|
import { Track } from './track/Track';
|
13
16
|
import type { TrackPublishOptions, VideoCodec } from './track/options';
|
14
17
|
declare const RTCEngine_base: new () => TypedEventEmitter<EngineEventCallbacks>;
|
15
18
|
/** @internal */
|
16
19
|
export default class RTCEngine extends RTCEngine_base {
|
17
20
|
private options;
|
18
|
-
publisher?: PCTransport;
|
19
|
-
subscriber?: PCTransport;
|
20
21
|
client: SignalClient;
|
21
22
|
rtcConfig: RTCConfiguration;
|
22
23
|
peerConnectionTimeout: number;
|
23
24
|
fullReconnectOnNext: boolean;
|
25
|
+
pcManager?: PCTransportManager;
|
24
26
|
/**
|
25
27
|
* @internal
|
26
28
|
*/
|
@@ -32,11 +34,9 @@ export default class RTCEngine extends RTCEngine_base {
|
|
32
34
|
private dcBufferStatus;
|
33
35
|
private reliableDCSub?;
|
34
36
|
private subscriberPrimary;
|
35
|
-
private primaryTransport?;
|
36
37
|
private pcState;
|
37
38
|
private _isClosed;
|
38
39
|
private pendingTrackResolvers;
|
39
|
-
private hasPublished;
|
40
40
|
private url?;
|
41
41
|
private token?;
|
42
42
|
private signalOpts?;
|
@@ -106,7 +106,10 @@ export default class RTCEngine extends RTCEngine_base {
|
|
106
106
|
/** @internal */
|
107
107
|
negotiate(): Promise<void>;
|
108
108
|
dataChannelForKind(kind: DataPacket_Kind, sub?: boolean): RTCDataChannel | undefined;
|
109
|
+
/** @internal */
|
110
|
+
sendSyncState(remoteTracks: RemoteTrackPublication[], localTracks: LocalTrackPublication[]): void;
|
109
111
|
failNext(): void;
|
112
|
+
private dataChannelsInfo;
|
110
113
|
private clearReconnectTimeout;
|
111
114
|
private clearPendingReconnect;
|
112
115
|
private handleBrowserOnLine;
|
@@ -63,6 +63,7 @@ declare class Room extends Room_base {
|
|
63
63
|
private connectionReconcileInterval?;
|
64
64
|
private regionUrlProvider?;
|
65
65
|
private regionUrl?;
|
66
|
+
private isVideoPlaybackBlocked;
|
66
67
|
/**
|
67
68
|
* Creates a new Room, the primary construct for a LiveKit session.
|
68
69
|
* @param options
|
@@ -133,10 +134,15 @@ declare class Room extends Room_base {
|
|
133
134
|
* - `getUserMedia`
|
134
135
|
*/
|
135
136
|
startAudio: () => Promise<void>;
|
137
|
+
startVideo: () => Promise<void>;
|
136
138
|
/**
|
137
139
|
* Returns true if audio playback is enabled
|
138
140
|
*/
|
139
141
|
get canPlaybackAudio(): boolean;
|
142
|
+
/**
|
143
|
+
* Returns true if video playback is enabled
|
144
|
+
*/
|
145
|
+
get canPlaybackVideo(): boolean;
|
140
146
|
/**
|
141
147
|
* Returns the active audio output device used in this room.
|
142
148
|
* @return the previously successfully set audio output device ID or an empty string if the default device is used.
|
@@ -171,6 +177,8 @@ declare class Room extends Room_base {
|
|
171
177
|
private handleDataPacket;
|
172
178
|
private handleAudioPlaybackStarted;
|
173
179
|
private handleAudioPlaybackFailed;
|
180
|
+
private handleVideoPlaybackStarted;
|
181
|
+
private handleVideoPlaybackFailed;
|
174
182
|
private handleDeviceChange;
|
175
183
|
private handleRoomUpdate;
|
176
184
|
private handleConnectionQualityUpdate;
|
@@ -238,6 +246,7 @@ export type RoomEventCallbacks = {
|
|
238
246
|
trackSubscriptionPermissionChanged: (publication: RemoteTrackPublication, status: TrackPublication.PermissionStatus, participant: RemoteParticipant) => void;
|
239
247
|
trackSubscriptionStatusChanged: (publication: RemoteTrackPublication, status: TrackPublication.SubscriptionStatus, participant: RemoteParticipant) => void;
|
240
248
|
audioPlaybackChanged: (playing: boolean) => void;
|
249
|
+
videoPlaybackChanged: (playing: boolean) => void;
|
241
250
|
signalConnected: () => void;
|
242
251
|
recordingStatusChanged: (recording: boolean) => void;
|
243
252
|
participantEncryptionStatusChanged: (encrypted: boolean, participant?: Participant) => void;
|
@@ -215,6 +215,12 @@ export declare enum RoomEvent {
|
|
215
215
|
* `Room.canPlaybackAudio` will indicate if audio playback is permitted.
|
216
216
|
*/
|
217
217
|
AudioPlaybackStatusChanged = "audioPlaybackChanged",
|
218
|
+
/**
|
219
|
+
* LiveKit will attempt to autoplay all video tracks when you attach them to
|
220
|
+
* a video element. However, if that fails, we'll notify you via VideoPlaybackStatusChanged.
|
221
|
+
* Calling `room.startVideo()` in a user gesture event handler will resume the video playback.
|
222
|
+
*/
|
223
|
+
VideoPlaybackStatusChanged = "videoPlaybackChanged",
|
218
224
|
/**
|
219
225
|
* When we have encountered an error while attempting to create a track.
|
220
226
|
* The errors take place in getUserMedia().
|
@@ -449,6 +455,10 @@ export declare enum TrackEvent {
|
|
449
455
|
/** @internal */
|
450
456
|
VideoDimensionsChanged = "videoDimensionsChanged",
|
451
457
|
/** @internal */
|
458
|
+
VideoPlaybackStarted = "videoPlaybackStarted",
|
459
|
+
/** @internal */
|
460
|
+
VideoPlaybackFailed = "videoPlaybackFailed",
|
461
|
+
/** @internal */
|
452
462
|
ElementAttached = "elementAttached",
|
453
463
|
/** @internal */
|
454
464
|
ElementDetached = "elementDetached",
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import type { InternalRoomOptions } from '../../options';
|
2
2
|
import { DataPacket_Kind, ParticipantInfo, ParticipantPermission } from '../../proto/livekit_models_pb';
|
3
|
-
import { DataChannelInfo, TrackPublishedResponse } from '../../proto/livekit_rtc_pb';
|
4
3
|
import type RTCEngine from '../RTCEngine';
|
5
4
|
import LocalTrack from '../track/LocalTrack';
|
6
5
|
import LocalTrackPublication from '../track/LocalTrackPublication';
|
@@ -174,9 +173,5 @@ export default class LocalParticipant extends Participant {
|
|
174
173
|
private handleLocalTrackUnpublished;
|
175
174
|
private handleTrackEnded;
|
176
175
|
private getPublicationForTrack;
|
177
|
-
/** @internal */
|
178
|
-
publishedTracksInfo(): TrackPublishedResponse[];
|
179
|
-
/** @internal */
|
180
|
-
dataChannelsInfo(): DataChannelInfo[];
|
181
176
|
}
|
182
177
|
//# sourceMappingURL=LocalParticipant.d.ts.map
|
@@ -64,8 +64,10 @@ export declare abstract class Track extends Track_base {
|
|
64
64
|
protected handleAppVisibilityChanged(): Promise<void>;
|
65
65
|
protected addAppVisibilityListener(): void;
|
66
66
|
protected removeAppVisibilityListener(): void;
|
67
|
+
private handleElementSuspended;
|
68
|
+
private handleElementPlay;
|
69
|
+
private debouncedPlaybackStateChange;
|
67
70
|
}
|
68
|
-
/** @internal */
|
69
71
|
export declare function attachToElement(track: MediaStreamTrack, element: HTMLMediaElement): void;
|
70
72
|
/** @internal */
|
71
73
|
export declare function detachTrack(track: MediaStreamTrack, element: HTMLMediaElement): void;
|
@@ -112,10 +114,12 @@ export type TrackEventCallbacks = {
|
|
112
114
|
updateSettings: () => void;
|
113
115
|
updateSubscription: () => void;
|
114
116
|
audioPlaybackStarted: () => void;
|
115
|
-
audioPlaybackFailed: (error
|
117
|
+
audioPlaybackFailed: (error?: Error) => void;
|
116
118
|
audioSilenceDetected: () => void;
|
117
119
|
visibilityChanged: (visible: boolean, track?: any) => void;
|
118
120
|
videoDimensionsChanged: (dimensions: Track.Dimensions, track?: any) => void;
|
121
|
+
videoPlaybackStarted: () => void;
|
122
|
+
videoPlaybackFailed: (error?: Error) => void;
|
119
123
|
elementAttached: (element: HTMLMediaElement) => void;
|
120
124
|
elementDetached: (element: HTMLMediaElement) => void;
|
121
125
|
upstreamPaused: (track: any) => void;
|
@@ -12,6 +12,8 @@ export interface TrackPublishDefaults {
|
|
12
12
|
*
|
13
13
|
* You could customize specific encoding parameters of the backup track by
|
14
14
|
* explicitly setting codec and encoding fields.
|
15
|
+
*
|
16
|
+
* Defaults to `true`
|
15
17
|
*/
|
16
18
|
backupCodec?: true | false | {
|
17
19
|
codec: BackupVideoCodec;
|
@@ -1,4 +1,6 @@
|
|
1
|
+
import { TrackPublishedResponse } from '../../proto/livekit_rtc_pb';
|
1
2
|
import { Track } from './Track';
|
3
|
+
import type { TrackPublication } from './TrackPublication';
|
2
4
|
import type { AudioCaptureOptions, CreateLocalTracksOptions, ScreenShareCaptureOptions, VideoCaptureOptions } from './options';
|
3
5
|
import type { AudioTrack } from './types';
|
4
6
|
export declare function mergeDefaultOptions(options?: CreateLocalTracksOptions, audioDefaults?: AudioCaptureOptions, videoDefaults?: VideoCaptureOptions): CreateLocalTracksOptions;
|
@@ -25,4 +27,5 @@ export declare function sourceToKind(source: Track.Source): MediaDeviceKind | un
|
|
25
27
|
*/
|
26
28
|
export declare function screenCaptureToDisplayMediaStreamOptions(options: ScreenShareCaptureOptions): DisplayMediaStreamOptions;
|
27
29
|
export declare function mimeTypeToVideoCodecString(mimeType: string): "vp8" | "h264" | "vp9" | "av1";
|
30
|
+
export declare function getTrackPublicationInfo<T extends TrackPublication>(tracks: T[]): TrackPublishedResponse[];
|
28
31
|
//# 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.15.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",
|
@@ -28,35 +28,20 @@
|
|
28
28
|
"./dist/ts4.2/src/index.d.ts"
|
29
29
|
],
|
30
30
|
"./dist/src/e2ee/worker/e2ee.worker.d.ts": [
|
31
|
-
"./dist/ts4.2
|
31
|
+
"./dist/ts4.2/dist/src/e2ee/worker/e2ee.worker.d.ts"
|
32
32
|
]
|
33
33
|
}
|
34
34
|
},
|
35
35
|
"repository": "git@github.com:livekit/client-sdk-js.git",
|
36
36
|
"author": "David Zhao <david@davidzhao.com>",
|
37
37
|
"license": "Apache-2.0",
|
38
|
-
"scripts": {
|
39
|
-
"build": "rollup --config --bundleConfigAsCjs && rollup --config rollup.config.worker.js --bundleConfigAsCjs && yarn downlevel-dts",
|
40
|
-
"build:watch": "rollup --watch --config rollup.config.js",
|
41
|
-
"build-docs": "typedoc",
|
42
|
-
"proto": "protoc --es_out src/proto --es_opt target=ts -I./protocol ./protocol/livekit_rtc.proto ./protocol/livekit_models.proto",
|
43
|
-
"sample": "vite example -c vite.config.js",
|
44
|
-
"lint": "eslint src",
|
45
|
-
"test": "vitest run src",
|
46
|
-
"deploy": "gh-pages -d example/dist",
|
47
|
-
"format": "prettier --write src example/sample.ts",
|
48
|
-
"format:check": "prettier --check src",
|
49
|
-
"release": "yarn build && yarn compat && changeset publish",
|
50
|
-
"downlevel-dts": "downlevel-dts ./dist/ ./dist/ts4.2 --to=4.2",
|
51
|
-
"compat": "eslint --no-eslintrc --config ./.eslintrc.dist.cjs ./dist/livekit-client.umd.js",
|
52
|
-
"size-limit": "size-limit"
|
53
|
-
},
|
54
38
|
"dependencies": {
|
55
39
|
"@bufbuild/protobuf": "^1.3.0",
|
56
40
|
"events": "^3.3.0",
|
57
41
|
"loglevel": "^1.8.0",
|
58
42
|
"sdp-transform": "^2.14.1",
|
59
43
|
"ts-debounce": "^4.0.0",
|
44
|
+
"tslib": "2.6.2",
|
60
45
|
"typed-emitter": "^2.1.0",
|
61
46
|
"webrtc-adapter": "^8.1.1"
|
62
47
|
},
|
@@ -98,5 +83,21 @@
|
|
98
83
|
"typescript": "5.2.2",
|
99
84
|
"vite": "4.5.0",
|
100
85
|
"vitest": "^0.34.0"
|
86
|
+
},
|
87
|
+
"scripts": {
|
88
|
+
"build": "rollup --config --bundleConfigAsCjs && rollup --config rollup.config.worker.js --bundleConfigAsCjs && pnpm downlevel-dts",
|
89
|
+
"build:watch": "rollup --watch --config rollup.config.js",
|
90
|
+
"build-docs": "typedoc",
|
91
|
+
"proto": "protoc --es_out src/proto --es_opt target=ts -I./protocol ./protocol/livekit_rtc.proto ./protocol/livekit_models.proto",
|
92
|
+
"sample": "vite example -c vite.config.js",
|
93
|
+
"lint": "eslint src",
|
94
|
+
"test": "vitest run src",
|
95
|
+
"deploy": "gh-pages -d example/dist",
|
96
|
+
"format": "prettier --write src example/sample.ts",
|
97
|
+
"format:check": "prettier --check src",
|
98
|
+
"ci:publish": "pnpm build && pnpm compat && changeset publish",
|
99
|
+
"downlevel-dts": "downlevel-dts ./dist/ ./dist/ts4.2 --to=4.2",
|
100
|
+
"compat": "eslint --no-eslintrc --config ./.eslintrc.dist.cjs ./dist/livekit-client.umd.js",
|
101
|
+
"size-limit": "size-limit"
|
101
102
|
}
|
102
|
-
}
|
103
|
+
}
|
package/src/api/SignalClient.ts
CHANGED
@@ -558,6 +558,8 @@ export class SignalClient {
|
|
558
558
|
log.debug('received unsupported message');
|
559
559
|
return;
|
560
560
|
}
|
561
|
+
|
562
|
+
let pingHandled = false;
|
561
563
|
if (msg.case === 'answer') {
|
562
564
|
const sd = fromProtoSessionDescription(msg.value);
|
563
565
|
if (this.onAnswer) {
|
@@ -626,13 +628,17 @@ export class SignalClient {
|
|
626
628
|
this.onSubscriptionError(msg.value);
|
627
629
|
}
|
628
630
|
} else if (msg.case === 'pong') {
|
629
|
-
this.resetPingTimeout();
|
630
631
|
} else if (msg.case === 'pongResp') {
|
631
632
|
this.rtt = Date.now() - Number.parseInt(msg.value.lastPingTimestamp.toString());
|
632
633
|
this.resetPingTimeout();
|
634
|
+
pingHandled = true;
|
633
635
|
} else {
|
634
636
|
log.debug('unsupported message', msg);
|
635
637
|
}
|
638
|
+
|
639
|
+
if (!pingHandled) {
|
640
|
+
this.resetPingTimeout();
|
641
|
+
}
|
636
642
|
}
|
637
643
|
|
638
644
|
setReconnected() {
|
@@ -38,8 +38,8 @@ export class WebRTCCheck extends Checker {
|
|
38
38
|
}
|
39
39
|
};
|
40
40
|
|
41
|
-
if (this.room.engine.
|
42
|
-
this.room.engine.subscriber.onIceCandidateError = (ev) => {
|
41
|
+
if (this.room.engine.pcManager) {
|
42
|
+
this.room.engine.pcManager.subscriber.onIceCandidateError = (ev) => {
|
43
43
|
if (ev instanceof RTCPeerConnectionIceErrorEvent) {
|
44
44
|
this.appendWarning(
|
45
45
|
`error with ICE candidate: ${ev.errorCode} ${ev.errorText} ${ev.url}`,
|
package/src/room/PCTransport.ts
CHANGED
@@ -33,10 +33,16 @@ export default class PCTransport extends EventEmitter {
|
|
33
33
|
private _pc: RTCPeerConnection | null;
|
34
34
|
|
35
35
|
private get pc() {
|
36
|
-
if (this._pc)
|
37
|
-
|
36
|
+
if (!this._pc) {
|
37
|
+
this._pc = this.createPC();
|
38
|
+
}
|
39
|
+
return this._pc;
|
38
40
|
}
|
39
41
|
|
42
|
+
private config?: RTCConfiguration;
|
43
|
+
|
44
|
+
private mediaConstraints: Record<string, unknown>;
|
45
|
+
|
40
46
|
pendingCandidates: RTCIceCandidateInit[] = [];
|
41
47
|
|
42
48
|
restartingIce: boolean = false;
|
@@ -57,32 +63,53 @@ export default class PCTransport extends EventEmitter {
|
|
57
63
|
|
58
64
|
onConnectionStateChange?: (state: RTCPeerConnectionState) => void;
|
59
65
|
|
66
|
+
onIceConnectionStateChange?: (state: RTCIceConnectionState) => void;
|
67
|
+
|
68
|
+
onSignalingStatechange?: (state: RTCSignalingState) => void;
|
69
|
+
|
60
70
|
onDataChannel?: (ev: RTCDataChannelEvent) => void;
|
61
71
|
|
62
72
|
onTrack?: (ev: RTCTrackEvent) => void;
|
63
73
|
|
64
74
|
constructor(config?: RTCConfiguration, mediaConstraints: Record<string, unknown> = {}) {
|
65
75
|
super();
|
66
|
-
this.
|
76
|
+
this.config = config;
|
77
|
+
this.mediaConstraints = mediaConstraints;
|
78
|
+
this._pc = this.createPC();
|
79
|
+
}
|
80
|
+
|
81
|
+
private createPC() {
|
82
|
+
const pc = isChromiumBased()
|
67
83
|
? // @ts-expect-error chrome allows additional media constraints to be passed into the RTCPeerConnection constructor
|
68
|
-
new RTCPeerConnection(config, mediaConstraints)
|
69
|
-
: new RTCPeerConnection(config);
|
70
|
-
|
84
|
+
new RTCPeerConnection(this.config, this.mediaConstraints)
|
85
|
+
: new RTCPeerConnection(this.config);
|
86
|
+
|
87
|
+
pc.onicecandidate = (ev) => {
|
71
88
|
if (!ev.candidate) return;
|
72
89
|
this.onIceCandidate?.(ev.candidate);
|
73
90
|
};
|
74
|
-
|
91
|
+
pc.onicecandidateerror = (ev) => {
|
75
92
|
this.onIceCandidateError?.(ev);
|
76
93
|
};
|
77
|
-
|
78
|
-
|
94
|
+
|
95
|
+
pc.oniceconnectionstatechange = () => {
|
96
|
+
this.onIceConnectionStateChange?.(pc.iceConnectionState);
|
79
97
|
};
|
80
|
-
|
98
|
+
|
99
|
+
pc.onsignalingstatechange = () => {
|
100
|
+
this.onSignalingStatechange?.(pc.signalingState);
|
101
|
+
};
|
102
|
+
|
103
|
+
pc.onconnectionstatechange = () => {
|
104
|
+
this.onConnectionStateChange?.(pc.connectionState);
|
105
|
+
};
|
106
|
+
pc.ondatachannel = (ev) => {
|
81
107
|
this.onDataChannel?.(ev);
|
82
108
|
};
|
83
|
-
|
109
|
+
pc.ontrack = (ev) => {
|
84
110
|
this.onTrack?.(ev);
|
85
111
|
};
|
112
|
+
return pc;
|
86
113
|
}
|
87
114
|
|
88
115
|
get isICEConnected(): boolean {
|
@@ -168,7 +195,7 @@ export default class PCTransport extends EventEmitter {
|
|
168
195
|
|
169
196
|
if (this.renegotiate) {
|
170
197
|
this.renegotiate = false;
|
171
|
-
this.createAndSendOffer();
|
198
|
+
await this.createAndSendOffer();
|
172
199
|
} else if (sd.type === 'answer') {
|
173
200
|
this.emit(PCEvents.NegotiationComplete);
|
174
201
|
if (sd.sdp) {
|
@@ -183,10 +210,10 @@ export default class PCTransport extends EventEmitter {
|
|
183
210
|
}
|
184
211
|
|
185
212
|
// debounced negotiate interface
|
186
|
-
negotiate = debounce((onError?: (e: Error) => void) => {
|
213
|
+
negotiate = debounce(async (onError?: (e: Error) => void) => {
|
187
214
|
this.emit(PCEvents.NegotiationStarted);
|
188
215
|
try {
|
189
|
-
this.createAndSendOffer();
|
216
|
+
await this.createAndSendOffer();
|
190
217
|
} catch (e) {
|
191
218
|
if (onError) {
|
192
219
|
onError(e as Error);
|
@@ -209,11 +236,11 @@ export default class PCTransport extends EventEmitter {
|
|
209
236
|
if (this._pc && this._pc.signalingState === 'have-local-offer') {
|
210
237
|
// we're waiting for the peer to accept our offer, so we'll just wait
|
211
238
|
// the only exception to this is when ICE restart is needed
|
212
|
-
const currentSD = this.
|
239
|
+
const currentSD = this._pc.remoteDescription;
|
213
240
|
if (options?.iceRestart && currentSD) {
|
214
241
|
// TODO: handle when ICE restart is needed but we don't have a remote description
|
215
242
|
// the best thing to do is to recreate the peerconnection
|
216
|
-
await this.
|
243
|
+
await this._pc.setRemoteDescription(currentSD);
|
217
244
|
} else {
|
218
245
|
this.renegotiate = true;
|
219
246
|
return;
|
@@ -307,7 +334,10 @@ export default class PCTransport extends EventEmitter {
|
|
307
334
|
}
|
308
335
|
|
309
336
|
addTrack(track: MediaStreamTrack) {
|
310
|
-
|
337
|
+
if (!this._pc) {
|
338
|
+
throw new UnexpectedConnectionState('PC closed, cannot add track');
|
339
|
+
}
|
340
|
+
return this._pc.addTrack(track);
|
311
341
|
}
|
312
342
|
|
313
343
|
setTrackCodecBitrate(info: TrackBitrateInfo) {
|
@@ -315,43 +345,50 @@ export default class PCTransport extends EventEmitter {
|
|
315
345
|
}
|
316
346
|
|
317
347
|
setConfiguration(rtcConfig: RTCConfiguration) {
|
318
|
-
|
348
|
+
if (!this._pc) {
|
349
|
+
throw new UnexpectedConnectionState('PC closed, cannot configure');
|
350
|
+
}
|
351
|
+
return this._pc?.setConfiguration(rtcConfig);
|
319
352
|
}
|
320
353
|
|
321
354
|
canRemoveTrack(): boolean {
|
322
|
-
return !!this.
|
355
|
+
return !!this._pc?.removeTrack;
|
323
356
|
}
|
324
357
|
|
325
358
|
removeTrack(sender: RTCRtpSender) {
|
326
|
-
return this.
|
359
|
+
return this._pc?.removeTrack(sender);
|
327
360
|
}
|
328
361
|
|
329
362
|
getConnectionState() {
|
330
|
-
return this.
|
363
|
+
return this._pc?.connectionState ?? 'closed';
|
331
364
|
}
|
332
365
|
|
333
366
|
getICEConnectionState() {
|
334
|
-
return this.
|
367
|
+
return this._pc?.iceConnectionState ?? 'closed';
|
335
368
|
}
|
336
369
|
|
337
370
|
getSignallingState() {
|
338
|
-
return this.
|
371
|
+
return this._pc?.signalingState ?? 'closed';
|
339
372
|
}
|
340
373
|
|
341
374
|
getTransceivers() {
|
342
|
-
return this.
|
375
|
+
return this._pc?.getTransceivers() ?? [];
|
343
376
|
}
|
344
377
|
|
345
378
|
getSenders() {
|
346
|
-
return this.
|
379
|
+
return this._pc?.getSenders() ?? [];
|
347
380
|
}
|
348
381
|
|
349
382
|
getLocalDescription() {
|
350
|
-
return this.
|
383
|
+
return this._pc?.localDescription;
|
351
384
|
}
|
352
385
|
|
353
386
|
getRemoteDescription() {
|
354
|
-
return this.pc
|
387
|
+
return this.pc?.remoteDescription;
|
388
|
+
}
|
389
|
+
|
390
|
+
getStats() {
|
391
|
+
return this.pc.getStats();
|
355
392
|
}
|
356
393
|
|
357
394
|
async getConnectedAddress(): Promise<string | undefined> {
|
@@ -391,7 +428,7 @@ export default class PCTransport extends EventEmitter {
|
|
391
428
|
return candidates.get(selectedID);
|
392
429
|
}
|
393
430
|
|
394
|
-
close() {
|
431
|
+
close = () => {
|
395
432
|
if (!this._pc) {
|
396
433
|
return;
|
397
434
|
}
|
@@ -408,7 +445,7 @@ export default class PCTransport extends EventEmitter {
|
|
408
445
|
this._pc.onconnectionstatechange = null;
|
409
446
|
this._pc.oniceconnectionstatechange = null;
|
410
447
|
this._pc = null;
|
411
|
-
}
|
448
|
+
};
|
412
449
|
|
413
450
|
private async setMungedSDP(sd: RTCSessionDescriptionInit, munged?: string, remote?: boolean) {
|
414
451
|
if (munged) {
|