livekit-client 1.9.0 → 1.9.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +6 -5
- package/dist/livekit-client.esm.mjs +200 -58
- 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 +1 -0
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +1 -0
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +4 -0
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +7 -1
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +3 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/ts4.2/src/api/SignalClient.d.ts +1 -0
- package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -0
- package/dist/ts4.2/src/room/Room.d.ts +4 -0
- package/dist/ts4.2/src/room/track/options.d.ts +7 -0
- package/dist/ts4.2/src/room/utils.d.ts +3 -0
- package/package.json +1 -1
- package/src/api/SignalClient.ts +15 -11
- package/src/room/PCTransport.ts +40 -1
- package/src/room/RTCEngine.ts +34 -1
- package/src/room/Room.ts +99 -42
- package/src/room/participant/LocalParticipant.ts +35 -4
- package/src/room/participant/publishUtils.ts +13 -5
- package/src/room/track/options.ts +14 -1
- package/src/room/utils.ts +18 -8
package/README.md
CHANGED
@@ -45,13 +45,12 @@ await room.connect(...);
|
|
45
45
|
|
46
46
|
```typescript
|
47
47
|
import {
|
48
|
-
|
49
|
-
Room,
|
50
|
-
RoomEvent,
|
48
|
+
Participant,
|
51
49
|
RemoteParticipant,
|
52
|
-
RemoteTrackPublication,
|
53
50
|
RemoteTrack,
|
54
|
-
|
51
|
+
RemoteTrackPublication,
|
52
|
+
Room,
|
53
|
+
RoomEvent,
|
55
54
|
} from 'livekit-client';
|
56
55
|
|
57
56
|
// creates a new room with options
|
@@ -296,7 +295,9 @@ You can have a look at the `"browerslist"` section of `package.json` for more de
|
|
296
295
|
If you are targeting legacy browsers, but still want adaptiveStream functionality you'll likely need to use polyfills for [ResizeObserver](https://www.npmjs.com/package/resize-observer-polyfill) and [IntersectionObserver](https://www.npmjs.com/package/intersection-observer).
|
297
296
|
|
298
297
|
<!--BEGIN_REPO_NAV-->
|
298
|
+
|
299
299
|
<br/><table>
|
300
|
+
|
300
301
|
<thead><tr><th colspan="2">LiveKit Ecosystem</th></tr></thead>
|
301
302
|
<tbody>
|
302
303
|
<tr><td>Client SDKs</td><td><a href="https://github.com/livekit/components-js">Components</a> · <b>JavaScript</b> · <a href="https://github.com/livekit/client-sdk-rust">Rust</a> · <a href="https://github.com/livekit/client-sdk-swift">iOS/macOS</a> · <a href="https://github.com/livekit/client-sdk-android">Android</a> · <a href="https://github.com/livekit/client-sdk-flutter">Flutter</a> · <a href="https://github.com/livekit/client-sdk-unity-web">Unity (web)</a> · <a href="https://github.com/livekit/client-sdk-react-native">React Native (beta)</a></td></tr><tr></tr>
|
@@ -14940,7 +14940,7 @@ var uaParser = {exports: {}};
|
|
14940
14940
|
var uaParserExports = uaParser.exports;
|
14941
14941
|
var UAParser = /*@__PURE__*/getDefaultExportFromCjs(uaParserExports);
|
14942
14942
|
|
14943
|
-
var version$1 = "1.9.
|
14943
|
+
var version$1 = "1.9.2";
|
14944
14944
|
|
14945
14945
|
const version = version$1;
|
14946
14946
|
const protocolVersion = 9;
|
@@ -15037,6 +15037,7 @@ function getNewAudioContext() {
|
|
15037
15037
|
}
|
15038
15038
|
|
15039
15039
|
const separator = '|';
|
15040
|
+
const ddExtensionURI = 'https://aomediacodec.github.io/av1-rtp-spec/#dependency-descriptor-rtp-header-extension';
|
15040
15041
|
function unpackStreamId(packed) {
|
15041
15042
|
const parts = packed.split(separator);
|
15042
15043
|
if (parts.length > 1) {
|
@@ -15064,7 +15065,6 @@ function supportsDynacast() {
|
|
15064
15065
|
function supportsAV1() {
|
15065
15066
|
const capabilities = RTCRtpReceiver.getCapabilities('video');
|
15066
15067
|
let hasAV1 = false;
|
15067
|
-
let hasDDExt = false;
|
15068
15068
|
if (capabilities) {
|
15069
15069
|
for (const codec of capabilities.codecs) {
|
15070
15070
|
if (codec.mimeType === 'video/AV1') {
|
@@ -15072,14 +15072,24 @@ function supportsAV1() {
|
|
15072
15072
|
break;
|
15073
15073
|
}
|
15074
15074
|
}
|
15075
|
-
|
15076
|
-
|
15077
|
-
|
15075
|
+
}
|
15076
|
+
return hasAV1;
|
15077
|
+
}
|
15078
|
+
function supportsVP9() {
|
15079
|
+
const capabilities = RTCRtpReceiver.getCapabilities('video');
|
15080
|
+
let hasVP9 = false;
|
15081
|
+
if (capabilities) {
|
15082
|
+
for (const codec of capabilities.codecs) {
|
15083
|
+
if (codec.mimeType === 'video/VP9') {
|
15084
|
+
hasVP9 = true;
|
15078
15085
|
break;
|
15079
15086
|
}
|
15080
15087
|
}
|
15081
15088
|
}
|
15082
|
-
return
|
15089
|
+
return hasVP9;
|
15090
|
+
}
|
15091
|
+
function isSVCCodec(codec) {
|
15092
|
+
return codec === 'av1' || codec === 'vp9';
|
15083
15093
|
}
|
15084
15094
|
function supportsSetSinkId(elm) {
|
15085
15095
|
if (!document) {
|
@@ -15499,13 +15509,7 @@ class SignalClient {
|
|
15499
15509
|
this.handleSignalResponse(resp);
|
15500
15510
|
};
|
15501
15511
|
this.ws.onclose = ev => {
|
15502
|
-
|
15503
|
-
livekitLogger.debug("websocket connection closed: ".concat(ev.reason));
|
15504
|
-
this.isConnected = false;
|
15505
|
-
if (this.onClose) {
|
15506
|
-
this.onClose(ev.reason);
|
15507
|
-
}
|
15508
|
-
this.ws = undefined;
|
15512
|
+
this.handleOnClose(ev.reason);
|
15509
15513
|
};
|
15510
15514
|
});
|
15511
15515
|
}
|
@@ -15774,6 +15778,17 @@ class SignalClient {
|
|
15774
15778
|
}
|
15775
15779
|
this.isReconnecting = false;
|
15776
15780
|
}
|
15781
|
+
handleOnClose(reason) {
|
15782
|
+
if (!this.isConnected) return;
|
15783
|
+
this.clearPingInterval();
|
15784
|
+
this.clearPingTimeout();
|
15785
|
+
livekitLogger.debug("websocket connection closed: ".concat(reason));
|
15786
|
+
this.isConnected = false;
|
15787
|
+
if (this.onClose) {
|
15788
|
+
this.onClose(reason);
|
15789
|
+
}
|
15790
|
+
this.ws = undefined;
|
15791
|
+
}
|
15777
15792
|
handleWSError(ev) {
|
15778
15793
|
livekitLogger.error('websocket error', ev);
|
15779
15794
|
}
|
@@ -15789,9 +15804,7 @@ class SignalClient {
|
|
15789
15804
|
}
|
15790
15805
|
this.pingTimeout = CriticalTimers.setTimeout(() => {
|
15791
15806
|
livekitLogger.warn("ping timeout triggered. last pong received at: ".concat(new Date(Date.now() - this.pingTimeoutDuration * 1000).toUTCString()));
|
15792
|
-
|
15793
|
-
this.onClose('ping timeout');
|
15794
|
-
}
|
15807
|
+
this.handleOnClose('ping timeout');
|
15795
15808
|
}, this.pingTimeoutDuration * 1000);
|
15796
15809
|
}
|
15797
15810
|
/**
|
@@ -16763,6 +16776,7 @@ class PCTransport extends EventEmitter$1 {
|
|
16763
16776
|
if (media.type === 'audio') {
|
16764
16777
|
ensureAudioNackAndStereo(media, [], []);
|
16765
16778
|
} else if (media.type === 'video') {
|
16779
|
+
ensureVideoDDExtensionForSVC(media);
|
16766
16780
|
// mung sdp for codec bitrate setting that can't apply by sendEncoding
|
16767
16781
|
this.trackBitrates.some(trackbr => {
|
16768
16782
|
if (!media.msid || !media.msid.includes(trackbr.sid)) {
|
@@ -16780,6 +16794,9 @@ class PCTransport extends EventEmitter$1 {
|
|
16780
16794
|
if (codecPayload > 0) {
|
16781
16795
|
if (!media.fmtp.some(fmtp => {
|
16782
16796
|
if (fmtp.payload === codecPayload) {
|
16797
|
+
if (!fmtp.config.includes('x-google-start-bitrate')) {
|
16798
|
+
fmtp.config += ";x-google-start-bitrate=".concat(trackbr.maxbr * 0.7);
|
16799
|
+
}
|
16783
16800
|
if (!fmtp.config.includes('x-google-max-bitrate')) {
|
16784
16801
|
fmtp.config += ";x-google-max-bitrate=".concat(trackbr.maxbr);
|
16785
16802
|
}
|
@@ -16789,7 +16806,7 @@ class PCTransport extends EventEmitter$1 {
|
|
16789
16806
|
})) {
|
16790
16807
|
media.fmtp.push({
|
16791
16808
|
payload: codecPayload,
|
16792
|
-
config: "x-google-max-bitrate=".concat(trackbr.maxbr)
|
16809
|
+
config: "x-google-start-bitrate=".concat(trackbr.maxbr * 0.7, ";x-google-max-bitrate=").concat(trackbr.maxbr)
|
16793
16810
|
});
|
16794
16811
|
}
|
16795
16812
|
}
|
@@ -16887,6 +16904,29 @@ function ensureAudioNackAndStereo(media, stereoMids, nackMids) {
|
|
16887
16904
|
}
|
16888
16905
|
}
|
16889
16906
|
}
|
16907
|
+
function ensureVideoDDExtensionForSVC(media) {
|
16908
|
+
var _a, _b, _c, _d;
|
16909
|
+
const codec = (_b = (_a = media.rtp.at(0)) === null || _a === void 0 ? void 0 : _a.codec) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
16910
|
+
if (!isSVCCodec(codec)) {
|
16911
|
+
return;
|
16912
|
+
}
|
16913
|
+
let maxID = 0;
|
16914
|
+
const ddFound = (_c = media.ext) === null || _c === void 0 ? void 0 : _c.some(ext => {
|
16915
|
+
if (ext.uri === ddExtensionURI) {
|
16916
|
+
return true;
|
16917
|
+
}
|
16918
|
+
if (ext.value > maxID) {
|
16919
|
+
maxID = ext.value;
|
16920
|
+
}
|
16921
|
+
return false;
|
16922
|
+
});
|
16923
|
+
if (!ddFound) {
|
16924
|
+
(_d = media.ext) === null || _d === void 0 ? void 0 : _d.push({
|
16925
|
+
value: maxID + 1,
|
16926
|
+
uri: ddExtensionURI
|
16927
|
+
});
|
16928
|
+
}
|
16929
|
+
}
|
16890
16930
|
function extractStereoAndNackAudioFromOffer(offer) {
|
16891
16931
|
var _a;
|
16892
16932
|
const stereoMids = [];
|
@@ -16996,6 +17036,9 @@ const backupCodecs = ['vp8', 'h264'];
|
|
16996
17036
|
function isBackupCodec(codec) {
|
16997
17037
|
return !!backupCodecs.find(backup => backup === codec);
|
16998
17038
|
}
|
17039
|
+
function isCodecEqual(c1, c2) {
|
17040
|
+
return (c1 === null || c1 === void 0 ? void 0 : c1.toLowerCase().replace(/audio\/|video\//y, '')) === (c2 === null || c2 === void 0 ? void 0 : c2.toLowerCase().replace(/audio\/|video\//y, ''));
|
17041
|
+
}
|
16999
17042
|
var AudioPresets;
|
17000
17043
|
(function (AudioPresets) {
|
17001
17044
|
AudioPresets.telephone = {
|
@@ -18531,7 +18574,7 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
18531
18574
|
} else {
|
18532
18575
|
livekitLogger.info("could not recover connection after ".concat(this.reconnectAttempts, " attempts, ").concat(Date.now() - this.reconnectStart, "ms. giving up"));
|
18533
18576
|
this.emit(EngineEvent.Disconnected);
|
18534
|
-
this.close();
|
18577
|
+
await this.close();
|
18535
18578
|
}
|
18536
18579
|
} finally {
|
18537
18580
|
this.attemptingReconnect = false;
|
@@ -18752,6 +18795,30 @@ class RTCEngine extends eventsExports.EventEmitter {
|
|
18752
18795
|
async ensurePublisherConnected(kind) {
|
18753
18796
|
await this.ensureDataTransportConnected(kind, false);
|
18754
18797
|
}
|
18798
|
+
/* @internal */
|
18799
|
+
verifyTransport() {
|
18800
|
+
// primary connection
|
18801
|
+
if (!this.primaryPC) {
|
18802
|
+
return false;
|
18803
|
+
}
|
18804
|
+
if (this.primaryPC.connectionState === 'closed' || this.primaryPC.connectionState === 'failed') {
|
18805
|
+
return false;
|
18806
|
+
}
|
18807
|
+
// also verify publisher connection if it's needed or different
|
18808
|
+
if (this.hasPublished && this.subscriberPrimary) {
|
18809
|
+
if (!this.publisher) {
|
18810
|
+
return false;
|
18811
|
+
}
|
18812
|
+
if (this.publisher.pc.connectionState === 'closed' || this.publisher.pc.connectionState === 'failed') {
|
18813
|
+
return false;
|
18814
|
+
}
|
18815
|
+
}
|
18816
|
+
// ensure signal is connected
|
18817
|
+
if (!this.client.ws || this.client.ws.readyState === WebSocket.CLOSED) {
|
18818
|
+
return false;
|
18819
|
+
}
|
18820
|
+
return true;
|
18821
|
+
}
|
18755
18822
|
/** @internal */
|
18756
18823
|
negotiate() {
|
18757
18824
|
// observe signal state
|
@@ -21064,7 +21131,7 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
21064
21131
|
livekitLogger.debug('using video encoding', videoEncoding);
|
21065
21132
|
}
|
21066
21133
|
const original = new VideoPreset(width, height, videoEncoding.maxBitrate, videoEncoding.maxFramerate);
|
21067
|
-
if (scalabilityMode && videoCodec
|
21134
|
+
if (scalabilityMode && isSVCCodec(videoCodec)) {
|
21068
21135
|
livekitLogger.debug("using svc with scalabilityMode ".concat(scalabilityMode));
|
21069
21136
|
const encodings = [];
|
21070
21137
|
// svc use first encoding as the original, so we sort encoding from high to low
|
@@ -21164,8 +21231,13 @@ function determineAppropriateEncoding(isScreenShare, width, height, codec) {
|
|
21164
21231
|
if (codec) {
|
21165
21232
|
switch (codec) {
|
21166
21233
|
case 'av1':
|
21234
|
+
encoding = _objectSpread2({}, encoding);
|
21167
21235
|
encoding.maxBitrate = encoding.maxBitrate * 0.7;
|
21168
21236
|
break;
|
21237
|
+
case 'vp9':
|
21238
|
+
encoding = _objectSpread2({}, encoding);
|
21239
|
+
encoding.maxBitrate = encoding.maxBitrate * 0.85;
|
21240
|
+
break;
|
21169
21241
|
}
|
21170
21242
|
}
|
21171
21243
|
return encoding;
|
@@ -21205,13 +21277,15 @@ function encodingsFromPresets(width, height, presets) {
|
|
21205
21277
|
}
|
21206
21278
|
const size = Math.min(width, height);
|
21207
21279
|
const rid = videoRids[idx];
|
21208
|
-
|
21280
|
+
const encoding = {
|
21209
21281
|
rid,
|
21210
21282
|
scaleResolutionDownBy: Math.max(1, size / Math.min(preset.width, preset.height)),
|
21211
|
-
maxBitrate: preset.encoding.maxBitrate
|
21212
|
-
|
21213
|
-
|
21214
|
-
|
21283
|
+
maxBitrate: preset.encoding.maxBitrate
|
21284
|
+
};
|
21285
|
+
if (preset.encoding.maxFramerate) {
|
21286
|
+
encoding.maxFramerate = preset.encoding.maxFramerate;
|
21287
|
+
}
|
21288
|
+
encodings.push(encoding);
|
21215
21289
|
});
|
21216
21290
|
return encodings;
|
21217
21291
|
}
|
@@ -21784,10 +21858,13 @@ class LocalParticipant extends Participant {
|
|
21784
21858
|
// we frequently get no data on layer 0 when enabled
|
21785
21859
|
opts.simulcast = false;
|
21786
21860
|
}
|
21787
|
-
// require full AV1 SVC support prior to using it
|
21861
|
+
// require full AV1/VP9 SVC support prior to using it
|
21788
21862
|
if (opts.videoCodec === 'av1' && !supportsAV1()) {
|
21789
21863
|
opts.videoCodec = undefined;
|
21790
21864
|
}
|
21865
|
+
if (opts.videoCodec === 'vp9' && !supportsVP9()) {
|
21866
|
+
opts.videoCodec = undefined;
|
21867
|
+
}
|
21791
21868
|
// handle track actions
|
21792
21869
|
track.on(TrackEvent.Muted, this.onTrackMuted);
|
21793
21870
|
track.on(TrackEvent.Unmuted, this.onTrackUnmuted);
|
@@ -21825,7 +21902,7 @@ class LocalParticipant extends Participant {
|
|
21825
21902
|
req.height = dims.height;
|
21826
21903
|
// for svc codecs, disable simulcast and use vp8 for backup codec
|
21827
21904
|
if (track instanceof LocalVideoTrack) {
|
21828
|
-
if ((opts
|
21905
|
+
if (isSVCCodec(opts.videoCodec)) {
|
21829
21906
|
// set scalabilityMode to 'L3T3' by default
|
21830
21907
|
opts.scalabilityMode = (_c = opts.scalabilityMode) !== null && _c !== void 0 ? _c : 'L3T3';
|
21831
21908
|
}
|
@@ -21856,6 +21933,28 @@ class LocalParticipant extends Participant {
|
|
21856
21933
|
throw new UnexpectedConnectionState('cannot publish track when not connected');
|
21857
21934
|
}
|
21858
21935
|
const ti = await this.engine.addTrack(req);
|
21936
|
+
let primaryCodecSupported = false;
|
21937
|
+
let backupCodecSupported = false;
|
21938
|
+
ti.codecs.forEach(c => {
|
21939
|
+
if (isCodecEqual(c.mimeType, opts.videoCodec)) {
|
21940
|
+
primaryCodecSupported = true;
|
21941
|
+
} else if (opts.backupCodec && isCodecEqual(c.mimeType, opts.backupCodec.codec)) {
|
21942
|
+
backupCodecSupported = true;
|
21943
|
+
}
|
21944
|
+
});
|
21945
|
+
if (req.simulcastCodecs.length > 0) {
|
21946
|
+
if (!primaryCodecSupported && !backupCodecSupported) {
|
21947
|
+
throw Error('cannot publish track, codec not supported by server');
|
21948
|
+
}
|
21949
|
+
if (!primaryCodecSupported && opts.backupCodec) {
|
21950
|
+
const backupCodec = opts.backupCodec;
|
21951
|
+
opts = _objectSpread2({}, opts);
|
21952
|
+
livekitLogger.debug("primary codec ".concat(opts.videoCodec, " not supported, fallback to ").concat(backupCodec.codec));
|
21953
|
+
opts.videoCodec = backupCodec.codec;
|
21954
|
+
opts.videoEncoding = backupCodec.encoding;
|
21955
|
+
encodings = simEncodings;
|
21956
|
+
}
|
21957
|
+
}
|
21859
21958
|
const publication = new LocalTrackPublication(track.kind, ti, track);
|
21860
21959
|
// save options for when it needs to be republished again
|
21861
21960
|
publication.options = opts;
|
@@ -21869,7 +21968,7 @@ class LocalParticipant extends Participant {
|
|
21869
21968
|
});
|
21870
21969
|
// store RTPSender
|
21871
21970
|
track.sender = await this.engine.createSender(track, opts, encodings);
|
21872
|
-
if (track.codec
|
21971
|
+
if (track.codec && isSVCCodec(track.codec) && encodings && ((_d = encodings[0]) === null || _d === void 0 ? void 0 : _d.maxBitrate)) {
|
21873
21972
|
this.engine.publisher.setTrackCodecBitrate(req.cid, track.codec, encodings[0].maxBitrate / 1000);
|
21874
21973
|
}
|
21875
21974
|
this.engine.negotiate();
|
@@ -22170,6 +22269,7 @@ var ConnectionState;
|
|
22170
22269
|
ConnectionState["Connected"] = "connected";
|
22171
22270
|
ConnectionState["Reconnecting"] = "reconnecting";
|
22172
22271
|
})(ConnectionState || (ConnectionState = {}));
|
22272
|
+
const connectionReconcileFrequency = 2 * 1000;
|
22173
22273
|
/** @deprecated RoomState has been renamed to [[ConnectionState]] */
|
22174
22274
|
const RoomState = ConnectionState;
|
22175
22275
|
/**
|
@@ -22349,6 +22449,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22349
22449
|
}
|
22350
22450
|
this.setAndEmitConnectionState(ConnectionState.Connected);
|
22351
22451
|
this.emit(RoomEvent.Connected);
|
22452
|
+
this.registerConnectionReconcile();
|
22352
22453
|
};
|
22353
22454
|
/**
|
22354
22455
|
* disconnects the room, emits [[RoomEvent.Disconnected]]
|
@@ -22392,6 +22493,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22392
22493
|
await this.disconnect();
|
22393
22494
|
};
|
22394
22495
|
this.handleRestarting = () => {
|
22496
|
+
this.clearConnectionReconcile();
|
22395
22497
|
// also unwind existing participants & existing subscriptions
|
22396
22498
|
for (const p of this.participants.values()) {
|
22397
22499
|
this.handleParticipantDisconnected(p.sid, p);
|
@@ -22404,6 +22506,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22404
22506
|
livekitLogger.debug("signal reconnected to server", {
|
22405
22507
|
region: joinResponse.serverRegion
|
22406
22508
|
});
|
22509
|
+
this.cachedParticipantSids = [];
|
22407
22510
|
this.applyJoinResponse(joinResponse);
|
22408
22511
|
try {
|
22409
22512
|
// unpublish & republish tracks
|
@@ -22447,6 +22550,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22447
22550
|
}
|
22448
22551
|
this.setAndEmitConnectionState(ConnectionState.Connected);
|
22449
22552
|
this.emit(RoomEvent.Reconnected);
|
22553
|
+
this.registerConnectionReconcile();
|
22450
22554
|
// emit participant connected events after connection has been re-established
|
22451
22555
|
this.participants.forEach(participant => {
|
22452
22556
|
this.emit(RoomEvent.ParticipantConnected, participant);
|
@@ -22647,6 +22751,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22647
22751
|
};
|
22648
22752
|
this.setMaxListeners(100);
|
22649
22753
|
this.participants = new Map();
|
22754
|
+
this.cachedParticipantSids = [];
|
22650
22755
|
this.identityToSid = new Map();
|
22651
22756
|
this.options = _objectSpread2(_objectSpread2({}, roomOptionDefaults), options);
|
22652
22757
|
this.options.audioCaptureDefaults = _objectSpread2(_objectSpread2({}, audioDefaults), options === null || options === void 0 ? void 0 : options.audioCaptureDefaults);
|
@@ -22687,7 +22792,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22687
22792
|
return (_b = (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.numPublishers) !== null && _b !== void 0 ? _b : 0;
|
22688
22793
|
}
|
22689
22794
|
maybeCreateEngine() {
|
22690
|
-
if (this.engine) {
|
22795
|
+
if (this.engine && !this.engine.isClosed) {
|
22691
22796
|
return;
|
22692
22797
|
}
|
22693
22798
|
this.engine = new RTCEngine(this.options);
|
@@ -22702,13 +22807,20 @@ class Room extends eventsExports.EventEmitter {
|
|
22702
22807
|
}).on(EngineEvent.Disconnected, reason => {
|
22703
22808
|
this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, reason);
|
22704
22809
|
}).on(EngineEvent.ActiveSpeakersUpdate, this.handleActiveSpeakersUpdate).on(EngineEvent.DataPacketReceived, this.handleDataPacket).on(EngineEvent.Resuming, () => {
|
22810
|
+
this.clearConnectionReconcile();
|
22705
22811
|
if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
|
22706
22812
|
this.emit(RoomEvent.Reconnecting);
|
22707
22813
|
}
|
22814
|
+
this.cachedParticipantSids = Array.from(this.participants.keys());
|
22708
22815
|
}).on(EngineEvent.Resumed, () => {
|
22709
22816
|
this.setAndEmitConnectionState(ConnectionState.Connected);
|
22710
22817
|
this.emit(RoomEvent.Reconnected);
|
22818
|
+
this.registerConnectionReconcile();
|
22711
22819
|
this.updateSubscriptions();
|
22820
|
+
// once reconnected, figure out if any participants connected during reconnect and emit events for it
|
22821
|
+
const diffParticipants = Array.from(this.participants.values()).filter(p => !this.cachedParticipantSids.includes(p.sid));
|
22822
|
+
diffParticipants.forEach(p => this.emit(RoomEvent.ParticipantConnected, p));
|
22823
|
+
this.cachedParticipantSids = [];
|
22712
22824
|
}).on(EngineEvent.SignalResumed, () => {
|
22713
22825
|
if (this.state === ConnectionState.Reconnecting) {
|
22714
22826
|
this.sendSyncState();
|
@@ -23014,41 +23126,45 @@ class Room extends eventsExports.EventEmitter {
|
|
23014
23126
|
let shouldStopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
23015
23127
|
let reason = arguments.length > 1 ? arguments[1] : undefined;
|
23016
23128
|
var _a;
|
23129
|
+
this.clearConnectionReconcile();
|
23017
23130
|
if (this.state === ConnectionState.Disconnected) {
|
23018
23131
|
return;
|
23019
23132
|
}
|
23020
|
-
|
23021
|
-
|
23022
|
-
p.
|
23133
|
+
try {
|
23134
|
+
this.participants.forEach(p => {
|
23135
|
+
p.tracks.forEach(pub => {
|
23136
|
+
p.unpublishTrack(pub.trackSid);
|
23137
|
+
});
|
23023
23138
|
});
|
23024
|
-
|
23025
|
-
|
23026
|
-
|
23027
|
-
|
23028
|
-
|
23029
|
-
|
23030
|
-
|
23031
|
-
|
23032
|
-
|
23139
|
+
this.localParticipant.tracks.forEach(pub => {
|
23140
|
+
var _a, _b;
|
23141
|
+
if (pub.track) {
|
23142
|
+
this.localParticipant.unpublishTrack(pub.track, shouldStopTracks);
|
23143
|
+
}
|
23144
|
+
if (shouldStopTracks) {
|
23145
|
+
(_a = pub.track) === null || _a === void 0 ? void 0 : _a.detach();
|
23146
|
+
(_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
|
23147
|
+
}
|
23148
|
+
});
|
23149
|
+
this.localParticipant.off(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).off(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).off(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).off(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).off(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).off(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).off(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).off(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).off(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
|
23150
|
+
this.localParticipant.tracks.clear();
|
23151
|
+
this.localParticipant.videoTracks.clear();
|
23152
|
+
this.localParticipant.audioTracks.clear();
|
23153
|
+
this.participants.clear();
|
23154
|
+
this.activeSpeakers = [];
|
23155
|
+
if (this.audioContext && typeof this.options.expWebAudioMix === 'boolean') {
|
23156
|
+
this.audioContext.close();
|
23157
|
+
this.audioContext = undefined;
|
23158
|
+
}
|
23159
|
+
if (isWeb()) {
|
23160
|
+
window.removeEventListener('beforeunload', this.onPageLeave);
|
23161
|
+
window.removeEventListener('pagehide', this.onPageLeave);
|
23162
|
+
(_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.removeEventListener('devicechange', this.handleDeviceChange);
|
23033
23163
|
}
|
23034
|
-
}
|
23035
|
-
|
23036
|
-
|
23037
|
-
this.localParticipant.videoTracks.clear();
|
23038
|
-
this.localParticipant.audioTracks.clear();
|
23039
|
-
this.participants.clear();
|
23040
|
-
this.activeSpeakers = [];
|
23041
|
-
if (this.audioContext && typeof this.options.expWebAudioMix === 'boolean') {
|
23042
|
-
this.audioContext.close();
|
23043
|
-
this.audioContext = undefined;
|
23044
|
-
}
|
23045
|
-
if (isWeb()) {
|
23046
|
-
window.removeEventListener('beforeunload', this.onPageLeave);
|
23047
|
-
window.removeEventListener('pagehide', this.onPageLeave);
|
23048
|
-
(_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.removeEventListener('devicechange', this.handleDeviceChange);
|
23164
|
+
} finally {
|
23165
|
+
this.setAndEmitConnectionState(ConnectionState.Disconnected);
|
23166
|
+
this.emit(RoomEvent.Disconnected, reason);
|
23049
23167
|
}
|
23050
|
-
this.setAndEmitConnectionState(ConnectionState.Disconnected);
|
23051
|
-
this.emit(RoomEvent.Disconnected, reason);
|
23052
23168
|
}
|
23053
23169
|
handleParticipantDisconnected(sid, participant) {
|
23054
23170
|
// remove and send event
|
@@ -23201,6 +23317,32 @@ class Room extends eventsExports.EventEmitter {
|
|
23201
23317
|
}
|
23202
23318
|
}
|
23203
23319
|
}
|
23320
|
+
registerConnectionReconcile() {
|
23321
|
+
this.clearConnectionReconcile();
|
23322
|
+
let consecutiveFailures = 0;
|
23323
|
+
this.connectionReconcileInterval = CriticalTimers.setInterval(() => {
|
23324
|
+
if (
|
23325
|
+
// ensure we didn't tear it down
|
23326
|
+
!this.engine ||
|
23327
|
+
// engine detected close, but Room missed it
|
23328
|
+
this.engine.isClosed ||
|
23329
|
+
// transports failed without notifying engine
|
23330
|
+
!this.engine.verifyTransport()) {
|
23331
|
+
consecutiveFailures++;
|
23332
|
+
livekitLogger.warn('detected connection state mismatch', {
|
23333
|
+
numFailures: consecutiveFailures
|
23334
|
+
});
|
23335
|
+
if (consecutiveFailures >= 3) this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, DisconnectReason.UNKNOWN_REASON);
|
23336
|
+
} else {
|
23337
|
+
consecutiveFailures = 0;
|
23338
|
+
}
|
23339
|
+
}, connectionReconcileFrequency);
|
23340
|
+
}
|
23341
|
+
clearConnectionReconcile() {
|
23342
|
+
if (this.connectionReconcileInterval) {
|
23343
|
+
CriticalTimers.clearInterval(this.connectionReconcileInterval);
|
23344
|
+
}
|
23345
|
+
}
|
23204
23346
|
setAndEmitConnectionState(state) {
|
23205
23347
|
if (state === this.state) {
|
23206
23348
|
// unchanged
|
@@ -23784,5 +23926,5 @@ class ConnectionCheck extends EventEmitter$1 {
|
|
23784
23926
|
}
|
23785
23927
|
}
|
23786
23928
|
|
23787
|
-
export { AudioPresets, ConnectionCheck, ConnectionError, ConnectionQuality, ConnectionState, CriticalTimers, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EngineEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, MediaDeviceFailure, NegotiationError, Participant, ParticipantEvent, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, RoomState, ScreenSharePresets, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, createAudioAnalyser, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, detachTrack, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, isBackupCodec, isBrowserSupported, protocolVersion, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, version };
|
23929
|
+
export { AudioPresets, ConnectionCheck, ConnectionError, ConnectionQuality, ConnectionState, CriticalTimers, DataPacket_Kind, DefaultReconnectPolicy, DeviceUnsupportedError, DisconnectReason, EngineEvent, LivekitError, LocalAudioTrack, LocalParticipant, LocalTrack, LocalTrackPublication, LocalVideoTrack, LogLevel, MediaDeviceFailure, NegotiationError, Participant, ParticipantEvent, PublishDataError, RemoteAudioTrack, RemoteParticipant, RemoteTrack, RemoteTrackPublication, RemoteVideoTrack, Room, RoomEvent, RoomState, ScreenSharePresets, Track, TrackEvent, TrackInvalidError, TrackPublication, UnexpectedConnectionState, UnsupportedServer, VideoPreset, VideoPresets, VideoPresets43, VideoQuality, attachToElement, createAudioAnalyser, createLocalAudioTrack, createLocalScreenTracks, createLocalTracks, createLocalVideoTrack, detachTrack, getEmptyAudioStreamTrack, getEmptyVideoStreamTrack, isBackupCodec, isBrowserSupported, isCodecEqual, protocolVersion, setLogExtension, setLogLevel, supportsAV1, supportsAdaptiveStream, supportsDynacast, version };
|
23788
23930
|
//# sourceMappingURL=livekit-client.esm.mjs.map
|