livekit-client 1.9.0 → 1.9.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 +6 -5
- package/dist/livekit-client.esm.mjs +96 -17
- 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/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +1 -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/room/Room.d.ts +1 -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/room/PCTransport.ts +40 -1
- package/src/room/Room.ts +12 -0
- 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.1";
|
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) {
|
@@ -16763,6 +16773,7 @@ class PCTransport extends EventEmitter$1 {
|
|
16763
16773
|
if (media.type === 'audio') {
|
16764
16774
|
ensureAudioNackAndStereo(media, [], []);
|
16765
16775
|
} else if (media.type === 'video') {
|
16776
|
+
ensureVideoDDExtensionForSVC(media);
|
16766
16777
|
// mung sdp for codec bitrate setting that can't apply by sendEncoding
|
16767
16778
|
this.trackBitrates.some(trackbr => {
|
16768
16779
|
if (!media.msid || !media.msid.includes(trackbr.sid)) {
|
@@ -16780,6 +16791,9 @@ class PCTransport extends EventEmitter$1 {
|
|
16780
16791
|
if (codecPayload > 0) {
|
16781
16792
|
if (!media.fmtp.some(fmtp => {
|
16782
16793
|
if (fmtp.payload === codecPayload) {
|
16794
|
+
if (!fmtp.config.includes('x-google-start-bitrate')) {
|
16795
|
+
fmtp.config += ";x-google-start-bitrate=".concat(trackbr.maxbr * 0.7);
|
16796
|
+
}
|
16783
16797
|
if (!fmtp.config.includes('x-google-max-bitrate')) {
|
16784
16798
|
fmtp.config += ";x-google-max-bitrate=".concat(trackbr.maxbr);
|
16785
16799
|
}
|
@@ -16789,7 +16803,7 @@ class PCTransport extends EventEmitter$1 {
|
|
16789
16803
|
})) {
|
16790
16804
|
media.fmtp.push({
|
16791
16805
|
payload: codecPayload,
|
16792
|
-
config: "x-google-max-bitrate=".concat(trackbr.maxbr)
|
16806
|
+
config: "x-google-start-bitrate=".concat(trackbr.maxbr * 0.7, ";x-google-max-bitrate=").concat(trackbr.maxbr)
|
16793
16807
|
});
|
16794
16808
|
}
|
16795
16809
|
}
|
@@ -16887,6 +16901,29 @@ function ensureAudioNackAndStereo(media, stereoMids, nackMids) {
|
|
16887
16901
|
}
|
16888
16902
|
}
|
16889
16903
|
}
|
16904
|
+
function ensureVideoDDExtensionForSVC(media) {
|
16905
|
+
var _a, _b, _c, _d;
|
16906
|
+
const codec = (_b = (_a = media.rtp.at(0)) === null || _a === void 0 ? void 0 : _a.codec) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
16907
|
+
if (!isSVCCodec(codec)) {
|
16908
|
+
return;
|
16909
|
+
}
|
16910
|
+
let maxID = 0;
|
16911
|
+
const ddFound = (_c = media.ext) === null || _c === void 0 ? void 0 : _c.some(ext => {
|
16912
|
+
if (ext.uri === ddExtensionURI) {
|
16913
|
+
return true;
|
16914
|
+
}
|
16915
|
+
if (ext.value > maxID) {
|
16916
|
+
maxID = ext.value;
|
16917
|
+
}
|
16918
|
+
return false;
|
16919
|
+
});
|
16920
|
+
if (!ddFound) {
|
16921
|
+
(_d = media.ext) === null || _d === void 0 ? void 0 : _d.push({
|
16922
|
+
value: maxID + 1,
|
16923
|
+
uri: ddExtensionURI
|
16924
|
+
});
|
16925
|
+
}
|
16926
|
+
}
|
16890
16927
|
function extractStereoAndNackAudioFromOffer(offer) {
|
16891
16928
|
var _a;
|
16892
16929
|
const stereoMids = [];
|
@@ -16996,6 +17033,9 @@ const backupCodecs = ['vp8', 'h264'];
|
|
16996
17033
|
function isBackupCodec(codec) {
|
16997
17034
|
return !!backupCodecs.find(backup => backup === codec);
|
16998
17035
|
}
|
17036
|
+
function isCodecEqual(c1, c2) {
|
17037
|
+
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, ''));
|
17038
|
+
}
|
16999
17039
|
var AudioPresets;
|
17000
17040
|
(function (AudioPresets) {
|
17001
17041
|
AudioPresets.telephone = {
|
@@ -21064,7 +21104,7 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
21064
21104
|
livekitLogger.debug('using video encoding', videoEncoding);
|
21065
21105
|
}
|
21066
21106
|
const original = new VideoPreset(width, height, videoEncoding.maxBitrate, videoEncoding.maxFramerate);
|
21067
|
-
if (scalabilityMode && videoCodec
|
21107
|
+
if (scalabilityMode && isSVCCodec(videoCodec)) {
|
21068
21108
|
livekitLogger.debug("using svc with scalabilityMode ".concat(scalabilityMode));
|
21069
21109
|
const encodings = [];
|
21070
21110
|
// svc use first encoding as the original, so we sort encoding from high to low
|
@@ -21164,8 +21204,13 @@ function determineAppropriateEncoding(isScreenShare, width, height, codec) {
|
|
21164
21204
|
if (codec) {
|
21165
21205
|
switch (codec) {
|
21166
21206
|
case 'av1':
|
21207
|
+
encoding = _objectSpread2({}, encoding);
|
21167
21208
|
encoding.maxBitrate = encoding.maxBitrate * 0.7;
|
21168
21209
|
break;
|
21210
|
+
case 'vp9':
|
21211
|
+
encoding = _objectSpread2({}, encoding);
|
21212
|
+
encoding.maxBitrate = encoding.maxBitrate * 0.85;
|
21213
|
+
break;
|
21169
21214
|
}
|
21170
21215
|
}
|
21171
21216
|
return encoding;
|
@@ -21205,13 +21250,15 @@ function encodingsFromPresets(width, height, presets) {
|
|
21205
21250
|
}
|
21206
21251
|
const size = Math.min(width, height);
|
21207
21252
|
const rid = videoRids[idx];
|
21208
|
-
|
21253
|
+
const encoding = {
|
21209
21254
|
rid,
|
21210
21255
|
scaleResolutionDownBy: Math.max(1, size / Math.min(preset.width, preset.height)),
|
21211
|
-
maxBitrate: preset.encoding.maxBitrate
|
21212
|
-
|
21213
|
-
|
21214
|
-
|
21256
|
+
maxBitrate: preset.encoding.maxBitrate
|
21257
|
+
};
|
21258
|
+
if (preset.encoding.maxFramerate) {
|
21259
|
+
encoding.maxFramerate = preset.encoding.maxFramerate;
|
21260
|
+
}
|
21261
|
+
encodings.push(encoding);
|
21215
21262
|
});
|
21216
21263
|
return encodings;
|
21217
21264
|
}
|
@@ -21784,10 +21831,13 @@ class LocalParticipant extends Participant {
|
|
21784
21831
|
// we frequently get no data on layer 0 when enabled
|
21785
21832
|
opts.simulcast = false;
|
21786
21833
|
}
|
21787
|
-
// require full AV1 SVC support prior to using it
|
21834
|
+
// require full AV1/VP9 SVC support prior to using it
|
21788
21835
|
if (opts.videoCodec === 'av1' && !supportsAV1()) {
|
21789
21836
|
opts.videoCodec = undefined;
|
21790
21837
|
}
|
21838
|
+
if (opts.videoCodec === 'vp9' && !supportsVP9()) {
|
21839
|
+
opts.videoCodec = undefined;
|
21840
|
+
}
|
21791
21841
|
// handle track actions
|
21792
21842
|
track.on(TrackEvent.Muted, this.onTrackMuted);
|
21793
21843
|
track.on(TrackEvent.Unmuted, this.onTrackUnmuted);
|
@@ -21825,7 +21875,7 @@ class LocalParticipant extends Participant {
|
|
21825
21875
|
req.height = dims.height;
|
21826
21876
|
// for svc codecs, disable simulcast and use vp8 for backup codec
|
21827
21877
|
if (track instanceof LocalVideoTrack) {
|
21828
|
-
if ((opts
|
21878
|
+
if (isSVCCodec(opts.videoCodec)) {
|
21829
21879
|
// set scalabilityMode to 'L3T3' by default
|
21830
21880
|
opts.scalabilityMode = (_c = opts.scalabilityMode) !== null && _c !== void 0 ? _c : 'L3T3';
|
21831
21881
|
}
|
@@ -21856,6 +21906,28 @@ class LocalParticipant extends Participant {
|
|
21856
21906
|
throw new UnexpectedConnectionState('cannot publish track when not connected');
|
21857
21907
|
}
|
21858
21908
|
const ti = await this.engine.addTrack(req);
|
21909
|
+
let primaryCodecSupported = false;
|
21910
|
+
let backupCodecSupported = false;
|
21911
|
+
ti.codecs.forEach(c => {
|
21912
|
+
if (isCodecEqual(c.mimeType, opts.videoCodec)) {
|
21913
|
+
primaryCodecSupported = true;
|
21914
|
+
} else if (opts.backupCodec && isCodecEqual(c.mimeType, opts.backupCodec.codec)) {
|
21915
|
+
backupCodecSupported = true;
|
21916
|
+
}
|
21917
|
+
});
|
21918
|
+
if (req.simulcastCodecs.length > 0) {
|
21919
|
+
if (!primaryCodecSupported && !backupCodecSupported) {
|
21920
|
+
throw Error('cannot publish track, codec not supported by server');
|
21921
|
+
}
|
21922
|
+
if (!primaryCodecSupported && opts.backupCodec) {
|
21923
|
+
const backupCodec = opts.backupCodec;
|
21924
|
+
opts = _objectSpread2({}, opts);
|
21925
|
+
livekitLogger.debug("primary codec ".concat(opts.videoCodec, " not supported, fallback to ").concat(backupCodec.codec));
|
21926
|
+
opts.videoCodec = backupCodec.codec;
|
21927
|
+
opts.videoEncoding = backupCodec.encoding;
|
21928
|
+
encodings = simEncodings;
|
21929
|
+
}
|
21930
|
+
}
|
21859
21931
|
const publication = new LocalTrackPublication(track.kind, ti, track);
|
21860
21932
|
// save options for when it needs to be republished again
|
21861
21933
|
publication.options = opts;
|
@@ -21869,7 +21941,7 @@ class LocalParticipant extends Participant {
|
|
21869
21941
|
});
|
21870
21942
|
// store RTPSender
|
21871
21943
|
track.sender = await this.engine.createSender(track, opts, encodings);
|
21872
|
-
if (track.codec
|
21944
|
+
if (track.codec && isSVCCodec(track.codec) && encodings && ((_d = encodings[0]) === null || _d === void 0 ? void 0 : _d.maxBitrate)) {
|
21873
21945
|
this.engine.publisher.setTrackCodecBitrate(req.cid, track.codec, encodings[0].maxBitrate / 1000);
|
21874
21946
|
}
|
21875
21947
|
this.engine.negotiate();
|
@@ -22404,6 +22476,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22404
22476
|
livekitLogger.debug("signal reconnected to server", {
|
22405
22477
|
region: joinResponse.serverRegion
|
22406
22478
|
});
|
22479
|
+
this.cachedParticipantSids = [];
|
22407
22480
|
this.applyJoinResponse(joinResponse);
|
22408
22481
|
try {
|
22409
22482
|
// unpublish & republish tracks
|
@@ -22647,6 +22720,7 @@ class Room extends eventsExports.EventEmitter {
|
|
22647
22720
|
};
|
22648
22721
|
this.setMaxListeners(100);
|
22649
22722
|
this.participants = new Map();
|
22723
|
+
this.cachedParticipantSids = [];
|
22650
22724
|
this.identityToSid = new Map();
|
22651
22725
|
this.options = _objectSpread2(_objectSpread2({}, roomOptionDefaults), options);
|
22652
22726
|
this.options.audioCaptureDefaults = _objectSpread2(_objectSpread2({}, audioDefaults), options === null || options === void 0 ? void 0 : options.audioCaptureDefaults);
|
@@ -22705,10 +22779,15 @@ class Room extends eventsExports.EventEmitter {
|
|
22705
22779
|
if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
|
22706
22780
|
this.emit(RoomEvent.Reconnecting);
|
22707
22781
|
}
|
22782
|
+
this.cachedParticipantSids = Array.from(this.participants.keys());
|
22708
22783
|
}).on(EngineEvent.Resumed, () => {
|
22709
22784
|
this.setAndEmitConnectionState(ConnectionState.Connected);
|
22710
22785
|
this.emit(RoomEvent.Reconnected);
|
22711
22786
|
this.updateSubscriptions();
|
22787
|
+
// once reconnected, figure out if any participants connected during reconnect and emit events for it
|
22788
|
+
const diffParticipants = Array.from(this.participants.values()).filter(p => !this.cachedParticipantSids.includes(p.sid));
|
22789
|
+
diffParticipants.forEach(p => this.emit(RoomEvent.ParticipantConnected, p));
|
22790
|
+
this.cachedParticipantSids = [];
|
22712
22791
|
}).on(EngineEvent.SignalResumed, () => {
|
22713
22792
|
if (this.state === ConnectionState.Reconnecting) {
|
22714
22793
|
this.sendSyncState();
|
@@ -23784,5 +23863,5 @@ class ConnectionCheck extends EventEmitter$1 {
|
|
23784
23863
|
}
|
23785
23864
|
}
|
23786
23865
|
|
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 };
|
23866
|
+
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
23867
|
//# sourceMappingURL=livekit-client.esm.mjs.map
|