livekit-client 2.13.8 → 2.15.0
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/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +276 -117
- 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/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +1 -0
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +18 -0
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +1 -0
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +3 -0
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrackPublication.d.ts +1 -0
- package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts +7 -0
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrackPublication.d.ts +12 -3
- package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +1 -0
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/TrackPublication.d.ts +1 -0
- package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +5 -1
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts +3 -1
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +2 -1
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/ts4.2/src/room/PCTransport.d.ts +1 -0
- package/dist/ts4.2/src/room/events.d.ts +18 -0
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +1 -0
- package/dist/ts4.2/src/room/participant/Participant.d.ts +3 -0
- package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +1 -0
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +7 -0
- package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +12 -3
- package/dist/ts4.2/src/room/track/Track.d.ts +1 -0
- package/dist/ts4.2/src/room/track/TrackPublication.d.ts +1 -0
- package/dist/ts4.2/src/room/track/options.d.ts +6 -1
- package/dist/ts4.2/src/room/track/utils.d.ts +3 -1
- package/dist/ts4.2/src/room/utils.d.ts +2 -1
- package/package.json +11 -11
- package/src/e2ee/E2eeManager.ts +3 -2
- package/src/room/PCTransport.ts +88 -77
- package/src/room/Room.ts +2 -0
- package/src/room/events.ts +21 -0
- package/src/room/participant/LocalParticipant.ts +14 -2
- package/src/room/participant/Participant.ts +3 -0
- package/src/room/participant/RemoteParticipant.ts +1 -0
- package/src/room/participant/publishUtils.ts +3 -2
- package/src/room/track/LocalTrackPublication.ts +9 -1
- package/src/room/track/LocalVideoTrack.ts +68 -1
- package/src/room/track/RemoteTrackPublication.ts +91 -32
- package/src/room/track/Track.ts +1 -0
- package/src/room/track/TrackPublication.ts +1 -0
- package/src/room/track/create.ts +2 -2
- package/src/room/track/options.ts +6 -1
- package/src/room/track/utils.ts +12 -1
- package/src/room/utils.ts +37 -3
@@ -4414,6 +4414,18 @@ const VideoLayer = /* @__PURE__ */proto3.makeMessageType("livekit.VideoLayer", (
|
|
4414
4414
|
kind: "scalar",
|
4415
4415
|
T: 13
|
4416
4416
|
/* ScalarType.UINT32 */
|
4417
|
+
}, {
|
4418
|
+
no: 6,
|
4419
|
+
name: "spatial_layer",
|
4420
|
+
kind: "scalar",
|
4421
|
+
T: 5
|
4422
|
+
/* ScalarType.INT32 */
|
4423
|
+
}, {
|
4424
|
+
no: 7,
|
4425
|
+
name: "rid",
|
4426
|
+
kind: "scalar",
|
4427
|
+
T: 9
|
4428
|
+
/* ScalarType.STRING */
|
4417
4429
|
}]);
|
4418
4430
|
const DataPacket = /* @__PURE__ */proto3.makeMessageType("livekit.DataPacket", () => [{
|
4419
4431
|
no: 1,
|
@@ -4963,6 +4975,9 @@ const ClientInfo_SDK = /* @__PURE__ */proto3.makeEnum("livekit.ClientInfo.SDK",
|
|
4963
4975
|
}, {
|
4964
4976
|
no: 13,
|
4965
4977
|
name: "UNREAL"
|
4978
|
+
}, {
|
4979
|
+
no: 14,
|
4980
|
+
name: "ESP32"
|
4966
4981
|
}]);
|
4967
4982
|
const ClientConfiguration = /* @__PURE__ */proto3.makeMessageType("livekit.ClientConfiguration", () => [{
|
4968
4983
|
no: 1,
|
@@ -11025,6 +11040,19 @@ var ParticipantEvent;
|
|
11025
11040
|
* args: ([[LocalTrackPublication]])
|
11026
11041
|
*/
|
11027
11042
|
ParticipantEvent["LocalTrackUnpublished"] = "localTrackUnpublished";
|
11043
|
+
/**
|
11044
|
+
* A local track has been constrained by cpu.
|
11045
|
+
* This event is useful to know when to reduce the capture resolution of the track.
|
11046
|
+
*
|
11047
|
+
* This event is emitted on the local participant.
|
11048
|
+
*
|
11049
|
+
* args: ([[LocalVideoTrack]], [[LocalTrackPublication]])
|
11050
|
+
*/
|
11051
|
+
ParticipantEvent["LocalTrackCpuConstrained"] = "localTrackCpuConstrained";
|
11052
|
+
/**
|
11053
|
+
* @internal
|
11054
|
+
*/
|
11055
|
+
ParticipantEvent["LocalSenderCreated"] = "localSenderCreated";
|
11028
11056
|
/**
|
11029
11057
|
* Participant metadata is a simple way for app-specific state to be pushed to
|
11030
11058
|
* all users.
|
@@ -11101,6 +11129,10 @@ var ParticipantEvent;
|
|
11101
11129
|
*
|
11102
11130
|
*/
|
11103
11131
|
ParticipantEvent["TrackSubscriptionStatusChanged"] = "trackSubscriptionStatusChanged";
|
11132
|
+
/**
|
11133
|
+
* a local track has been constrained by cpu
|
11134
|
+
*/
|
11135
|
+
ParticipantEvent["TrackCpuConstrained"] = "trackCpuConstrained";
|
11104
11136
|
// fired only on LocalParticipant
|
11105
11137
|
/** @internal */
|
11106
11138
|
ParticipantEvent["MediaDevicesError"] = "mediaDevicesError";
|
@@ -11178,6 +11210,7 @@ var TrackEvent;
|
|
11178
11210
|
TrackEvent["Ended"] = "ended";
|
11179
11211
|
TrackEvent["Subscribed"] = "subscribed";
|
11180
11212
|
TrackEvent["Unsubscribed"] = "unsubscribed";
|
11213
|
+
TrackEvent["CpuConstrained"] = "cpuConstrained";
|
11181
11214
|
/** @internal */
|
11182
11215
|
TrackEvent["UpdateSettings"] = "updateSettings";
|
11183
11216
|
/** @internal */
|
@@ -11331,7 +11364,7 @@ function getOSVersion(ua) {
|
|
11331
11364
|
return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
|
11332
11365
|
}
|
11333
11366
|
|
11334
|
-
var version$1 = "2.
|
11367
|
+
var version$1 = "2.15.0";
|
11335
11368
|
|
11336
11369
|
const version = version$1;
|
11337
11370
|
const protocolVersion = 16;
|
@@ -11765,7 +11798,7 @@ class VideoPreset {
|
|
11765
11798
|
}
|
11766
11799
|
}
|
11767
11800
|
const backupCodecs = ['vp8', 'h264'];
|
11768
|
-
const videoCodecs = ['vp8', 'h264', 'vp9', 'av1'];
|
11801
|
+
const videoCodecs = ['vp8', 'h264', 'vp9', 'av1', 'h265'];
|
11769
11802
|
function isBackupCodec(codec) {
|
11770
11803
|
return !!backupCodecs.find(backup => backup === codec);
|
11771
11804
|
}
|
@@ -11902,6 +11935,10 @@ function supportsVP9() {
|
|
11902
11935
|
// Safari 16 and below does not support VP9
|
11903
11936
|
return false;
|
11904
11937
|
}
|
11938
|
+
if ((browser === null || browser === void 0 ? void 0 : browser.os) === 'iOS' && (browser === null || browser === void 0 ? void 0 : browser.osVersion) && compareVersions(browser.osVersion, '16') < 0) {
|
11939
|
+
// Safari 16 and below on iOS does not support VP9 we need the iOS check to account for other browsers running webkit under the hood
|
11940
|
+
return false;
|
11941
|
+
}
|
11905
11942
|
}
|
11906
11943
|
const capabilities = RTCRtpSender.getCapabilities('video');
|
11907
11944
|
let hasVP9 = false;
|
@@ -11945,16 +11982,16 @@ function isSafariBased() {
|
|
11945
11982
|
const b = getBrowser();
|
11946
11983
|
return (b === null || b === void 0 ? void 0 : b.name) === 'Safari' || (b === null || b === void 0 ? void 0 : b.os) === 'iOS';
|
11947
11984
|
}
|
11948
|
-
function
|
11985
|
+
function isSafari17Based() {
|
11949
11986
|
const b = getBrowser();
|
11950
|
-
return (b === null || b === void 0 ? void 0 : b.name) === 'Safari' && b.version.startsWith('17.');
|
11987
|
+
return (b === null || b === void 0 ? void 0 : b.name) === 'Safari' && b.version.startsWith('17.') || (b === null || b === void 0 ? void 0 : b.os) === 'iOS' && !!(b === null || b === void 0 ? void 0 : b.osVersion) && compareVersions(b.osVersion, '17') >= 0;
|
11951
11988
|
}
|
11952
11989
|
function isSafariSvcApi(browser) {
|
11953
11990
|
if (!browser) {
|
11954
11991
|
browser = getBrowser();
|
11955
11992
|
}
|
11956
11993
|
// Safari 18.4 requires legacy svc api and scaleResolutionDown to be set
|
11957
|
-
return (browser === null || browser === void 0 ? void 0 : browser.name) === 'Safari' && compareVersions(browser.version, '18.3') > 0;
|
11994
|
+
return (browser === null || browser === void 0 ? void 0 : browser.name) === 'Safari' && compareVersions(browser.version, '18.3') > 0 || (browser === null || browser === void 0 ? void 0 : browser.os) === 'iOS' && !!(browser === null || browser === void 0 ? void 0 : browser.osVersion) && compareVersions(browser.osVersion, '18.3') > 0;
|
11958
11995
|
}
|
11959
11996
|
function isMobile() {
|
11960
11997
|
var _a, _b;
|
@@ -12660,6 +12697,13 @@ function getTrackSourceFromProto(source) {
|
|
12660
12697
|
return Track.Source.Unknown;
|
12661
12698
|
}
|
12662
12699
|
}
|
12700
|
+
function areDimensionsSmaller(a, b) {
|
12701
|
+
return a.width * a.height < b.width * b.height;
|
12702
|
+
}
|
12703
|
+
function layerDimensionsFor(trackInfo, quality) {
|
12704
|
+
var _a;
|
12705
|
+
return (_a = trackInfo.layers) === null || _a === void 0 ? void 0 : _a.find(l => l.quality === quality);
|
12706
|
+
}
|
12663
12707
|
|
12664
12708
|
/**
|
12665
12709
|
* @experimental
|
@@ -12799,8 +12843,8 @@ class E2EEManager extends eventsExports.EventEmitter {
|
|
12799
12843
|
});
|
12800
12844
|
this.setParticipantCryptorEnabled(this.room.localParticipant.isE2EEEnabled, this.room.localParticipant.identity);
|
12801
12845
|
});
|
12802
|
-
room.localParticipant.on(ParticipantEvent.
|
12803
|
-
this.setupE2EESender(
|
12846
|
+
room.localParticipant.on(ParticipantEvent.LocalSenderCreated, (sender, track) => __awaiter(this, void 0, void 0, function* () {
|
12847
|
+
this.setupE2EESender(track, sender);
|
12804
12848
|
}));
|
12805
12849
|
keyProvider.on(KeyProviderEvent.SetKey, keyInfo => this.postKey(keyInfo)).on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) => this.postRatchetRequest(participantId, keyIndex));
|
12806
12850
|
}
|
@@ -14789,6 +14833,7 @@ class PCTransport extends eventsExports.EventEmitter {
|
|
14789
14833
|
this.loggerOptions = loggerOptions;
|
14790
14834
|
this.config = config;
|
14791
14835
|
this._pc = this.createPC();
|
14836
|
+
this.offerLock = new _();
|
14792
14837
|
}
|
14793
14838
|
createPC() {
|
14794
14839
|
const pc = new RTCPeerConnection(this.config);
|
@@ -14927,92 +14972,97 @@ class PCTransport extends eventsExports.EventEmitter {
|
|
14927
14972
|
createAndSendOffer(options) {
|
14928
14973
|
return __awaiter(this, void 0, void 0, function* () {
|
14929
14974
|
var _a;
|
14930
|
-
|
14931
|
-
|
14932
|
-
|
14933
|
-
|
14934
|
-
|
14935
|
-
|
14936
|
-
if (options === null || options === void 0 ? void 0 : options.iceRestart) {
|
14937
|
-
this.log.debug('restarting ICE', this.logContext);
|
14938
|
-
this.restartingIce = true;
|
14939
|
-
}
|
14940
|
-
if (this._pc && this._pc.signalingState === 'have-local-offer') {
|
14941
|
-
// we're waiting for the peer to accept our offer, so we'll just wait
|
14942
|
-
// the only exception to this is when ICE restart is needed
|
14943
|
-
const currentSD = this._pc.remoteDescription;
|
14944
|
-
if ((options === null || options === void 0 ? void 0 : options.iceRestart) && currentSD) {
|
14945
|
-
// TODO: handle when ICE restart is needed but we don't have a remote description
|
14946
|
-
// the best thing to do is to recreate the peerconnection
|
14947
|
-
yield this._pc.setRemoteDescription(currentSD);
|
14948
|
-
} else {
|
14949
|
-
this.renegotiate = true;
|
14975
|
+
const unlock = yield this.offerLock.lock();
|
14976
|
+
try {
|
14977
|
+
// increase the offer id at the start to ensure the offer is always > 0 so that we can use 0 as a default value for legacy behavior
|
14978
|
+
const offerId = this.latestOfferId + 1;
|
14979
|
+
this.latestOfferId = offerId;
|
14980
|
+
if (this.onOffer === undefined) {
|
14950
14981
|
return;
|
14951
14982
|
}
|
14952
|
-
|
14953
|
-
|
14954
|
-
|
14955
|
-
|
14956
|
-
|
14957
|
-
|
14958
|
-
|
14959
|
-
|
14960
|
-
|
14961
|
-
|
14962
|
-
|
14963
|
-
|
14964
|
-
|
14965
|
-
|
14966
|
-
|
14967
|
-
|
14968
|
-
|
14969
|
-
|
14970
|
-
|
14971
|
-
|
14972
|
-
|
14973
|
-
|
14974
|
-
|
14975
|
-
|
14983
|
+
if (options === null || options === void 0 ? void 0 : options.iceRestart) {
|
14984
|
+
this.log.debug('restarting ICE', this.logContext);
|
14985
|
+
this.restartingIce = true;
|
14986
|
+
}
|
14987
|
+
if (this._pc && this._pc.signalingState === 'have-local-offer') {
|
14988
|
+
// we're waiting for the peer to accept our offer, so we'll just wait
|
14989
|
+
// the only exception to this is when ICE restart is needed
|
14990
|
+
const currentSD = this._pc.remoteDescription;
|
14991
|
+
if ((options === null || options === void 0 ? void 0 : options.iceRestart) && currentSD) {
|
14992
|
+
// TODO: handle when ICE restart is needed but we don't have a remote description
|
14993
|
+
// the best thing to do is to recreate the peerconnection
|
14994
|
+
yield this._pc.setRemoteDescription(currentSD);
|
14995
|
+
} else {
|
14996
|
+
this.renegotiate = true;
|
14997
|
+
return;
|
14998
|
+
}
|
14999
|
+
} else if (!this._pc || this._pc.signalingState === 'closed') {
|
15000
|
+
this.log.warn('could not createOffer with closed peer connection', this.logContext);
|
15001
|
+
return;
|
15002
|
+
}
|
15003
|
+
// actually negotiate
|
15004
|
+
this.log.debug('starting to negotiate', this.logContext);
|
15005
|
+
const offer = yield this.pc.createOffer(options);
|
15006
|
+
this.log.debug('original offer', Object.assign({
|
15007
|
+
sdp: offer.sdp
|
15008
|
+
}, this.logContext));
|
15009
|
+
const sdpParsed = libExports.parse((_a = offer.sdp) !== null && _a !== void 0 ? _a : '');
|
15010
|
+
sdpParsed.media.forEach(media => {
|
15011
|
+
ensureIPAddrMatchVersion(media);
|
15012
|
+
if (media.type === 'audio') {
|
15013
|
+
ensureAudioNackAndStereo(media, [], []);
|
15014
|
+
} else if (media.type === 'video') {
|
15015
|
+
this.trackBitrates.some(trackbr => {
|
15016
|
+
if (!media.msid || !trackbr.cid || !media.msid.includes(trackbr.cid)) {
|
15017
|
+
return false;
|
15018
|
+
}
|
15019
|
+
let codecPayload = 0;
|
15020
|
+
media.rtp.some(rtp => {
|
15021
|
+
if (rtp.codec.toUpperCase() === trackbr.codec.toUpperCase()) {
|
15022
|
+
codecPayload = rtp.payload;
|
15023
|
+
return true;
|
15024
|
+
}
|
15025
|
+
return false;
|
15026
|
+
});
|
15027
|
+
if (codecPayload === 0) {
|
14976
15028
|
return true;
|
14977
15029
|
}
|
14978
|
-
|
14979
|
-
|
14980
|
-
|
14981
|
-
|
14982
|
-
|
14983
|
-
|
14984
|
-
|
14985
|
-
|
14986
|
-
|
14987
|
-
|
14988
|
-
|
14989
|
-
|
14990
|
-
|
14991
|
-
|
14992
|
-
|
14993
|
-
|
14994
|
-
|
14995
|
-
|
14996
|
-
// initial track's bitrate for all tracks
|
14997
|
-
if (!fmtp.config.includes('x-google-start-bitrate')) {
|
14998
|
-
fmtp.config += ";x-google-start-bitrate=".concat(startBitrate);
|
15030
|
+
if (isSVCCodec(trackbr.codec)) {
|
15031
|
+
this.ensureVideoDDExtensionForSVC(media, sdpParsed);
|
15032
|
+
}
|
15033
|
+
// TODO: av1 slow starting issue already fixed in chrome 124, clean this after some versions
|
15034
|
+
// mung sdp for av1 bitrate setting that can't apply by sendEncoding
|
15035
|
+
if (trackbr.codec !== 'av1') {
|
15036
|
+
return true;
|
15037
|
+
}
|
15038
|
+
const startBitrate = Math.round(trackbr.maxbr * startBitrateForSVC);
|
15039
|
+
for (const fmtp of media.fmtp) {
|
15040
|
+
if (fmtp.payload === codecPayload) {
|
15041
|
+
// if another track's fmtp already is set, we cannot override the bitrate
|
15042
|
+
// this has the unfortunate consequence of being forced to use the
|
15043
|
+
// initial track's bitrate for all tracks
|
15044
|
+
if (!fmtp.config.includes('x-google-start-bitrate')) {
|
15045
|
+
fmtp.config += ";x-google-start-bitrate=".concat(startBitrate);
|
15046
|
+
}
|
15047
|
+
break;
|
14999
15048
|
}
|
15000
|
-
break;
|
15001
15049
|
}
|
15002
|
-
|
15003
|
-
|
15004
|
-
}
|
15050
|
+
return true;
|
15051
|
+
});
|
15052
|
+
}
|
15053
|
+
});
|
15054
|
+
if (this.latestOfferId > offerId) {
|
15055
|
+
this.log.warn('latestOfferId mismatch', Object.assign(Object.assign({}, this.logContext), {
|
15056
|
+
latestOfferId: this.latestOfferId,
|
15057
|
+
offerId
|
15058
|
+
}));
|
15059
|
+
return;
|
15005
15060
|
}
|
15006
|
-
|
15007
|
-
|
15008
|
-
|
15009
|
-
|
15010
|
-
offerId
|
15011
|
-
}));
|
15012
|
-
return;
|
15061
|
+
yield this.setMungedSDP(offer, libExports.write(sdpParsed));
|
15062
|
+
this.onOffer(offer, this.latestOfferId);
|
15063
|
+
} finally {
|
15064
|
+
unlock();
|
15013
15065
|
}
|
15014
|
-
yield this.setMungedSDP(offer, libExports.write(sdpParsed));
|
15015
|
-
this.onOffer(offer, this.latestOfferId);
|
15016
15066
|
});
|
15017
15067
|
}
|
15018
15068
|
createAndSetAnswer() {
|
@@ -16677,7 +16727,7 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
|
|
16677
16727
|
// before M113.
|
16678
16728
|
// Announced here: https://groups.google.com/g/discuss-webrtc/c/-QQ3pxrl-fw?pli=1
|
16679
16729
|
const browser = getBrowser();
|
16680
|
-
if (
|
16730
|
+
if (isSafariBased() ||
|
16681
16731
|
// Even tho RN runs M114, it does not produce SVC layers when a single encoding
|
16682
16732
|
// is provided. So we'll use the legacy SVC specification for now.
|
16683
16733
|
// TODO: when we upstream libwebrtc, this will need additional verification
|
@@ -16797,6 +16847,7 @@ function determineAppropriateEncoding(isScreenShare, width, height, codec) {
|
|
16797
16847
|
if (codec) {
|
16798
16848
|
switch (codec) {
|
16799
16849
|
case 'av1':
|
16850
|
+
case 'h265':
|
16800
16851
|
encoding = Object.assign({}, encoding);
|
16801
16852
|
encoding.maxBitrate = encoding.maxBitrate * 0.7;
|
16802
16853
|
break;
|
@@ -16964,6 +17015,8 @@ class LocalVideoTrack extends LocalTrack {
|
|
16964
17015
|
/* @internal */
|
16965
17016
|
this.simulcastCodecs = new Map();
|
16966
17017
|
this.degradationPreference = 'balanced';
|
17018
|
+
this.isCpuConstrained = false;
|
17019
|
+
this.optimizeForPerformance = false;
|
16967
17020
|
this.monitorSender = () => __awaiter(this, void 0, void 0, function* () {
|
16968
17021
|
if (!this.sender) {
|
16969
17022
|
this._currentBitrate = 0;
|
@@ -16973,12 +17026,19 @@ class LocalVideoTrack extends LocalTrack {
|
|
16973
17026
|
try {
|
16974
17027
|
stats = yield this.getSenderStats();
|
16975
17028
|
} catch (e) {
|
16976
|
-
this.log.error('could not get
|
17029
|
+
this.log.error('could not get video sender stats', Object.assign(Object.assign({}, this.logContext), {
|
16977
17030
|
error: e
|
16978
17031
|
}));
|
16979
17032
|
return;
|
16980
17033
|
}
|
16981
17034
|
const statsMap = new Map(stats.map(s => [s.rid, s]));
|
17035
|
+
const isCpuConstrained = stats.some(s => s.qualityLimitationReason === 'cpu');
|
17036
|
+
if (isCpuConstrained !== this.isCpuConstrained) {
|
17037
|
+
this.isCpuConstrained = isCpuConstrained;
|
17038
|
+
if (this.isCpuConstrained) {
|
17039
|
+
this.emit(TrackEvent.CpuConstrained);
|
17040
|
+
}
|
17041
|
+
}
|
16982
17042
|
if (this.prevStats) {
|
16983
17043
|
let totalBitrate = 0;
|
16984
17044
|
statsMap.forEach((s, key) => {
|
@@ -17214,6 +17274,8 @@ class LocalVideoTrack extends LocalTrack {
|
|
17214
17274
|
}
|
17215
17275
|
}
|
17216
17276
|
yield this.restart(constraints);
|
17277
|
+
// reset cpu constrained state after track is restarted
|
17278
|
+
this.isCpuConstrained = false;
|
17217
17279
|
try {
|
17218
17280
|
for (var _e = true, _f = __asyncValues(this.simulcastCodecs.values()), _g; _g = yield _f.next(), _a = _g.done, !_a; _e = true) {
|
17219
17281
|
_c = _g.value;
|
@@ -17383,6 +17445,12 @@ class LocalVideoTrack extends LocalTrack {
|
|
17383
17445
|
*/
|
17384
17446
|
setPublishingLayers(isSvc, qualities) {
|
17385
17447
|
return __awaiter(this, void 0, void 0, function* () {
|
17448
|
+
if (this.optimizeForPerformance) {
|
17449
|
+
this.log.info('skipping setPublishingLayers due to optimized publishing performance', Object.assign(Object.assign({}, this.logContext), {
|
17450
|
+
qualities
|
17451
|
+
}));
|
17452
|
+
return;
|
17453
|
+
}
|
17386
17454
|
this.log.debug('setting publishing layers', Object.assign(Object.assign({}, this.logContext), {
|
17387
17455
|
qualities
|
17388
17456
|
}));
|
@@ -17392,6 +17460,44 @@ class LocalVideoTrack extends LocalTrack {
|
|
17392
17460
|
yield setPublishingLayersForSender(this.sender, this.encodings, qualities, this.senderLock, isSvc, this.log, this.logContext);
|
17393
17461
|
});
|
17394
17462
|
}
|
17463
|
+
/**
|
17464
|
+
* Designed for lower powered devices, reduces video publishing quality and disables simulcast.
|
17465
|
+
* @experimental
|
17466
|
+
*/
|
17467
|
+
prioritizePerformance() {
|
17468
|
+
return __awaiter(this, void 0, void 0, function* () {
|
17469
|
+
if (!this.sender) {
|
17470
|
+
throw new Error('sender not found');
|
17471
|
+
}
|
17472
|
+
const unlock = yield this.senderLock.lock();
|
17473
|
+
try {
|
17474
|
+
this.optimizeForPerformance = true;
|
17475
|
+
const params = this.sender.getParameters();
|
17476
|
+
params.encodings = params.encodings.map((e, idx) => {
|
17477
|
+
var _a;
|
17478
|
+
return Object.assign(Object.assign({}, e), {
|
17479
|
+
active: idx === 0,
|
17480
|
+
scaleResolutionDownBy: Math.max(1, Math.ceil(((_a = this.mediaStreamTrack.getSettings().height) !== null && _a !== void 0 ? _a : 360) / 360)),
|
17481
|
+
scalabilityMode: idx === 0 && isSVCCodec(this.codec) ? 'L1T3' : undefined,
|
17482
|
+
maxFramerate: idx === 0 ? 15 : 0,
|
17483
|
+
maxBitrate: idx === 0 ? e.maxBitrate : 0
|
17484
|
+
});
|
17485
|
+
});
|
17486
|
+
this.log.debug('setting performance optimised encodings', Object.assign(Object.assign({}, this.logContext), {
|
17487
|
+
encodings: params.encodings
|
17488
|
+
}));
|
17489
|
+
this.encodings = params.encodings;
|
17490
|
+
yield this.sender.setParameters(params);
|
17491
|
+
} catch (e) {
|
17492
|
+
this.log.error('failed to set performance optimised encodings', Object.assign(Object.assign({}, this.logContext), {
|
17493
|
+
error: e
|
17494
|
+
}));
|
17495
|
+
this.optimizeForPerformance = false;
|
17496
|
+
} finally {
|
17497
|
+
unlock();
|
17498
|
+
}
|
17499
|
+
});
|
17500
|
+
}
|
17395
17501
|
handleAppVisibilityChanged() {
|
17396
17502
|
const _super = Object.create(null, {
|
17397
17503
|
handleAppVisibilityChanged: {
|
@@ -19818,16 +19924,23 @@ class LocalTrackPublication extends TrackPublication {
|
|
19818
19924
|
this.handleTrackEnded = () => {
|
19819
19925
|
this.emit(TrackEvent.Ended);
|
19820
19926
|
};
|
19927
|
+
this.handleCpuConstrained = () => {
|
19928
|
+
if (this.track && isVideoTrack(this.track)) {
|
19929
|
+
this.emit(TrackEvent.CpuConstrained, this.track);
|
19930
|
+
}
|
19931
|
+
};
|
19821
19932
|
this.updateInfo(ti);
|
19822
19933
|
this.setTrack(track);
|
19823
19934
|
}
|
19824
19935
|
setTrack(track) {
|
19825
19936
|
if (this.track) {
|
19826
19937
|
this.track.off(TrackEvent.Ended, this.handleTrackEnded);
|
19938
|
+
this.track.off(TrackEvent.CpuConstrained, this.handleCpuConstrained);
|
19827
19939
|
}
|
19828
19940
|
super.setTrack(track);
|
19829
19941
|
if (track) {
|
19830
19942
|
track.on(TrackEvent.Ended, this.handleTrackEnded);
|
19943
|
+
track.on(TrackEvent.CpuConstrained, this.handleCpuConstrained);
|
19831
19944
|
}
|
19832
19945
|
}
|
19833
19946
|
get isMuted() {
|
@@ -20065,7 +20178,7 @@ function createLocalScreenTracks(options) {
|
|
20065
20178
|
if (options === undefined) {
|
20066
20179
|
options = {};
|
20067
20180
|
}
|
20068
|
-
if (options.resolution === undefined && !
|
20181
|
+
if (options.resolution === undefined && !isSafari17Based()) {
|
20069
20182
|
options.resolution = ScreenSharePresets.h1080fps30.resolution;
|
20070
20183
|
}
|
20071
20184
|
if (navigator.mediaDevices.getDisplayMedia === undefined) {
|
@@ -20498,6 +20611,10 @@ class LocalParticipant extends Participant {
|
|
20498
20611
|
}
|
20499
20612
|
this.engine.client.sendUpdateLocalAudioTrack(pub.trackSid, pub.getTrackFeatures());
|
20500
20613
|
};
|
20614
|
+
this.onTrackCpuConstrained = (track, publication) => {
|
20615
|
+
this.log.debug('track cpu constrained', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(publication)));
|
20616
|
+
this.emit(ParticipantEvent.LocalTrackCpuConstrained, track, publication);
|
20617
|
+
};
|
20501
20618
|
this.handleSubscribedQualityUpdate = update => __awaiter(this, void 0, void 0, function* () {
|
20502
20619
|
var _a, e_1, _b, _c;
|
20503
20620
|
var _d;
|
@@ -20957,7 +21074,7 @@ class LocalParticipant extends Participant {
|
|
20957
21074
|
if (navigator.mediaDevices.getDisplayMedia === undefined) {
|
20958
21075
|
throw new DeviceUnsupportedError('getDisplayMedia not supported');
|
20959
21076
|
}
|
20960
|
-
if (options.resolution === undefined && !
|
21077
|
+
if (options.resolution === undefined && !isSafari17Based()) {
|
20961
21078
|
// we need to constrain the dimensions, otherwise it could lead to low bitrate
|
20962
21079
|
// due to encoding a huge video. Encoding such large surfaces is really expensive
|
20963
21080
|
// unfortunately Safari 17 has a but and cannot be constrained by default
|
@@ -21324,6 +21441,7 @@ class LocalParticipant extends Participant {
|
|
21324
21441
|
throw new UnexpectedConnectionState('pcManager is not ready');
|
21325
21442
|
}
|
21326
21443
|
track.sender = yield this.engine.createSender(track, opts, encodings);
|
21444
|
+
this.emit(ParticipantEvent.LocalSenderCreated, track.sender, track);
|
21327
21445
|
if (isLocalVideoTrack(track)) {
|
21328
21446
|
(_a = opts.degradationPreference) !== null && _a !== void 0 ? _a : opts.degradationPreference = getDefaultDegradationPreference(track);
|
21329
21447
|
track.setDegradationPreference(opts.degradationPreference);
|
@@ -21409,6 +21527,7 @@ class LocalParticipant extends Participant {
|
|
21409
21527
|
loggerName: this.roomOptions.loggerName,
|
21410
21528
|
loggerContextCb: () => this.logContext
|
21411
21529
|
});
|
21530
|
+
publication.on(TrackEvent.CpuConstrained, constrainedTrack => this.onTrackCpuConstrained(constrainedTrack, publication));
|
21412
21531
|
// save options for when it needs to be republished again
|
21413
21532
|
publication.options = opts;
|
21414
21533
|
track.sid = ti.sid;
|
@@ -22308,20 +22427,20 @@ class RemoteTrackPublication extends TrackPublication {
|
|
22308
22427
|
this.track = undefined;
|
22309
22428
|
/** @internal */
|
22310
22429
|
this.allowed = true;
|
22311
|
-
this.
|
22312
|
-
this.
|
22430
|
+
this.requestedDisabled = undefined;
|
22431
|
+
this.visible = true;
|
22313
22432
|
this.handleEnded = track => {
|
22314
22433
|
this.setTrack(undefined);
|
22315
22434
|
this.emit(TrackEvent.Ended, track);
|
22316
22435
|
};
|
22317
22436
|
this.handleVisibilityChange = visible => {
|
22318
22437
|
this.log.debug("adaptivestream video visibility ".concat(this.trackSid, ", visible=").concat(visible), this.logContext);
|
22319
|
-
this.
|
22438
|
+
this.visible = visible;
|
22320
22439
|
this.emitTrackUpdate();
|
22321
22440
|
};
|
22322
22441
|
this.handleVideoDimensionsChange = dimensions => {
|
22323
22442
|
this.log.debug("adaptivestream video dimensions ".concat(dimensions.width, "x").concat(dimensions.height), this.logContext);
|
22324
|
-
this.
|
22443
|
+
this.videoDimensionsAdaptiveStream = dimensions;
|
22325
22444
|
this.emitTrackUpdate();
|
22326
22445
|
};
|
22327
22446
|
this.subscribed = autoSubscribe;
|
@@ -22380,7 +22499,7 @@ class RemoteTrackPublication extends TrackPublication {
|
|
22380
22499
|
return this.subscribed !== false;
|
22381
22500
|
}
|
22382
22501
|
get isEnabled() {
|
22383
|
-
return !this.
|
22502
|
+
return this.requestedDisabled !== undefined ? !this.requestedDisabled : this.isAdaptiveStream ? this.visible : true;
|
22384
22503
|
}
|
22385
22504
|
get isLocal() {
|
22386
22505
|
return false;
|
@@ -22392,10 +22511,10 @@ class RemoteTrackPublication extends TrackPublication {
|
|
22392
22511
|
* @param enabled
|
22393
22512
|
*/
|
22394
22513
|
setEnabled(enabled) {
|
22395
|
-
if (!this.isManualOperationAllowed() || this.
|
22514
|
+
if (!this.isManualOperationAllowed() || this.requestedDisabled === !enabled) {
|
22396
22515
|
return;
|
22397
22516
|
}
|
22398
|
-
this.
|
22517
|
+
this.requestedDisabled = !enabled;
|
22399
22518
|
this.emitTrackUpdate();
|
22400
22519
|
}
|
22401
22520
|
/**
|
@@ -22406,25 +22525,32 @@ class RemoteTrackPublication extends TrackPublication {
|
|
22406
22525
|
* optimize for uninterrupted video
|
22407
22526
|
*/
|
22408
22527
|
setVideoQuality(quality) {
|
22409
|
-
if (!this.isManualOperationAllowed() || this.
|
22528
|
+
if (!this.isManualOperationAllowed() || this.requestedMaxQuality === quality) {
|
22410
22529
|
return;
|
22411
22530
|
}
|
22412
|
-
this.
|
22413
|
-
this.
|
22531
|
+
this.requestedMaxQuality = quality;
|
22532
|
+
this.requestedVideoDimensions = undefined;
|
22414
22533
|
this.emitTrackUpdate();
|
22415
22534
|
}
|
22535
|
+
/**
|
22536
|
+
* Explicitly set the video dimensions for this track.
|
22537
|
+
*
|
22538
|
+
* This will take precedence over adaptive stream dimensions.
|
22539
|
+
*
|
22540
|
+
* @param dimensions The video dimensions to set.
|
22541
|
+
*/
|
22416
22542
|
setVideoDimensions(dimensions) {
|
22417
22543
|
var _a, _b;
|
22418
22544
|
if (!this.isManualOperationAllowed()) {
|
22419
22545
|
return;
|
22420
22546
|
}
|
22421
|
-
if (((_a = this.
|
22547
|
+
if (((_a = this.requestedVideoDimensions) === null || _a === void 0 ? void 0 : _a.width) === dimensions.width && ((_b = this.requestedVideoDimensions) === null || _b === void 0 ? void 0 : _b.height) === dimensions.height) {
|
22422
22548
|
return;
|
22423
22549
|
}
|
22424
22550
|
if (isRemoteVideoTrack(this.track)) {
|
22425
|
-
this.
|
22551
|
+
this.requestedVideoDimensions = dimensions;
|
22426
22552
|
}
|
22427
|
-
this.
|
22553
|
+
this.requestedMaxQuality = undefined;
|
22428
22554
|
this.emitTrackUpdate();
|
22429
22555
|
}
|
22430
22556
|
setVideoFPS(fps) {
|
@@ -22441,7 +22567,8 @@ class RemoteTrackPublication extends TrackPublication {
|
|
22441
22567
|
this.emitTrackUpdate();
|
22442
22568
|
}
|
22443
22569
|
get videoQuality() {
|
22444
|
-
|
22570
|
+
var _a;
|
22571
|
+
return (_a = this.requestedMaxQuality) !== null && _a !== void 0 ? _a : VideoQuality.HIGH;
|
22445
22572
|
}
|
22446
22573
|
/** @internal */
|
22447
22574
|
setTrack(track) {
|
@@ -22508,10 +22635,6 @@ class RemoteTrackPublication extends TrackPublication {
|
|
22508
22635
|
}
|
22509
22636
|
}
|
22510
22637
|
isManualOperationAllowed() {
|
22511
|
-
if (this.kind === Track.Kind.Video && this.isAdaptiveStream) {
|
22512
|
-
this.log.warn('adaptive stream is enabled, cannot change video track settings', this.logContext);
|
22513
|
-
return false;
|
22514
|
-
}
|
22515
22638
|
if (!this.isDesired) {
|
22516
22639
|
this.log.warn('cannot update track settings when not subscribed', this.logContext);
|
22517
22640
|
return false;
|
@@ -22525,17 +22648,46 @@ class RemoteTrackPublication extends TrackPublication {
|
|
22525
22648
|
emitTrackUpdate() {
|
22526
22649
|
const settings = new UpdateTrackSettings({
|
22527
22650
|
trackSids: [this.trackSid],
|
22528
|
-
disabled: this.
|
22651
|
+
disabled: !this.isEnabled,
|
22529
22652
|
fps: this.fps
|
22530
22653
|
});
|
22531
|
-
if (this.
|
22532
|
-
|
22533
|
-
|
22534
|
-
|
22535
|
-
|
22536
|
-
|
22537
|
-
|
22538
|
-
|
22654
|
+
if (this.kind === Track.Kind.Video) {
|
22655
|
+
let minDimensions = this.requestedVideoDimensions;
|
22656
|
+
if (this.videoDimensionsAdaptiveStream !== undefined) {
|
22657
|
+
if (minDimensions) {
|
22658
|
+
// check whether the adaptive stream dimensions are smaller than the requested dimensions and use smaller one
|
22659
|
+
const smallerAdaptive = areDimensionsSmaller(this.videoDimensionsAdaptiveStream, minDimensions);
|
22660
|
+
if (smallerAdaptive) {
|
22661
|
+
this.log.debug('using adaptive stream dimensions instead of requested', Object.assign(Object.assign({}, this.logContext), this.videoDimensionsAdaptiveStream));
|
22662
|
+
minDimensions = this.videoDimensionsAdaptiveStream;
|
22663
|
+
}
|
22664
|
+
} else if (this.requestedMaxQuality !== undefined && this.trackInfo) {
|
22665
|
+
// check whether adaptive stream dimensions are smaller than the max quality layer and use smaller one
|
22666
|
+
const maxQualityLayer = layerDimensionsFor(this.trackInfo, this.requestedMaxQuality);
|
22667
|
+
if (maxQualityLayer && areDimensionsSmaller(this.videoDimensionsAdaptiveStream, maxQualityLayer)) {
|
22668
|
+
this.log.debug('using adaptive stream dimensions instead of max quality layer', Object.assign(Object.assign({}, this.logContext), this.videoDimensionsAdaptiveStream));
|
22669
|
+
minDimensions = this.videoDimensionsAdaptiveStream;
|
22670
|
+
}
|
22671
|
+
} else {
|
22672
|
+
this.log.debug('using adaptive stream dimensions', Object.assign(Object.assign({}, this.logContext), this.videoDimensionsAdaptiveStream));
|
22673
|
+
minDimensions = this.videoDimensionsAdaptiveStream;
|
22674
|
+
}
|
22675
|
+
}
|
22676
|
+
if (minDimensions) {
|
22677
|
+
settings.width = Math.ceil(minDimensions.width);
|
22678
|
+
settings.height = Math.ceil(minDimensions.height);
|
22679
|
+
} else if (this.requestedMaxQuality !== undefined) {
|
22680
|
+
this.log.debug('using requested max quality', Object.assign(Object.assign({}, this.logContext), {
|
22681
|
+
quality: this.requestedMaxQuality
|
22682
|
+
}));
|
22683
|
+
settings.quality = this.requestedMaxQuality;
|
22684
|
+
} else {
|
22685
|
+
this.log.debug('using default quality', Object.assign(Object.assign({}, this.logContext), {
|
22686
|
+
quality: VideoQuality.HIGH
|
22687
|
+
}));
|
22688
|
+
// defaults to high quality
|
22689
|
+
settings.quality = VideoQuality.HIGH;
|
22690
|
+
}
|
22539
22691
|
}
|
22540
22692
|
this.emit(TrackEvent.UpdateSettings, settings);
|
22541
22693
|
}
|
@@ -22566,7 +22718,9 @@ class RemoteParticipant extends Participant {
|
|
22566
22718
|
super.addTrackPublication(publication);
|
22567
22719
|
// register action events
|
22568
22720
|
publication.on(TrackEvent.UpdateSettings, settings => {
|
22569
|
-
this.log.debug('send update settings', Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(publication))
|
22721
|
+
this.log.debug('send update settings', Object.assign(Object.assign(Object.assign({}, this.logContext), getLogContextFromTrack(publication)), {
|
22722
|
+
settings
|
22723
|
+
}));
|
22570
22724
|
this.signalClient.sendUpdateTrackSettings(settings);
|
22571
22725
|
});
|
22572
22726
|
publication.on(TrackEvent.UpdateSubscription, sub => {
|
@@ -24105,6 +24259,11 @@ class Room extends eventsExports.EventEmitter {
|
|
24105
24259
|
_this3.options.videoCaptureDefaults.deviceId = prevDeviceId;
|
24106
24260
|
throw e;
|
24107
24261
|
}
|
24262
|
+
const isMuted = tracks.some(t => {
|
24263
|
+
var _a, _b;
|
24264
|
+
return (_b = (_a = t.track) === null || _a === void 0 ? void 0 : _a.isMuted) !== null && _b !== void 0 ? _b : false;
|
24265
|
+
});
|
24266
|
+
if (success && isMuted) shouldTriggerImmediateDeviceChange = true;
|
24108
24267
|
} else if (kind === 'audiooutput') {
|
24109
24268
|
shouldTriggerImmediateDeviceChange = true;
|
24110
24269
|
if (!supportsSetSinkId() && !_this3.options.webAudioMix || _this3.options.webAudioMix && _this3.audioContext && !('setSinkId' in _this3.audioContext)) {
|