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
package/src/room/RTCEngine.ts
CHANGED
@@ -29,7 +29,7 @@ import {
|
|
29
29
|
UnexpectedConnectionState,
|
30
30
|
} from './errors';
|
31
31
|
import { EngineEvent } from './events';
|
32
|
-
import PCTransport from './PCTransport';
|
32
|
+
import PCTransport, { PCEvents } from './PCTransport';
|
33
33
|
import type { ReconnectContext, ReconnectPolicy } from './ReconnectPolicy';
|
34
34
|
import type LocalTrack from './track/LocalTrack';
|
35
35
|
import type LocalVideoTrack from './track/LocalVideoTrack';
|
@@ -38,6 +38,7 @@ import type { TrackPublishOptions, VideoCodec } from './track/options';
|
|
38
38
|
import { Track } from './track/Track';
|
39
39
|
import {
|
40
40
|
isWeb,
|
41
|
+
Mutex,
|
41
42
|
sleep,
|
42
43
|
supportsAddTrack,
|
43
44
|
supportsSetCodecPreferences,
|
@@ -130,12 +131,15 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
130
131
|
/** specifies how often an initial join connection is allowed to retry */
|
131
132
|
private maxJoinAttempts: number = 1;
|
132
133
|
|
134
|
+
private closingLock: Mutex;
|
135
|
+
|
133
136
|
constructor(private options: InternalRoomOptions) {
|
134
137
|
super();
|
135
138
|
this.client = new SignalClient();
|
136
139
|
this.client.signalLatency = this.options.expSignalLatency;
|
137
140
|
this.reconnectPolicy = this.options.reconnectPolicy;
|
138
141
|
this.registerOnLineListener();
|
142
|
+
this.closingLock = new Mutex();
|
139
143
|
}
|
140
144
|
|
141
145
|
async join(
|
@@ -179,30 +183,40 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
179
183
|
}
|
180
184
|
}
|
181
185
|
|
182
|
-
close() {
|
183
|
-
|
184
|
-
this.
|
185
|
-
|
186
|
-
|
187
|
-
if (this.publisher && this.publisher.pc.signalingState !== 'closed') {
|
188
|
-
this.publisher.pc.getSenders().forEach((sender) => {
|
189
|
-
try {
|
190
|
-
// TODO: react-native-webrtc doesn't have removeTrack yet.
|
191
|
-
if (this.publisher?.pc.removeTrack) {
|
192
|
-
this.publisher?.pc.removeTrack(sender);
|
193
|
-
}
|
194
|
-
} catch (e) {
|
195
|
-
log.warn('could not removeTrack', { error: e });
|
196
|
-
}
|
197
|
-
});
|
198
|
-
this.publisher.close();
|
199
|
-
this.publisher = undefined;
|
186
|
+
async close() {
|
187
|
+
const unlock = await this.closingLock.lock();
|
188
|
+
if (this.isClosed) {
|
189
|
+
unlock();
|
190
|
+
return;
|
200
191
|
}
|
201
|
-
|
202
|
-
this.
|
203
|
-
this.
|
192
|
+
try {
|
193
|
+
this._isClosed = true;
|
194
|
+
this.emit(EngineEvent.Closing);
|
195
|
+
this.removeAllListeners();
|
196
|
+
this.deregisterOnLineListener();
|
197
|
+
this.clearPendingReconnect();
|
198
|
+
if (this.publisher && this.publisher.pc.signalingState !== 'closed') {
|
199
|
+
this.publisher.pc.getSenders().forEach((sender) => {
|
200
|
+
try {
|
201
|
+
// TODO: react-native-webrtc doesn't have removeTrack yet.
|
202
|
+
if (this.publisher?.pc.removeTrack) {
|
203
|
+
this.publisher?.pc.removeTrack(sender);
|
204
|
+
}
|
205
|
+
} catch (e) {
|
206
|
+
log.warn('could not removeTrack', { error: e });
|
207
|
+
}
|
208
|
+
});
|
209
|
+
this.publisher.close();
|
210
|
+
this.publisher = undefined;
|
211
|
+
}
|
212
|
+
if (this.subscriber) {
|
213
|
+
this.subscriber.close();
|
214
|
+
this.subscriber = undefined;
|
215
|
+
}
|
216
|
+
await this.client.close();
|
217
|
+
} finally {
|
218
|
+
unlock();
|
204
219
|
}
|
205
|
-
this.client.close();
|
206
220
|
}
|
207
221
|
|
208
222
|
addTrack(req: AddTrackRequest): Promise<TrackInfo> {
|
@@ -335,7 +349,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
335
349
|
const shouldEmit = this.pcState === PCState.New;
|
336
350
|
this.pcState = PCState.Connected;
|
337
351
|
if (shouldEmit) {
|
338
|
-
this.emit(EngineEvent.Connected);
|
352
|
+
this.emit(EngineEvent.Connected, joinResponse);
|
339
353
|
}
|
340
354
|
} else if (primaryPC.connectionState === 'failed') {
|
341
355
|
// on Safari, PeerConnection will switch to 'disconnected' during renegotiation
|
@@ -784,9 +798,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
784
798
|
}
|
785
799
|
|
786
800
|
if (this.client.isConnected) {
|
787
|
-
this.client.sendLeave();
|
801
|
+
await this.client.sendLeave();
|
788
802
|
}
|
789
|
-
this.client.close();
|
803
|
+
await this.client.close();
|
790
804
|
this.primaryPC = undefined;
|
791
805
|
this.publisher?.close();
|
792
806
|
this.publisher = undefined;
|
@@ -906,52 +920,99 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
906
920
|
}
|
907
921
|
}
|
908
922
|
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
923
|
+
/**
|
924
|
+
* @internal
|
925
|
+
*/
|
926
|
+
async ensureDataTransportConnected(
|
927
|
+
kind: DataPacket_Kind,
|
928
|
+
subscriber: boolean = this.subscriberPrimary,
|
929
|
+
) {
|
930
|
+
const transport = subscriber ? this.subscriber : this.publisher;
|
931
|
+
const transportName = subscriber ? 'Subscriber' : 'Publisher';
|
932
|
+
if (!transport) {
|
933
|
+
throw new ConnectionError(`${transportName} connection not set`);
|
916
934
|
}
|
917
935
|
|
918
|
-
if (
|
936
|
+
if (
|
937
|
+
!subscriber &&
|
938
|
+
!this.publisher?.isICEConnected &&
|
939
|
+
this.publisher?.pc.iceConnectionState !== 'checking'
|
940
|
+
) {
|
919
941
|
// start negotiation
|
920
942
|
this.negotiate();
|
921
943
|
}
|
922
944
|
|
923
|
-
const targetChannel = this.dataChannelForKind(kind);
|
945
|
+
const targetChannel = this.dataChannelForKind(kind, subscriber);
|
924
946
|
if (targetChannel?.readyState === 'open') {
|
925
947
|
return;
|
926
948
|
}
|
927
949
|
|
928
|
-
// wait until
|
950
|
+
// wait until ICE connected
|
929
951
|
const endTime = new Date().getTime() + this.peerConnectionTimeout;
|
930
952
|
while (new Date().getTime() < endTime) {
|
931
|
-
if (
|
953
|
+
if (
|
954
|
+
transport.isICEConnected &&
|
955
|
+
this.dataChannelForKind(kind, subscriber)?.readyState === 'open'
|
956
|
+
) {
|
932
957
|
return;
|
933
958
|
}
|
934
959
|
await sleep(50);
|
935
960
|
}
|
936
961
|
|
937
962
|
throw new ConnectionError(
|
938
|
-
`could not establish
|
963
|
+
`could not establish ${transportName} connection, state: ${transport.pc.iceConnectionState}`,
|
939
964
|
);
|
940
965
|
}
|
941
966
|
|
967
|
+
private async ensurePublisherConnected(kind: DataPacket_Kind) {
|
968
|
+
await this.ensureDataTransportConnected(kind, false);
|
969
|
+
}
|
970
|
+
|
942
971
|
/** @internal */
|
943
|
-
negotiate() {
|
944
|
-
|
945
|
-
|
946
|
-
|
972
|
+
negotiate(): Promise<void> {
|
973
|
+
// observe signal state
|
974
|
+
return new Promise<void>((resolve, reject) => {
|
975
|
+
if (!this.publisher) {
|
976
|
+
reject(new NegotiationError('publisher is not defined'));
|
977
|
+
return;
|
978
|
+
}
|
947
979
|
|
948
|
-
|
980
|
+
this.hasPublished = true;
|
949
981
|
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
982
|
+
const handleClosed = () => {
|
983
|
+
log.debug('engine disconnected while negotiation was ongoing');
|
984
|
+
cleanup();
|
985
|
+
resolve();
|
986
|
+
return;
|
987
|
+
};
|
988
|
+
|
989
|
+
this.on(EngineEvent.Closing, handleClosed);
|
990
|
+
|
991
|
+
const negotiationTimeout = setTimeout(() => {
|
992
|
+
reject('negotiation timed out');
|
993
|
+
this.handleDisconnect('negotiation');
|
994
|
+
}, this.peerConnectionTimeout);
|
995
|
+
|
996
|
+
const cleanup = () => {
|
997
|
+
clearTimeout(negotiationTimeout);
|
998
|
+
this.off(EngineEvent.Closing, handleClosed);
|
999
|
+
};
|
1000
|
+
|
1001
|
+
this.publisher.once(PCEvents.NegotiationStarted, () => {
|
1002
|
+
this.publisher?.once(PCEvents.NegotiationComplete, () => {
|
1003
|
+
cleanup();
|
1004
|
+
resolve();
|
1005
|
+
});
|
1006
|
+
});
|
1007
|
+
|
1008
|
+
this.publisher.negotiate((e) => {
|
1009
|
+
cleanup();
|
1010
|
+
reject(e);
|
1011
|
+
if (e instanceof NegotiationError) {
|
1012
|
+
this.fullReconnectOnNext = true;
|
1013
|
+
}
|
1014
|
+
this.handleDisconnect('negotiation');
|
1015
|
+
});
|
955
1016
|
});
|
956
1017
|
}
|
957
1018
|
|
@@ -1040,13 +1101,14 @@ async function getConnectedAddress(pc: RTCPeerConnection): Promise<string | unde
|
|
1040
1101
|
class SignalReconnectError extends Error {}
|
1041
1102
|
|
1042
1103
|
export type EngineEventCallbacks = {
|
1043
|
-
connected: () => void;
|
1104
|
+
connected: (joinResp: JoinResponse) => void;
|
1044
1105
|
disconnected: (reason?: DisconnectReason) => void;
|
1045
1106
|
resuming: () => void;
|
1046
1107
|
resumed: () => void;
|
1047
1108
|
restarting: () => void;
|
1048
1109
|
restarted: (joinResp: JoinResponse) => void;
|
1049
1110
|
signalResumed: () => void;
|
1111
|
+
closing: () => void;
|
1050
1112
|
mediaTrackAdded: (
|
1051
1113
|
track: MediaStreamTrack,
|
1052
1114
|
streams: MediaStream,
|