livekit-client 1.12.1 → 1.12.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +7 -3
- package/dist/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +389 -301
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +12735 -14958
- 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 +2 -2
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/connectionHelper/ConnectionCheck.d.ts +3 -2
- package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/Checker.d.ts +3 -2
- package/dist/src/connectionHelper/checks/Checker.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/webrtc.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/websocket.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +4 -2
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/KeyProvider.d.ts +4 -2
- package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
- package/dist/src/e2ee/constants.d.ts +1 -0
- package/dist/src/e2ee/constants.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +1 -0
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +4 -2
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +14 -3
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/proto/livekit_models_pb.d.ts +1264 -0
- package/dist/src/proto/livekit_models_pb.d.ts.map +1 -0
- package/dist/src/proto/livekit_rtc_pb.d.ts +1373 -0
- package/dist/src/proto/livekit_rtc_pb.d.ts.map +1 -0
- package/dist/src/room/PCTransport.d.ts +2 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +9 -5
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/RegionUrlProvider.d.ts +4 -1
- package/dist/src/room/RegionUrlProvider.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +15 -11
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +2 -2
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +5 -3
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/participant/ParticipantTrackPermission.d.ts +1 -1
- package/dist/src/room/participant/ParticipantTrackPermission.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +2 -3
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/timers.d.ts +5 -4
- package/dist/src/room/timers.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +3 -0
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrackPublication.d.ts +1 -1
- package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts +2 -2
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrackPublication.d.ts +1 -1
- package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +6 -4
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/TrackPublication.d.ts +7 -5
- package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/create.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +7 -0
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts +5 -1
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +3 -1
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/test/mocks.d.ts +4 -3
- package/dist/src/test/mocks.d.ts.map +1 -1
- package/dist/ts4.2/src/api/SignalClient.d.ts +2 -2
- package/dist/ts4.2/src/connectionHelper/ConnectionCheck.d.ts +3 -2
- package/dist/ts4.2/src/connectionHelper/checks/Checker.d.ts +3 -2
- package/dist/ts4.2/src/e2ee/E2eeManager.d.ts +4 -2
- package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +4 -2
- package/dist/ts4.2/src/e2ee/constants.d.ts +1 -0
- package/dist/ts4.2/src/e2ee/types.d.ts +1 -0
- package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +4 -2
- package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +14 -3
- package/dist/ts4.2/src/index.d.ts +1 -1
- package/dist/ts4.2/src/proto/livekit_models_pb.d.ts +1264 -0
- package/dist/ts4.2/src/proto/livekit_rtc_pb.d.ts +1373 -0
- package/dist/ts4.2/src/room/PCTransport.d.ts +2 -1
- package/dist/ts4.2/src/room/RTCEngine.d.ts +9 -5
- package/dist/ts4.2/src/room/RegionUrlProvider.d.ts +4 -1
- package/dist/ts4.2/src/room/Room.d.ts +15 -11
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +2 -2
- package/dist/ts4.2/src/room/participant/Participant.d.ts +5 -3
- package/dist/ts4.2/src/room/participant/ParticipantTrackPermission.d.ts +1 -1
- package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +2 -3
- package/dist/ts4.2/src/room/timers.d.ts +5 -4
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -0
- package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +1 -1
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -2
- package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +1 -1
- package/dist/ts4.2/src/room/track/Track.d.ts +6 -4
- package/dist/ts4.2/src/room/track/TrackPublication.d.ts +7 -5
- package/dist/ts4.2/src/room/track/options.d.ts +7 -0
- package/dist/ts4.2/src/room/track/utils.d.ts +5 -1
- package/dist/ts4.2/src/room/utils.d.ts +3 -1
- package/dist/ts4.2/src/test/mocks.d.ts +4 -3
- package/package.json +10 -10
- package/src/api/SignalClient.ts +104 -101
- package/src/connectionHelper/ConnectionCheck.ts +3 -2
- package/src/connectionHelper/checks/Checker.ts +3 -3
- package/src/connectionHelper/checks/webrtc.ts +66 -2
- package/src/connectionHelper/checks/websocket.ts +4 -0
- package/src/e2ee/E2eeManager.ts +4 -3
- package/src/e2ee/KeyProvider.ts +3 -2
- package/src/e2ee/constants.ts +4 -0
- package/src/e2ee/types.ts +1 -0
- package/src/e2ee/worker/FrameCryptor.test.ts +1 -3
- package/src/e2ee/worker/FrameCryptor.ts +5 -5
- package/src/e2ee/worker/ParticipantKeyHandler.ts +37 -6
- package/src/e2ee/worker/e2ee.worker.ts +1 -1
- package/src/index.ts +1 -1
- package/src/proto/livekit_models_pb.ts +2096 -0
- package/src/proto/livekit_rtc_pb.ts +2332 -0
- package/src/room/PCTransport.ts +1 -1
- package/src/room/RTCEngine.ts +24 -18
- package/src/room/RegionUrlProvider.ts +11 -2
- package/src/room/Room.test.ts +1 -0
- package/src/room/Room.ts +158 -79
- package/src/room/participant/LocalParticipant.ts +43 -59
- package/src/room/participant/Participant.ts +6 -4
- package/src/room/participant/ParticipantTrackPermission.ts +3 -3
- package/src/room/participant/RemoteParticipant.ts +5 -6
- package/src/room/participant/publishUtils.test.ts +1 -0
- package/src/room/track/LocalTrack.ts +24 -9
- package/src/room/track/LocalTrackPublication.ts +1 -1
- package/src/room/track/LocalVideoTrack.test.ts +2 -1
- package/src/room/track/LocalVideoTrack.ts +22 -22
- package/src/room/track/RemoteTrackPublication.ts +12 -7
- package/src/room/track/RemoteVideoTrack.test.ts +5 -4
- package/src/room/track/Track.ts +9 -6
- package/src/room/track/TrackPublication.ts +7 -5
- package/src/room/track/create.ts +9 -17
- package/src/room/track/facingMode.test.ts +1 -0
- package/src/room/track/options.ts +6 -0
- package/src/room/track/utils.test.ts +1 -0
- package/src/room/track/utils.ts +44 -2
- package/src/room/utils.test.ts +16 -0
- package/src/room/utils.ts +20 -4
- package/src/test/mocks.ts +7 -5
- package/src/utils/AsyncQueue.test.ts +1 -0
- package/src/utils/browserParser.test.ts +33 -3
- package/src/utils/browserParser.ts +1 -1
- package/dist/src/proto/google/protobuf/timestamp.d.ts +0 -146
- package/dist/src/proto/google/protobuf/timestamp.d.ts.map +0 -1
- package/dist/src/proto/livekit_models.d.ts +0 -2399
- package/dist/src/proto/livekit_models.d.ts.map +0 -1
- package/dist/src/proto/livekit_rtc.d.ts +0 -14352
- package/dist/src/proto/livekit_rtc.d.ts.map +0 -1
- package/dist/ts4.2/src/proto/google/protobuf/timestamp.d.ts +0 -150
- package/dist/ts4.2/src/proto/livekit_models.d.ts +0 -2659
- package/dist/ts4.2/src/proto/livekit_rtc.d.ts +0 -15764
- package/src/proto/google/protobuf/timestamp.ts +0 -230
- package/src/proto/livekit_models.ts +0 -4006
- package/src/proto/livekit_rtc.ts +0 -4672
package/src/room/PCTransport.ts
CHANGED
package/src/room/RTCEngine.ts
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
import EventEmitter from '
|
1
|
+
import { EventEmitter } from 'events';
|
2
2
|
import type { MediaAttributes } from 'sdp-transform';
|
3
|
-
import
|
3
|
+
import type TypedEventEmitter from 'typed-emitter';
|
4
4
|
import type { SignalOptions } from '../api/SignalClient';
|
5
|
+
import { SignalClient } from '../api/SignalClient';
|
5
6
|
import log from '../logger';
|
6
7
|
import type { InternalRoomOptions } from '../options';
|
7
8
|
import {
|
@@ -16,7 +17,7 @@ import {
|
|
16
17
|
SpeakerInfo,
|
17
18
|
TrackInfo,
|
18
19
|
UserPacket,
|
19
|
-
} from '../proto/
|
20
|
+
} from '../proto/livekit_models_pb';
|
20
21
|
import {
|
21
22
|
AddTrackRequest,
|
22
23
|
ConnectionQualityUpdate,
|
@@ -28,10 +29,10 @@ import {
|
|
28
29
|
SubscriptionPermissionUpdate,
|
29
30
|
SubscriptionResponse,
|
30
31
|
TrackPublishedResponse,
|
31
|
-
} from '../proto/
|
32
|
+
} from '../proto/livekit_rtc_pb';
|
32
33
|
import PCTransport, { PCEvents } from './PCTransport';
|
33
34
|
import type { ReconnectContext, ReconnectPolicy } from './ReconnectPolicy';
|
34
|
-
import { RegionUrlProvider } from './RegionUrlProvider';
|
35
|
+
import type { RegionUrlProvider } from './RegionUrlProvider';
|
35
36
|
import { roomConnectOptionDefaults } from './defaults';
|
36
37
|
import {
|
37
38
|
ConnectionError,
|
@@ -49,7 +50,6 @@ import { Track } from './track/Track';
|
|
49
50
|
import type { TrackPublishOptions, VideoCodec } from './track/options';
|
50
51
|
import {
|
51
52
|
Mutex,
|
52
|
-
isCloud,
|
53
53
|
isVideoCodec,
|
54
54
|
isWeb,
|
55
55
|
sleep,
|
@@ -72,7 +72,7 @@ enum PCState {
|
|
72
72
|
}
|
73
73
|
|
74
74
|
/** @internal */
|
75
|
-
export default class RTCEngine extends EventEmitter<EngineEventCallbacks> {
|
75
|
+
export default class RTCEngine extends (EventEmitter as new () => TypedEventEmitter<EngineEventCallbacks>) {
|
76
76
|
publisher?: PCTransport;
|
77
77
|
|
78
78
|
subscriber?: PCTransport;
|
@@ -122,7 +122,7 @@ export default class RTCEngine extends EventEmitter<EngineEventCallbacks> {
|
|
122
122
|
// this is helpful to know if we need to restart ICE on the publisher connection
|
123
123
|
private hasPublished: boolean = false;
|
124
124
|
|
125
|
-
// keep join info around for reconnect
|
125
|
+
// keep join info around for reconnect, this could be a region url
|
126
126
|
private url?: string;
|
127
127
|
|
128
128
|
private token?: string;
|
@@ -358,6 +358,11 @@ export default class RTCEngine extends EventEmitter<EngineEventCallbacks> {
|
|
358
358
|
return getConnectedAddress(this.primaryPC);
|
359
359
|
}
|
360
360
|
|
361
|
+
/* @internal */
|
362
|
+
setRegionUrlProvider(provider: RegionUrlProvider) {
|
363
|
+
this.regionUrlProvider = provider;
|
364
|
+
}
|
365
|
+
|
361
366
|
private configure(joinResponse: JoinResponse) {
|
362
367
|
// already configured
|
363
368
|
if (this.publisher || this.subscriber) {
|
@@ -628,12 +633,12 @@ export default class RTCEngine extends EventEmitter<EngineEventCallbacks> {
|
|
628
633
|
log.error('unsupported data type', message.data);
|
629
634
|
return;
|
630
635
|
}
|
631
|
-
const dp = DataPacket.
|
632
|
-
if (dp.value
|
636
|
+
const dp = DataPacket.fromBinary(new Uint8Array(buffer));
|
637
|
+
if (dp.value?.case === 'speaker') {
|
633
638
|
// dispatch speaker updates
|
634
|
-
this.emit(EngineEvent.ActiveSpeakersUpdate, dp.value.
|
635
|
-
} else if (dp.value
|
636
|
-
this.emit(EngineEvent.DataPacketReceived, dp.value.
|
639
|
+
this.emit(EngineEvent.ActiveSpeakersUpdate, dp.value.value.speakers);
|
640
|
+
} else if (dp.value?.case === 'user') {
|
641
|
+
this.emit(EngineEvent.DataPacketReceived, dp.value.value, dp.kind);
|
637
642
|
}
|
638
643
|
} finally {
|
639
644
|
unlock();
|
@@ -843,8 +848,10 @@ export default class RTCEngine extends EventEmitter<EngineEventCallbacks> {
|
|
843
848
|
log.debug(`reconnecting in ${delay}ms`);
|
844
849
|
|
845
850
|
this.clearReconnectTimeout();
|
846
|
-
if (this.
|
847
|
-
|
851
|
+
if (this.token && this.regionUrlProvider) {
|
852
|
+
// token may have been refreshed, we do not want to recreate the regionUrlProvider
|
853
|
+
// since the current engine may have inherited a regional url
|
854
|
+
this.regionUrlProvider.updateToken(this.token);
|
848
855
|
}
|
849
856
|
this.reconnectTimeout = CriticalTimers.setTimeout(
|
850
857
|
() => this.attemptReconnect(disconnectReason),
|
@@ -1114,13 +1121,12 @@ export default class RTCEngine extends EventEmitter<EngineEventCallbacks> {
|
|
1114
1121
|
};
|
1115
1122
|
this.once(EngineEvent.Restarted, onRestarted);
|
1116
1123
|
this.once(EngineEvent.Disconnected, onDisconnected);
|
1117
|
-
this.once(EngineEvent.Closing, onDisconnected);
|
1118
1124
|
});
|
1119
1125
|
};
|
1120
1126
|
|
1121
1127
|
/* @internal */
|
1122
1128
|
async sendDataPacket(packet: DataPacket, kind: DataPacket_Kind) {
|
1123
|
-
const msg =
|
1129
|
+
const msg = packet.toBinary();
|
1124
1130
|
|
1125
1131
|
// make sure we do have a data connection
|
1126
1132
|
await this.ensurePublisherConnected(kind);
|
@@ -1241,7 +1247,7 @@ export default class RTCEngine extends EventEmitter<EngineEventCallbacks> {
|
|
1241
1247
|
this.hasPublished = true;
|
1242
1248
|
|
1243
1249
|
const handleClosed = () => {
|
1244
|
-
log.
|
1250
|
+
log.debug('engine disconnected while negotiation was ongoing');
|
1245
1251
|
cleanup();
|
1246
1252
|
resolve();
|
1247
1253
|
return;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import log from '../logger';
|
2
|
-
import type { RegionInfo, RegionSettings } from '../proto/
|
2
|
+
import type { RegionInfo, RegionSettings } from '../proto/livekit_rtc_pb';
|
3
3
|
import { ConnectionError, ConnectionErrorReason } from './errors';
|
4
4
|
import { isCloud } from './utils';
|
5
5
|
|
@@ -21,10 +21,18 @@ export class RegionUrlProvider {
|
|
21
21
|
this.token = token;
|
22
22
|
}
|
23
23
|
|
24
|
+
updateToken(token: string) {
|
25
|
+
this.token = token;
|
26
|
+
}
|
27
|
+
|
24
28
|
isCloud() {
|
25
29
|
return isCloud(this.serverUrl);
|
26
30
|
}
|
27
31
|
|
32
|
+
getServerUrl() {
|
33
|
+
return this.serverUrl;
|
34
|
+
}
|
35
|
+
|
28
36
|
async getNextBestRegionUrl(abortSignal?: AbortSignal) {
|
29
37
|
if (!this.isCloud()) {
|
30
38
|
throw Error('region availability is only supported for LiveKit Cloud domains');
|
@@ -49,7 +57,8 @@ export class RegionUrlProvider {
|
|
49
57
|
this.attemptedRegions = [];
|
50
58
|
}
|
51
59
|
|
52
|
-
|
60
|
+
/* @internal */
|
61
|
+
async fetchRegionSettings(signal?: AbortSignal) {
|
53
62
|
const regionSettingsResponse = await fetch(`${getCloudConfigUrl(this.serverUrl)}/regions`, {
|
54
63
|
headers: { authorization: `Bearer ${this.token}` },
|
55
64
|
signal,
|
package/src/room/Room.test.ts
CHANGED
package/src/room/Room.ts
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
import
|
1
|
+
import { protoInt64 } from '@bufbuild/protobuf';
|
2
|
+
import { EventEmitter } from 'events';
|
3
|
+
import type TypedEmitter from 'typed-emitter';
|
2
4
|
import 'webrtc-adapter';
|
3
5
|
import { toProtoSessionDescription } from '../api/SignalClient';
|
4
6
|
import { EncryptionEvent } from '../e2ee';
|
@@ -24,15 +26,18 @@ import {
|
|
24
26
|
TrackSource,
|
25
27
|
TrackType,
|
26
28
|
UserPacket,
|
27
|
-
} from '../proto/
|
29
|
+
} from '../proto/livekit_models_pb';
|
28
30
|
import {
|
29
31
|
ConnectionQualityUpdate,
|
30
32
|
JoinResponse,
|
33
|
+
LeaveRequest,
|
31
34
|
SimulateScenario,
|
32
35
|
StreamStateUpdate,
|
33
36
|
SubscriptionPermissionUpdate,
|
34
37
|
SubscriptionResponse,
|
35
|
-
|
38
|
+
SyncState,
|
39
|
+
UpdateSubscription,
|
40
|
+
} from '../proto/livekit_rtc_pb';
|
36
41
|
import { getBrowser } from '../utils/browserParser';
|
37
42
|
import DeviceManager from './DeviceManager';
|
38
43
|
import RTCEngine from './RTCEngine';
|
@@ -69,6 +74,7 @@ import {
|
|
69
74
|
isCloud,
|
70
75
|
isWeb,
|
71
76
|
supportsSetSinkId,
|
77
|
+
toHttpUrl,
|
72
78
|
unpackStreamId,
|
73
79
|
unwrapConstraint,
|
74
80
|
} from './utils';
|
@@ -93,7 +99,7 @@ export const RoomState = ConnectionState;
|
|
93
99
|
*
|
94
100
|
* @noInheritDoc
|
95
101
|
*/
|
96
|
-
class Room extends EventEmitter<RoomEventCallbacks> {
|
102
|
+
class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>) {
|
97
103
|
state: ConnectionState = ConnectionState.Disconnected;
|
98
104
|
|
99
105
|
/** map of sid: [[RemoteParticipant]] */
|
@@ -142,12 +148,17 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
142
148
|
|
143
149
|
private connectionReconcileInterval?: ReturnType<typeof setInterval>;
|
144
150
|
|
151
|
+
private regionUrlProvider?: RegionUrlProvider;
|
152
|
+
|
153
|
+
private regionUrl?: string;
|
154
|
+
|
145
155
|
/**
|
146
156
|
* Creates a new Room, the primary construct for a LiveKit session.
|
147
157
|
* @param options
|
148
158
|
*/
|
149
159
|
constructor(options?: RoomOptions) {
|
150
160
|
super();
|
161
|
+
this.setMaxListeners(100);
|
151
162
|
this.participants = new Map();
|
152
163
|
this.cachedParticipantSids = [];
|
153
164
|
this.identityToSid = new Map();
|
@@ -337,15 +348,36 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
337
348
|
}
|
338
349
|
|
339
350
|
/**
|
340
|
-
*
|
341
|
-
*
|
342
|
-
*
|
343
|
-
*
|
344
|
-
*
|
345
|
-
*
|
351
|
+
* prepareConnection should be called as soon as the page is loaded, in order
|
352
|
+
* to speed up the connection attempt. This function will
|
353
|
+
* - perform DNS resolution and pre-warm the DNS cache
|
354
|
+
* - establish TLS connection and cache TLS keys
|
355
|
+
*
|
356
|
+
* With LiveKit Cloud, it will also determine the best edge data center for
|
357
|
+
* the current client to connect to if a token is provided.
|
346
358
|
*/
|
347
|
-
async prepareConnection(url: string) {
|
348
|
-
|
359
|
+
async prepareConnection(url: string, token?: string) {
|
360
|
+
if (this.state !== ConnectionState.Disconnected) {
|
361
|
+
return;
|
362
|
+
}
|
363
|
+
log.debug(`prepareConnection to ${url}`);
|
364
|
+
try {
|
365
|
+
if (isCloud(new URL(url)) && token) {
|
366
|
+
this.regionUrlProvider = new RegionUrlProvider(url, token);
|
367
|
+
const regionUrl = await this.regionUrlProvider.getNextBestRegionUrl();
|
368
|
+
// we will not replace the regionUrl if an attempt had already started
|
369
|
+
// to avoid overriding regionUrl after a new connection attempt had started
|
370
|
+
if (regionUrl && this.state === ConnectionState.Disconnected) {
|
371
|
+
this.regionUrl = regionUrl;
|
372
|
+
await fetch(toHttpUrl(regionUrl), { method: 'HEAD' });
|
373
|
+
log.debug(`prepared connection to ${regionUrl}`);
|
374
|
+
}
|
375
|
+
} else {
|
376
|
+
await fetch(toHttpUrl(url), { method: 'HEAD' });
|
377
|
+
}
|
378
|
+
} catch (e) {
|
379
|
+
log.warn('could not prepare connection', { error: e });
|
380
|
+
}
|
349
381
|
}
|
350
382
|
|
351
383
|
connect = async (url: string, token: string, opts?: RoomConnectOptions): Promise<void> => {
|
@@ -365,8 +397,23 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
365
397
|
}
|
366
398
|
|
367
399
|
this.setAndEmitConnectionState(ConnectionState.Connecting);
|
368
|
-
|
369
|
-
|
400
|
+
if (this.regionUrlProvider?.getServerUrl().toString() !== url) {
|
401
|
+
this.regionUrl = undefined;
|
402
|
+
this.regionUrlProvider = undefined;
|
403
|
+
}
|
404
|
+
if (isCloud(new URL(url))) {
|
405
|
+
if (this.regionUrlProvider === undefined) {
|
406
|
+
this.regionUrlProvider = new RegionUrlProvider(url, token);
|
407
|
+
} else {
|
408
|
+
this.regionUrlProvider.updateToken(token);
|
409
|
+
}
|
410
|
+
// trigger the first fetch without waiting for a response
|
411
|
+
// if initial connection fails, this will speed up picking regional url
|
412
|
+
// on subsequent runs
|
413
|
+
this.regionUrlProvider.fetchRegionSettings().catch((e) => {
|
414
|
+
log.warn('could not fetch region settings', { error: e });
|
415
|
+
});
|
416
|
+
}
|
370
417
|
|
371
418
|
const connectFn = async (
|
372
419
|
resolve: () => void,
|
@@ -376,6 +423,7 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
376
423
|
if (this.abortController) {
|
377
424
|
this.abortController.abort();
|
378
425
|
}
|
426
|
+
|
379
427
|
this.abortController = new AbortController();
|
380
428
|
|
381
429
|
// at this point the intention to connect has been signalled so we can allow cancelling of the connection via disconnect() again
|
@@ -387,13 +435,16 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
387
435
|
resolve();
|
388
436
|
} catch (e) {
|
389
437
|
if (
|
390
|
-
|
438
|
+
this.regionUrlProvider &&
|
391
439
|
e instanceof ConnectionError &&
|
392
|
-
e.reason !== ConnectionErrorReason.Cancelled
|
440
|
+
e.reason !== ConnectionErrorReason.Cancelled &&
|
441
|
+
e.reason !== ConnectionErrorReason.NotAllowed
|
393
442
|
) {
|
394
443
|
let nextUrl: string | null = null;
|
395
444
|
try {
|
396
|
-
nextUrl = await
|
445
|
+
nextUrl = await this.regionUrlProvider.getNextBestRegionUrl(
|
446
|
+
this.abortController?.signal,
|
447
|
+
);
|
397
448
|
} catch (error) {
|
398
449
|
if (
|
399
450
|
error instanceof ConnectionError &&
|
@@ -404,7 +455,9 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
404
455
|
}
|
405
456
|
}
|
406
457
|
if (nextUrl) {
|
407
|
-
log.
|
458
|
+
log.info('initial connection failed, retrying with another region', {
|
459
|
+
nextUrl,
|
460
|
+
});
|
408
461
|
await connectFn(resolve, reject, nextUrl);
|
409
462
|
} else {
|
410
463
|
reject(e);
|
@@ -414,9 +467,17 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
414
467
|
}
|
415
468
|
}
|
416
469
|
};
|
417
|
-
|
418
|
-
|
419
|
-
|
470
|
+
|
471
|
+
const regionUrl = this.regionUrl;
|
472
|
+
this.regionUrl = undefined;
|
473
|
+
this.connectFuture = new Future(
|
474
|
+
(resolve, reject) => {
|
475
|
+
connectFn(resolve, reject, regionUrl);
|
476
|
+
},
|
477
|
+
() => {
|
478
|
+
this.clearConnectionFutures();
|
479
|
+
},
|
480
|
+
);
|
420
481
|
|
421
482
|
return this.connectFuture.promise;
|
422
483
|
};
|
@@ -495,6 +556,9 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
495
556
|
// create engine if previously disconnected
|
496
557
|
this.maybeCreateEngine();
|
497
558
|
}
|
559
|
+
if (this.regionUrlProvider?.isCloud()) {
|
560
|
+
this.engine.setRegionUrlProvider(this.regionUrlProvider);
|
561
|
+
}
|
498
562
|
|
499
563
|
this.acquireAudioContext();
|
500
564
|
|
@@ -637,34 +701,34 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
637
701
|
await this.engine.client.handleOnClose('simulate disconnect');
|
638
702
|
break;
|
639
703
|
case 'speaker':
|
640
|
-
req = SimulateScenario
|
704
|
+
req = new SimulateScenario({
|
641
705
|
scenario: {
|
642
|
-
|
643
|
-
|
706
|
+
case: 'speakerUpdate',
|
707
|
+
value: 3,
|
644
708
|
},
|
645
709
|
});
|
646
710
|
break;
|
647
711
|
case 'node-failure':
|
648
|
-
req = SimulateScenario
|
712
|
+
req = new SimulateScenario({
|
649
713
|
scenario: {
|
650
|
-
|
651
|
-
|
714
|
+
case: 'nodeFailure',
|
715
|
+
value: true,
|
652
716
|
},
|
653
717
|
});
|
654
718
|
break;
|
655
719
|
case 'server-leave':
|
656
|
-
req = SimulateScenario
|
720
|
+
req = new SimulateScenario({
|
657
721
|
scenario: {
|
658
|
-
|
659
|
-
|
722
|
+
case: 'serverLeave',
|
723
|
+
value: true,
|
660
724
|
},
|
661
725
|
});
|
662
726
|
break;
|
663
727
|
case 'migration':
|
664
|
-
req = SimulateScenario
|
728
|
+
req = new SimulateScenario({
|
665
729
|
scenario: {
|
666
|
-
|
667
|
-
|
730
|
+
case: 'migration',
|
731
|
+
value: true,
|
668
732
|
},
|
669
733
|
});
|
670
734
|
break;
|
@@ -680,19 +744,21 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
680
744
|
break;
|
681
745
|
case 'force-tcp':
|
682
746
|
case 'force-tls':
|
683
|
-
req = SimulateScenario
|
747
|
+
req = new SimulateScenario({
|
684
748
|
scenario: {
|
685
|
-
|
686
|
-
|
749
|
+
case: 'switchCandidateProtocol',
|
750
|
+
value: scenario === 'force-tls' ? 2 : 1,
|
687
751
|
},
|
688
752
|
});
|
689
753
|
postAction = async () => {
|
690
754
|
const onLeave = this.engine.client.onLeave;
|
691
755
|
if (onLeave) {
|
692
|
-
onLeave(
|
693
|
-
|
694
|
-
|
695
|
-
|
756
|
+
onLeave(
|
757
|
+
new LeaveRequest({
|
758
|
+
reason: DisconnectReason.CLIENT_INITIATED,
|
759
|
+
canReconnect: true,
|
760
|
+
}),
|
761
|
+
);
|
696
762
|
}
|
697
763
|
};
|
698
764
|
break;
|
@@ -737,8 +803,19 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
737
803
|
dummyAudioEl.hidden = true;
|
738
804
|
const track = getEmptyAudioStreamTrack();
|
739
805
|
track.enabled = true;
|
740
|
-
|
806
|
+
const stream = new MediaStream([track]);
|
807
|
+
dummyAudioEl.srcObject = stream;
|
808
|
+
document.addEventListener('visibilitychange', () => {
|
809
|
+
if (!dummyAudioEl) {
|
810
|
+
return;
|
811
|
+
}
|
812
|
+
// set the srcObject to null on page hide in order to prevent lock screen controls to show up for it
|
813
|
+
dummyAudioEl.srcObject = document.hidden ? null : stream;
|
814
|
+
});
|
741
815
|
document.body.append(dummyAudioEl);
|
816
|
+
this.once(RoomEvent.Disconnected, () => {
|
817
|
+
dummyAudioEl?.remove();
|
818
|
+
});
|
742
819
|
}
|
743
820
|
elements.push(dummyAudioEl);
|
744
821
|
}
|
@@ -985,6 +1062,8 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
985
1062
|
if (!track.isMuted) {
|
986
1063
|
if (
|
987
1064
|
(track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) &&
|
1065
|
+
track.source !== Track.Source.ScreenShare &&
|
1066
|
+
track.source !== Track.Source.ScreenShareAudio &&
|
988
1067
|
!track.isUserProvided
|
989
1068
|
) {
|
990
1069
|
// we need to restart the track before publishing, often a full reconnect
|
@@ -1030,6 +1109,8 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1030
1109
|
return;
|
1031
1110
|
}
|
1032
1111
|
|
1112
|
+
this.regionUrl = undefined;
|
1113
|
+
|
1033
1114
|
try {
|
1034
1115
|
this.participants.forEach((p) => {
|
1035
1116
|
p.tracks.forEach((pub) => {
|
@@ -1461,25 +1542,27 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1461
1542
|
});
|
1462
1543
|
});
|
1463
1544
|
|
1464
|
-
this.engine.client.sendSyncState(
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1545
|
+
this.engine.client.sendSyncState(
|
1546
|
+
new SyncState({
|
1547
|
+
answer: toProtoSessionDescription({
|
1548
|
+
sdp: previousAnswer.sdp,
|
1549
|
+
type: previousAnswer.type,
|
1550
|
+
}),
|
1551
|
+
offer: previousOffer
|
1552
|
+
? toProtoSessionDescription({
|
1553
|
+
sdp: previousOffer.sdp,
|
1554
|
+
type: previousOffer.type,
|
1555
|
+
})
|
1556
|
+
: undefined,
|
1557
|
+
subscription: new UpdateSubscription({
|
1558
|
+
trackSids,
|
1559
|
+
subscribe: !autoSubscribe,
|
1560
|
+
participantTracks: [],
|
1561
|
+
}),
|
1562
|
+
publishTracks: this.localParticipant.publishedTracksInfo(),
|
1563
|
+
dataChannels: this.localParticipant.dataChannelsInfo(),
|
1468
1564
|
}),
|
1469
|
-
|
1470
|
-
? toProtoSessionDescription({
|
1471
|
-
sdp: previousOffer.sdp,
|
1472
|
-
type: previousOffer.type,
|
1473
|
-
})
|
1474
|
-
: undefined,
|
1475
|
-
subscription: {
|
1476
|
-
trackSids,
|
1477
|
-
subscribe: !autoSubscribe,
|
1478
|
-
participantTracks: [],
|
1479
|
-
},
|
1480
|
-
publishTracks: this.localParticipant.publishedTracksInfo(),
|
1481
|
-
dataChannels: this.localParticipant.dataChannelsInfo(),
|
1482
|
-
});
|
1565
|
+
);
|
1483
1566
|
}
|
1484
1567
|
|
1485
1568
|
/**
|
@@ -1539,9 +1622,9 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1539
1622
|
return true;
|
1540
1623
|
}
|
1541
1624
|
|
1542
|
-
private emitWhenConnected<
|
1543
|
-
event:
|
1544
|
-
...args:
|
1625
|
+
private emitWhenConnected<E extends keyof RoomEventCallbacks>(
|
1626
|
+
event: E,
|
1627
|
+
...args: Parameters<RoomEventCallbacks[E]>
|
1545
1628
|
): boolean {
|
1546
1629
|
if (this.state === ConnectionState.Connected) {
|
1547
1630
|
return this.emit(event, ...args);
|
@@ -1621,22 +1704,22 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1621
1704
|
...options.participants,
|
1622
1705
|
};
|
1623
1706
|
this.handleDisconnect();
|
1624
|
-
this.roomInfo = {
|
1707
|
+
this.roomInfo = new RoomModel({
|
1625
1708
|
sid: 'RM_SIMULATED',
|
1626
1709
|
name: 'simulated-room',
|
1627
1710
|
emptyTimeout: 0,
|
1628
1711
|
maxParticipants: 0,
|
1629
|
-
creationTime: new Date().getTime(),
|
1712
|
+
creationTime: protoInt64.parse(new Date().getTime()),
|
1630
1713
|
metadata: '',
|
1631
1714
|
numParticipants: 1,
|
1632
1715
|
numPublishers: 1,
|
1633
1716
|
turnPassword: '',
|
1634
1717
|
enabledCodecs: [],
|
1635
1718
|
activeRecording: false,
|
1636
|
-
};
|
1719
|
+
});
|
1637
1720
|
|
1638
1721
|
this.localParticipant.updateInfo(
|
1639
|
-
ParticipantInfo
|
1722
|
+
new ParticipantInfo({
|
1640
1723
|
identity: 'simulated-local',
|
1641
1724
|
name: 'local-name',
|
1642
1725
|
}),
|
@@ -1648,7 +1731,7 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1648
1731
|
if (publishOptions.video) {
|
1649
1732
|
const camPub = new LocalTrackPublication(
|
1650
1733
|
Track.Kind.Video,
|
1651
|
-
TrackInfo
|
1734
|
+
new TrackInfo({
|
1652
1735
|
source: TrackSource.CAMERA,
|
1653
1736
|
sid: Math.floor(Math.random() * 10_000).toString(),
|
1654
1737
|
type: TrackType.AUDIO,
|
@@ -1674,7 +1757,7 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1674
1757
|
if (publishOptions.audio) {
|
1675
1758
|
const audioPub = new LocalTrackPublication(
|
1676
1759
|
Track.Kind.Audio,
|
1677
|
-
TrackInfo
|
1760
|
+
new TrackInfo({
|
1678
1761
|
source: TrackSource.MICROPHONE,
|
1679
1762
|
sid: Math.floor(Math.random() * 10_000).toString(),
|
1680
1763
|
type: TrackType.AUDIO,
|
@@ -1691,12 +1774,12 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1691
1774
|
}
|
1692
1775
|
|
1693
1776
|
for (let i = 0; i < participantOptions.count - 1; i += 1) {
|
1694
|
-
let info: ParticipantInfo = ParticipantInfo
|
1777
|
+
let info: ParticipantInfo = new ParticipantInfo({
|
1695
1778
|
sid: Math.floor(Math.random() * 10_000).toString(),
|
1696
1779
|
identity: `simulated-${i}`,
|
1697
1780
|
state: ParticipantInfo_State.ACTIVE,
|
1698
1781
|
tracks: [],
|
1699
|
-
joinedAt: Date.now(),
|
1782
|
+
joinedAt: protoInt64.parse(Date.now()),
|
1700
1783
|
});
|
1701
1784
|
const p = this.getOrCreateParticipant(info.identity, info);
|
1702
1785
|
if (participantOptions.video) {
|
@@ -1706,7 +1789,7 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1706
1789
|
false,
|
1707
1790
|
true,
|
1708
1791
|
);
|
1709
|
-
const videoTrack = TrackInfo
|
1792
|
+
const videoTrack = new TrackInfo({
|
1710
1793
|
source: TrackSource.CAMERA,
|
1711
1794
|
sid: Math.floor(Math.random() * 10_000).toString(),
|
1712
1795
|
type: TrackType.AUDIO,
|
@@ -1716,7 +1799,7 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1716
1799
|
}
|
1717
1800
|
if (participantOptions.audio) {
|
1718
1801
|
const dummyTrack = getEmptyAudioStreamTrack();
|
1719
|
-
const audioTrack = TrackInfo
|
1802
|
+
const audioTrack = new TrackInfo({
|
1720
1803
|
source: TrackSource.MICROPHONE,
|
1721
1804
|
sid: Math.floor(Math.random() * 10_000).toString(),
|
1722
1805
|
type: TrackType.AUDIO,
|
@@ -1730,14 +1813,10 @@ class Room extends EventEmitter<RoomEventCallbacks> {
|
|
1730
1813
|
}
|
1731
1814
|
|
1732
1815
|
// /** @internal */
|
1733
|
-
emit<
|
1734
|
-
event:
|
1735
|
-
...args:
|
1816
|
+
emit<E extends keyof RoomEventCallbacks>(
|
1817
|
+
event: E,
|
1818
|
+
...args: Parameters<RoomEventCallbacks[E]>
|
1736
1819
|
): boolean {
|
1737
|
-
// emit<E extends keyof RoomEventCallbacks>(
|
1738
|
-
// event: E,
|
1739
|
-
// ...args: Parameters<RoomEventCallbacks[E]>
|
1740
|
-
// ): boolean {
|
1741
1820
|
// active speaker updates are too spammy
|
1742
1821
|
if (event !== RoomEvent.ActiveSpeakersChanged) {
|
1743
1822
|
log.debug(`room event ${event}`, { event, args });
|