livekit-client 2.22.2 → 2.22.4
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 +35 -0
- 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 +488 -438
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +954 -301
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.fm.worker.js +1 -1
- package/dist/livekit-client.fm.worker.js.map +1 -1
- package/dist/livekit-client.fm.worker.mjs +10 -2
- package/dist/livekit-client.fm.worker.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 +4 -2
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/api/WebSocketStream.d.ts.map +1 -1
- package/dist/src/api/utils.d.ts +1 -0
- package/dist/src/api/utils.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +26 -0
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +15 -1
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ErrorRateLimiter.d.ts +21 -0
- package/dist/src/e2ee/worker/ErrorRateLimiter.d.ts.map +1 -0
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +1 -18
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/logger.d.ts +4 -0
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/options.d.ts +14 -0
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +78 -7
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +9 -0
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/defaults.d.ts.map +1 -1
- package/dist/src/room/errors.d.ts +18 -0
- package/dist/src/room/errors.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +3 -2
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/publishUtils.d.ts +16 -0
- package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
- package/dist/src/room/rpc/client/RpcClientManager.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts +9 -0
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +1 -1
- package/dist/src/room/track/utils.d.ts +13 -0
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +66 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/test/compressionStreamStubs.d.ts +12 -0
- package/dist/src/test/compressionStreamStubs.d.ts.map +1 -0
- package/dist/ts4.2/api/SignalClient.d.ts +187 -185
- package/dist/ts4.2/api/SignalClientStateMachine.d.ts +85 -85
- package/dist/ts4.2/api/WebSocketStream.d.ts +33 -33
- package/dist/ts4.2/api/utils.d.ts +9 -8
- package/dist/ts4.2/connectionHelper/ConnectionCheck.d.ts +30 -30
- package/dist/ts4.2/connectionHelper/checks/Checker.d.ts +62 -62
- package/dist/ts4.2/connectionHelper/checks/cloudRegion.d.ts +18 -18
- package/dist/ts4.2/connectionHelper/checks/connectionProtocol.d.ts +20 -20
- package/dist/ts4.2/connectionHelper/checks/publishAudio.d.ts +6 -6
- package/dist/ts4.2/connectionHelper/checks/publishVideo.d.ts +7 -7
- package/dist/ts4.2/connectionHelper/checks/reconnect.d.ts +6 -6
- package/dist/ts4.2/connectionHelper/checks/turn.d.ts +6 -6
- package/dist/ts4.2/connectionHelper/checks/webrtc.d.ts +6 -6
- package/dist/ts4.2/connectionHelper/checks/websocket.d.ts +6 -6
- package/dist/ts4.2/e2ee/E2eeManager.d.ts +111 -85
- package/dist/ts4.2/e2ee/KeyProvider.d.ts +54 -54
- package/dist/ts4.2/e2ee/constants.d.ts +21 -21
- package/dist/ts4.2/e2ee/errors.d.ts +12 -12
- package/dist/ts4.2/e2ee/events.d.ts +39 -39
- package/dist/ts4.2/e2ee/index.d.ts +6 -6
- package/dist/ts4.2/e2ee/types.d.ts +231 -217
- package/dist/ts4.2/e2ee/utils.d.ts +32 -32
- package/dist/ts4.2/e2ee/worker/DataCryptor.d.ts +16 -16
- package/dist/ts4.2/e2ee/worker/ErrorRateLimiter.d.ts +21 -0
- package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +209 -226
- package/dist/ts4.2/e2ee/worker/ParticipantKeyHandler.d.ts +81 -84
- package/dist/ts4.2/e2ee/worker/e2ee.worker.d.ts +2 -2
- package/dist/ts4.2/e2ee/worker/naluUtils.d.ts +28 -28
- package/dist/ts4.2/e2ee/worker/sifPayload.d.ts +23 -23
- package/dist/ts4.2/frameMetadata/FrameMetadataManager.d.ts +53 -53
- package/dist/ts4.2/frameMetadata/frameMetadata.d.ts +33 -33
- package/dist/ts4.2/frameMetadata/types.d.ts +62 -62
- package/dist/ts4.2/frameMetadata/utils.d.ts +9 -9
- package/dist/ts4.2/frameMetadata/worker/frameMetadata.worker.d.ts +2 -2
- package/dist/ts4.2/index.d.ts +76 -76
- package/dist/ts4.2/logger.d.ts +66 -62
- package/dist/ts4.2/options.d.ts +163 -149
- package/dist/ts4.2/room/BackOffStrategy.d.ts +27 -27
- package/dist/ts4.2/room/DefaultReconnectPolicy.d.ts +8 -8
- package/dist/ts4.2/room/DeviceManager.d.ts +12 -12
- package/dist/ts4.2/room/PCTransport.d.ts +246 -175
- package/dist/ts4.2/room/PCTransportManager.d.ts +77 -77
- package/dist/ts4.2/room/RTCEngine.d.ts +269 -261
- package/dist/ts4.2/room/ReconnectPolicy.d.ts +24 -24
- package/dist/ts4.2/room/RegionUrlProvider.d.ts +36 -36
- package/dist/ts4.2/room/Room.d.ts +354 -365
- package/dist/ts4.2/room/attribute-typings.d.ts +35 -35
- package/dist/ts4.2/room/data-channel/DataChannelManager.d.ts +62 -62
- package/dist/ts4.2/room/data-channel/FlowControlledDataChannel.d.ts +94 -95
- package/dist/ts4.2/room/data-channel/LossyDataChannel.d.ts +41 -41
- package/dist/ts4.2/room/data-channel/ReliableDataChannel.d.ts +57 -57
- package/dist/ts4.2/room/data-channel/types.d.ts +12 -12
- package/dist/ts4.2/room/data-stream/compression.d.ts +49 -49
- package/dist/ts4.2/room/data-stream/constants.d.ts +18 -18
- package/dist/ts4.2/room/data-stream/incoming/IncomingDataStreamManager.d.ts +29 -29
- package/dist/ts4.2/room/data-stream/incoming/StreamReader.d.ts +80 -80
- package/dist/ts4.2/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts +73 -73
- package/dist/ts4.2/room/data-stream/outgoing/StreamWriter.d.ts +16 -16
- package/dist/ts4.2/room/data-stream/outgoing/header-utils.d.ts +18 -18
- package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +79 -80
- package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +50 -50
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +59 -59
- package/dist/ts4.2/room/data-track/frame.d.ts +22 -22
- package/dist/ts4.2/room/data-track/handle.d.ts +27 -27
- package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +124 -124
- package/dist/ts4.2/room/data-track/incoming/errors.d.ts +24 -24
- package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +41 -41
- package/dist/ts4.2/room/data-track/incoming/types.d.ts +20 -20
- package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +126 -126
- package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +74 -74
- package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +23 -23
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +48 -48
- package/dist/ts4.2/room/data-track/packet/constants.d.ts +20 -20
- package/dist/ts4.2/room/data-track/packet/errors.d.ts +40 -40
- package/dist/ts4.2/room/data-track/packet/extensions.d.ts +69 -69
- package/dist/ts4.2/room/data-track/packet/index.d.ts +98 -98
- package/dist/ts4.2/room/data-track/packet/serializable.d.ts +13 -13
- package/dist/ts4.2/room/data-track/packetizer.d.ts +43 -43
- package/dist/ts4.2/room/data-track/track-interfaces.d.ts +23 -23
- package/dist/ts4.2/room/data-track/types.d.ts +22 -22
- package/dist/ts4.2/room/data-track/utils.d.ts +60 -60
- package/dist/ts4.2/room/debounce.d.ts +11 -11
- package/dist/ts4.2/room/defaults.d.ts +9 -9
- package/dist/ts4.2/room/errors.d.ts +180 -162
- package/dist/ts4.2/room/events.d.ts +638 -637
- package/dist/ts4.2/room/participant/LocalParticipant.d.ts +287 -287
- package/dist/ts4.2/room/participant/Participant.d.ts +142 -144
- package/dist/ts4.2/room/participant/ParticipantTrackPermission.d.ts +26 -26
- package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +85 -86
- package/dist/ts4.2/room/participant/publishUtils.d.ts +53 -37
- package/dist/ts4.2/room/rpc/client/RpcClientManager.d.ts +43 -43
- package/dist/ts4.2/room/rpc/client/events.d.ts +8 -8
- package/dist/ts4.2/room/rpc/index.d.ts +7 -7
- package/dist/ts4.2/room/rpc/server/RpcServerManager.d.ts +44 -44
- package/dist/ts4.2/room/rpc/server/events.d.ts +8 -8
- package/dist/ts4.2/room/rpc/utils.d.ts +131 -131
- package/dist/ts4.2/room/stats.d.ts +71 -71
- package/dist/ts4.2/room/statsSummary.d.ts +13 -13
- package/dist/ts4.2/room/timers.d.ts +12 -12
- package/dist/ts4.2/room/token-source/TokenSource.d.ts +82 -82
- package/dist/ts4.2/room/token-source/types.d.ts +70 -70
- package/dist/ts4.2/room/token-source/utils.d.ts +8 -8
- package/dist/ts4.2/room/track/FrameMetadataExtractor.d.ts +19 -19
- package/dist/ts4.2/room/track/LocalAudioTrack.d.ts +39 -42
- package/dist/ts4.2/room/track/LocalTrack.d.ts +125 -125
- package/dist/ts4.2/room/track/LocalTrackPublication.d.ts +42 -42
- package/dist/ts4.2/room/track/LocalVideoTrack.d.ts +102 -93
- package/dist/ts4.2/room/track/RemoteAudioTrack.d.ts +55 -55
- package/dist/ts4.2/room/track/RemoteTrack.d.ts +38 -38
- package/dist/ts4.2/room/track/RemoteTrackPublication.d.ts +72 -75
- package/dist/ts4.2/room/track/RemoteVideoTrack.d.ts +73 -76
- package/dist/ts4.2/room/track/Track.d.ts +156 -166
- package/dist/ts4.2/room/track/TrackPublication.d.ts +75 -81
- package/dist/ts4.2/room/track/create.d.ts +25 -25
- package/dist/ts4.2/room/track/facingMode.d.ts +41 -41
- package/dist/ts4.2/room/track/options.d.ts +403 -403
- package/dist/ts4.2/room/track/processor/types.d.ts +31 -31
- package/dist/ts4.2/room/track/record.d.ts +13 -13
- package/dist/ts4.2/room/track/types.d.ts +28 -28
- package/dist/ts4.2/room/track/utils.d.ts +60 -47
- package/dist/ts4.2/room/types.d.ts +127 -127
- package/dist/ts4.2/room/utils.d.ts +246 -180
- package/dist/ts4.2/test/MockMediaStreamTrack.d.ts +26 -26
- package/dist/ts4.2/test/compressionStreamStubs.d.ts +12 -0
- package/dist/ts4.2/test/mocks.d.ts +12 -12
- package/dist/ts4.2/test/promiseState.d.ts +12 -12
- package/dist/ts4.2/test/signalToken.d.ts +26 -26
- package/dist/ts4.2/type-polyfills/non-shared-typed-arrays.d.ts +2 -2
- package/dist/ts4.2/utils/AsyncQueue.d.ts +23 -23
- package/dist/ts4.2/utils/TypedPromise.d.ts +17 -17
- package/dist/ts4.2/utils/abort-signal-polyfill.d.ts +13 -13
- package/dist/ts4.2/utils/browserParser.d.ts +13 -13
- package/dist/ts4.2/utils/camelToSnakeCase.d.ts +8 -8
- package/dist/ts4.2/utils/cloneDeep.d.ts +2 -2
- package/dist/ts4.2/utils/dataPacketBuffer.d.ts +34 -34
- package/dist/ts4.2/utils/deferrable-map.d.ts +32 -32
- package/dist/ts4.2/utils/machineInspector.d.ts +54 -54
- package/dist/ts4.2/utils/serializer.d.ts +48 -48
- package/dist/ts4.2/utils/subscribeToEvents.d.ts +15 -15
- package/dist/ts4.2/utils/ttlmap.d.ts +20 -20
- package/dist/ts4.2/version.d.ts +15 -15
- package/package.json +5 -4
- package/src/api/SignalClient.e2e.test.ts +1 -3
- package/src/api/SignalClient.test.ts +160 -10
- package/src/api/SignalClient.ts +75 -54
- package/src/api/WebSocketStream.ts +3 -8
- package/src/api/utils.ts +10 -0
- package/src/e2ee/E2eeManager.test.ts +196 -0
- package/src/e2ee/E2eeManager.ts +114 -19
- package/src/e2ee/types.ts +19 -1
- package/src/e2ee/worker/DataCryptor.ts +2 -1
- package/src/e2ee/worker/ErrorRateLimiter.test.ts +53 -0
- package/src/e2ee/worker/ErrorRateLimiter.ts +52 -0
- package/src/e2ee/worker/FrameCryptor.ts +20 -70
- package/src/e2ee/worker/e2ee.worker.ts +34 -11
- package/src/logger.ts +22 -0
- package/src/options.ts +16 -0
- package/src/room/PCTransport.test.ts +183 -7
- package/src/room/PCTransport.ts +197 -36
- package/src/room/PCTransportManager.ts +3 -1
- package/src/room/RTCEngine.test.ts +84 -0
- package/src/room/RTCEngine.ts +52 -12
- package/src/room/Room.test.ts +32 -6
- package/src/room/Room.ts +27 -7
- package/src/room/data-stream/incoming/IncomingDataStreamManager.test.ts +16 -20
- package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +5 -5
- package/src/room/data-stream/outgoing/OutgoingDataStreamManager.test.ts +60 -39
- package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +4 -4
- package/src/room/defaults.ts +1 -0
- package/src/room/errors.test.ts +36 -0
- package/src/room/errors.ts +27 -0
- package/src/room/events.ts +2 -1
- package/src/room/participant/LocalParticipant.ts +30 -14
- package/src/room/participant/publishUtils.test.ts +133 -0
- package/src/room/participant/publishUtils.ts +54 -38
- package/src/room/rpc/client/RpcClientManager.test.ts +51 -0
- package/src/room/rpc/client/RpcClientManager.ts +32 -15
- package/src/room/track/LocalTrack.ts +18 -7
- package/src/room/track/LocalVideoTrack.ts +25 -8
- package/src/room/track/RemoteAudioTrack.ts +3 -3
- package/src/room/track/RemoteVideoTrack.test.ts +210 -0
- package/src/room/track/RemoteVideoTrack.ts +29 -3
- package/src/room/track/options.ts +1 -1
- package/src/room/track/utils.test.ts +201 -2
- package/src/room/track/utils.ts +88 -0
- package/src/room/utils.test.ts +211 -0
- package/src/room/utils.ts +129 -0
- package/src/test/compressionStreamStubs.ts +53 -0
|
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
import { ScreenSharePresets, VideoPreset, VideoPresets, VideoPresets43 } from '../track/options';
|
|
3
3
|
import {
|
|
4
4
|
computeDefaultScreenShareSimulcastPresets,
|
|
5
|
+
computeStartTargetBitrate,
|
|
5
6
|
computeVideoEncodings,
|
|
6
7
|
determineAppropriateEncoding,
|
|
7
8
|
presets43,
|
|
@@ -116,6 +117,78 @@ describe('computeVideoEncodings', () => {
|
|
|
116
117
|
expect(encodings![0].scaleResolutionDownBy).toBe(1);
|
|
117
118
|
});
|
|
118
119
|
|
|
120
|
+
// svc carries the scalabilityMode on the first encoding only (whether it emits a
|
|
121
|
+
// single encoding or the legacy multi-encoding shape), simulcast carries it on all
|
|
122
|
+
const countScalabilityModes = (encodings?: RTCRtpEncodingParameters[]) =>
|
|
123
|
+
/* @ts-ignore */
|
|
124
|
+
encodings!.filter((encoding) => encoding.scalabilityMode !== undefined).length;
|
|
125
|
+
|
|
126
|
+
it('keeps svc for an svc codec without simulcast', () => {
|
|
127
|
+
const encodings = computeVideoEncodings(false, 960, 540, {
|
|
128
|
+
simulcast: false,
|
|
129
|
+
videoCodec: 'vp9',
|
|
130
|
+
scalabilityMode: 'L3T3_KEY',
|
|
131
|
+
});
|
|
132
|
+
/* @ts-ignore */
|
|
133
|
+
expect(encodings![0].scalabilityMode).toBe('L3T3_KEY');
|
|
134
|
+
expect(countScalabilityModes(encodings)).toBe(1);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('keeps svc for an svc codec with a multi spatial layer mode even if simulcast is set', () => {
|
|
138
|
+
const encodings = computeVideoEncodings(false, 960, 540, {
|
|
139
|
+
simulcast: true,
|
|
140
|
+
videoCodec: 'vp9',
|
|
141
|
+
scalabilityMode: 'L3T3_KEY',
|
|
142
|
+
});
|
|
143
|
+
/* @ts-ignore */
|
|
144
|
+
expect(encodings![0].scalabilityMode).toBe('L3T3_KEY');
|
|
145
|
+
expect(countScalabilityModes(encodings)).toBe(1);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('returns a simulcast ladder for an svc codec with simulcast and an L1Tx mode', () => {
|
|
149
|
+
for (const videoCodec of ['vp9', 'av1'] as const) {
|
|
150
|
+
const encodings = computeVideoEncodings(false, 960, 540, {
|
|
151
|
+
simulcast: true,
|
|
152
|
+
videoCodec,
|
|
153
|
+
scalabilityMode: 'L1T2',
|
|
154
|
+
});
|
|
155
|
+
expect(encodings).toHaveLength(3);
|
|
156
|
+
expect(encodings!.map((e) => e.rid)).toEqual(['q', 'h', 'f']);
|
|
157
|
+
// every encoding needs both scalabilityMode and scaleResolutionDownBy for chrome
|
|
158
|
+
// M113+ to treat them as real simulcast rather than legacy svc
|
|
159
|
+
encodings!.forEach((encoding) => {
|
|
160
|
+
/* @ts-ignore */
|
|
161
|
+
expect(encoding.scalabilityMode).toBe('L1T2');
|
|
162
|
+
expect(encoding.scaleResolutionDownBy).toBeGreaterThanOrEqual(1);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('sets the scalability mode on a single encoding svc simulcast ladder', () => {
|
|
168
|
+
const encodings = computeVideoEncodings(false, 100, 120, {
|
|
169
|
+
simulcast: true,
|
|
170
|
+
videoCodec: 'vp9',
|
|
171
|
+
scalabilityMode: 'L1T3',
|
|
172
|
+
});
|
|
173
|
+
expect(encodings).toHaveLength(1);
|
|
174
|
+
expect(encodings![0].rid).toBe('q');
|
|
175
|
+
/* @ts-ignore */
|
|
176
|
+
expect(encodings![0].scalabilityMode).toBe('L1T3');
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('does not set a scalability mode for non-svc simulcast', () => {
|
|
180
|
+
const encodings = computeVideoEncodings(false, 960, 540, {
|
|
181
|
+
simulcast: true,
|
|
182
|
+
videoCodec: 'vp8',
|
|
183
|
+
scalabilityMode: 'L1T2',
|
|
184
|
+
});
|
|
185
|
+
expect(encodings).toHaveLength(3);
|
|
186
|
+
encodings!.forEach((encoding) => {
|
|
187
|
+
/* @ts-ignore */
|
|
188
|
+
expect(encoding.scalabilityMode).toBeUndefined();
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
119
192
|
// it('respects default backup codec encoding', () => {
|
|
120
193
|
// const vp8Encodings = computeTrackBackupEncodings(false, 100, 120, { simulcast: true });
|
|
121
194
|
// const h264Encodings = computeVideoEncodings(false, 100, 120, {
|
|
@@ -193,3 +266,63 @@ describe('screenShareSimulcastDefaults', () => {
|
|
|
193
266
|
expect(defaultSimulcastLayers[0].encoding.maxBitrate).toBe(375000);
|
|
194
267
|
});
|
|
195
268
|
});
|
|
269
|
+
|
|
270
|
+
describe('computeStartTargetBitrate', () => {
|
|
271
|
+
// ordered q..f, as encodingsFromPresets builds them
|
|
272
|
+
const simulcastLadder: RTCRtpEncodingParameters[] = [
|
|
273
|
+
{ rid: 'q', maxBitrate: 160_000 },
|
|
274
|
+
{ rid: 'h', maxBitrate: 450_000 },
|
|
275
|
+
{ rid: 'f', maxBitrate: 680_000 },
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
it('sums the ladder for plain simulcast', () => {
|
|
279
|
+
expect(computeStartTargetBitrate('vp8', { simulcast: true }, simulcastLadder)).toBe(1_290_000);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('sums the ladder for vp9/av1 published as rid simulcast', () => {
|
|
283
|
+
// encodings[0] is the *smallest* layer here, so taking it would under-hint BWE
|
|
284
|
+
for (const codec of ['vp9', 'av1'] as const) {
|
|
285
|
+
expect(
|
|
286
|
+
computeStartTargetBitrate(
|
|
287
|
+
codec,
|
|
288
|
+
{ simulcast: true, videoCodec: codec, scalabilityMode: 'L1T2' },
|
|
289
|
+
simulcastLadder,
|
|
290
|
+
),
|
|
291
|
+
).toBe(1_290_000);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('uses the single encoding for vp9/av1 svc', () => {
|
|
296
|
+
for (const codec of ['vp9', 'av1'] as const) {
|
|
297
|
+
expect(
|
|
298
|
+
computeStartTargetBitrate(
|
|
299
|
+
codec,
|
|
300
|
+
{ simulcast: false, videoCodec: codec, scalabilityMode: 'L3T3_KEY' },
|
|
301
|
+
[{ maxBitrate: 680_000 }],
|
|
302
|
+
),
|
|
303
|
+
).toBe(680_000);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('uses the first encoding for the legacy svc shape, which is ordered f..q', () => {
|
|
308
|
+
// legacy SVC pushes videoRids[2 - i], so encodings[0] carries the full bitrate
|
|
309
|
+
const legacySvc: RTCRtpEncodingParameters[] = [
|
|
310
|
+
{ rid: 'f', maxBitrate: 680_000 },
|
|
311
|
+
{ rid: 'h', maxBitrate: 226_667 },
|
|
312
|
+
{ rid: 'q', maxBitrate: 75_556 },
|
|
313
|
+
];
|
|
314
|
+
expect(
|
|
315
|
+
computeStartTargetBitrate(
|
|
316
|
+
'vp9',
|
|
317
|
+
{ simulcast: false, videoCodec: 'vp9', scalabilityMode: 'L3T3_KEY' },
|
|
318
|
+
legacySvc,
|
|
319
|
+
),
|
|
320
|
+
).toBe(680_000);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('handles missing bitrates and empty encodings', () => {
|
|
324
|
+
expect(computeStartTargetBitrate('vp8', { simulcast: true }, [])).toBe(0);
|
|
325
|
+
expect(computeStartTargetBitrate('vp9', undefined, [])).toBe(0);
|
|
326
|
+
expect(computeStartTargetBitrate('vp8', { simulcast: true }, [{ rid: 'q' }])).toBe(0);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
@@ -13,12 +13,12 @@ import type {
|
|
|
13
13
|
import { ScreenSharePresets, VideoPreset, VideoPresets, VideoPresets43 } from '../track/options';
|
|
14
14
|
import type { LoggerOptions } from '../types';
|
|
15
15
|
import {
|
|
16
|
-
compareVersions,
|
|
17
16
|
getReactNativeOs,
|
|
18
17
|
isReactNative,
|
|
19
18
|
isSVCCodec,
|
|
20
|
-
|
|
19
|
+
isSVCSimulcast,
|
|
21
20
|
isSafariSvcApi,
|
|
21
|
+
usesLegacySVCEncodings,
|
|
22
22
|
} from '../utils';
|
|
23
23
|
|
|
24
24
|
/** @internal */
|
|
@@ -74,25 +74,6 @@ export const computeDefaultScreenShareSimulcastPresets = (fromPreset: VideoPrese
|
|
|
74
74
|
);
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
// /**
|
|
78
|
-
// *
|
|
79
|
-
// * @internal
|
|
80
|
-
// * @experimental
|
|
81
|
-
// */
|
|
82
|
-
// const computeDefaultMultiCodecSimulcastEncodings = (width: number, height: number) => {
|
|
83
|
-
// // use vp8 as a default
|
|
84
|
-
// const vp8 = determineAppropriateEncoding(false, width, height);
|
|
85
|
-
// const vp9 = { ...vp8, maxBitrate: vp8.maxBitrate * 0.9 };
|
|
86
|
-
// const h264 = { ...vp8, maxBitrate: vp8.maxBitrate * 1.1 };
|
|
87
|
-
// const av1 = { ...vp8, maxBitrate: vp8.maxBitrate * 0.7 };
|
|
88
|
-
// return {
|
|
89
|
-
// vp8,
|
|
90
|
-
// vp9,
|
|
91
|
-
// h264,
|
|
92
|
-
// av1,
|
|
93
|
-
// };
|
|
94
|
-
// };
|
|
95
|
-
|
|
96
77
|
const videoRids = ['q', 'h', 'f'];
|
|
97
78
|
|
|
98
79
|
/* @internal */
|
|
@@ -111,6 +92,8 @@ export function computeVideoEncodings(
|
|
|
111
92
|
const useSimulcast = options?.simulcast;
|
|
112
93
|
const scalabilityMode = options?.scalabilityMode;
|
|
113
94
|
const videoCodec = options?.videoCodec;
|
|
95
|
+
// VP9/AV1 published as rid based simulcast rather than SVC, see isSVCSimulcast
|
|
96
|
+
const useSVCSimulcast = isSVCSimulcast(videoCodec, options);
|
|
114
97
|
|
|
115
98
|
if ((!videoEncoding && !useSimulcast && !scalabilityMode) || !width || !height) {
|
|
116
99
|
// when we aren't simulcasting or svc, will need to return a single encoding without
|
|
@@ -134,7 +117,7 @@ export function computeVideoEncodings(
|
|
|
134
117
|
videoEncoding.priority,
|
|
135
118
|
);
|
|
136
119
|
|
|
137
|
-
if (scalabilityMode && isSVCCodec(videoCodec)) {
|
|
120
|
+
if (scalabilityMode && isSVCCodec(videoCodec) && !useSVCSimulcast) {
|
|
138
121
|
const sm = new ScalabilityMode(scalabilityMode);
|
|
139
122
|
|
|
140
123
|
const encodings: RTCRtpEncodingParameters[] = [];
|
|
@@ -142,20 +125,10 @@ export function computeVideoEncodings(
|
|
|
142
125
|
if (sm.spatial > 3) {
|
|
143
126
|
throw new Error(`unsupported scalabilityMode: ${scalabilityMode}`);
|
|
144
127
|
}
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
// This is a bit confusing but is due to how libwebrtc interpreted the encodings field
|
|
148
|
-
// before M113.
|
|
149
|
-
// Announced here: https://groups.google.com/g/discuss-webrtc/c/-QQ3pxrl-fw?pli=1
|
|
128
|
+
// Browsers that read multiple encodings on an SVC codec as SVC rather than as
|
|
129
|
+
// simulcast, see usesLegacySVCEncodings
|
|
150
130
|
const browser = getBrowser();
|
|
151
|
-
if (
|
|
152
|
-
isSafariBased() ||
|
|
153
|
-
// Even tho RN runs M114, it does not produce SVC layers when a single encoding
|
|
154
|
-
// is provided. So we'll use the legacy SVC specification for now.
|
|
155
|
-
// TODO: when we upstream libwebrtc, this will need additional verification
|
|
156
|
-
isReactNative() ||
|
|
157
|
-
(browser?.name === 'Chrome' && compareVersions(browser?.version, '113') < 0)
|
|
158
|
-
) {
|
|
131
|
+
if (usesLegacySVCEncodings()) {
|
|
159
132
|
const bitratesRatio = sm.suffix == 'h' ? 2 : 3;
|
|
160
133
|
// safari 18.4 uses a different svc API that requires scaleResolutionDownBy to be set.
|
|
161
134
|
const requireScale = isSafariSvcApi(browser);
|
|
@@ -193,6 +166,19 @@ export function computeVideoEncodings(
|
|
|
193
166
|
return [videoEncoding];
|
|
194
167
|
}
|
|
195
168
|
|
|
169
|
+
// Chrome M113+ only treats multiple encodings on an SVC capable codec as real
|
|
170
|
+
// simulcast when every encoding carries an explicit scalabilityMode next to its
|
|
171
|
+
// scaleResolutionDownBy. Without it the encodings are interpreted as legacy SVC.
|
|
172
|
+
const applySVCSimulcastMode = (encodings: RTCRtpEncodingParameters[]) => {
|
|
173
|
+
if (useSVCSimulcast) {
|
|
174
|
+
encodings.forEach((encoding) => {
|
|
175
|
+
/* @ts-ignore */
|
|
176
|
+
encoding.scalabilityMode = scalabilityMode;
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return encodings;
|
|
180
|
+
};
|
|
181
|
+
|
|
196
182
|
let presets: Array<VideoPreset>;
|
|
197
183
|
if (isScreenShare) {
|
|
198
184
|
presets =
|
|
@@ -220,13 +206,43 @@ export function computeVideoEncodings(
|
|
|
220
206
|
// based on other conditions.
|
|
221
207
|
const size = Math.max(width, height);
|
|
222
208
|
if (size >= 960 && midPreset) {
|
|
223
|
-
return
|
|
209
|
+
return applySVCSimulcastMode(
|
|
210
|
+
encodingsFromPresets(width, height, [lowPreset, midPreset, original], sourceFramerate),
|
|
211
|
+
);
|
|
224
212
|
}
|
|
225
213
|
if (size >= 480) {
|
|
226
|
-
return
|
|
214
|
+
return applySVCSimulcastMode(
|
|
215
|
+
encodingsFromPresets(width, height, [lowPreset, original], sourceFramerate),
|
|
216
|
+
);
|
|
227
217
|
}
|
|
228
218
|
}
|
|
229
|
-
return encodingsFromPresets(width, height, [original]);
|
|
219
|
+
return applySVCSimulcastMode(encodingsFromPresets(width, height, [original]));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Bitrate to hint to the bandwidth estimator through `x-google-start-bitrate`, so that
|
|
224
|
+
* a publish does not spend its first seconds ramping up from a very low rate.
|
|
225
|
+
*
|
|
226
|
+
* It has to be the total the encoder will put on the wire, which means picking the
|
|
227
|
+
* encoding that carries the inclusive bitrate:
|
|
228
|
+
* - SVC publishes a single stream with the layers built in. `encodings[0]` holds the
|
|
229
|
+
* full bitrate — the legacy SVC shape orders its encodings `f`..`q`, so that holds
|
|
230
|
+
* for both SVC shapes.
|
|
231
|
+
* - Simulcast publishes independent streams ordered `q`..`f`, so the total is the sum.
|
|
232
|
+
* This includes VP9/AV1 published as rid based simulcast, where `encodings[0]` is
|
|
233
|
+
* the *smallest* layer even though the codec is SVC capable.
|
|
234
|
+
*
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
export function computeStartTargetBitrate(
|
|
238
|
+
codec: string,
|
|
239
|
+
options: TrackPublishOptions | undefined,
|
|
240
|
+
encodings: RTCRtpEncodingParameters[],
|
|
241
|
+
): number {
|
|
242
|
+
if (isSVCCodec(codec) && !isSVCSimulcast(codec, options)) {
|
|
243
|
+
return encodings[0]?.maxBitrate ?? 0;
|
|
244
|
+
}
|
|
245
|
+
return encodings.reduce((sum, enc) => sum + (enc.maxBitrate ?? 0), 0);
|
|
230
246
|
}
|
|
231
247
|
|
|
232
248
|
export function computeTrackBackupEncodings(
|
|
@@ -255,6 +255,57 @@ describe('RpcClientManager', () => {
|
|
|
255
255
|
}
|
|
256
256
|
});
|
|
257
257
|
|
|
258
|
+
it('cleans up a failed v2 publish without a later ack timeout', async () => {
|
|
259
|
+
vi.useFakeTimers();
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
sendTextMock.mockRejectedValue(new Error('engine closed'));
|
|
263
|
+
await expect(
|
|
264
|
+
rpcClientManager.performRpc({
|
|
265
|
+
destinationIdentity: 'remote-identity',
|
|
266
|
+
method: 'test-method',
|
|
267
|
+
payload: 'test-payload',
|
|
268
|
+
}),
|
|
269
|
+
).rejects.toThrow('engine closed');
|
|
270
|
+
|
|
271
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
272
|
+
expect((rpcClientManager as any).pendingAcks.size).toBe(0);
|
|
273
|
+
expect((rpcClientManager as any).pendingResponses.size).toBe(0);
|
|
274
|
+
await vi.advanceTimersByTimeAsync(7001);
|
|
275
|
+
// An unhandled rejection from completionFuture would also fail Vitest.
|
|
276
|
+
} finally {
|
|
277
|
+
vi.useRealTimers();
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('handles an ack timeout while a v2 publish is still pending', async () => {
|
|
282
|
+
vi.useFakeTimers();
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
let resolveSend!: () => void;
|
|
286
|
+
sendTextMock.mockReturnValue(
|
|
287
|
+
new Promise<void>((resolve) => {
|
|
288
|
+
resolveSend = resolve;
|
|
289
|
+
}),
|
|
290
|
+
);
|
|
291
|
+
const performRpcPromise = rpcClientManager.performRpc({
|
|
292
|
+
destinationIdentity: 'remote-identity',
|
|
293
|
+
method: 'test-method',
|
|
294
|
+
payload: 'test-payload',
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
await vi.advanceTimersByTimeAsync(7001);
|
|
298
|
+
resolveSend();
|
|
299
|
+
const [, completionPromise] = await performRpcPromise;
|
|
300
|
+
await expect(completionPromise).rejects.toThrow(/Connection timeout/i);
|
|
301
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
302
|
+
expect((rpcClientManager as any).pendingAcks.size).toBe(0);
|
|
303
|
+
expect((rpcClientManager as any).pendingResponses.size).toBe(0);
|
|
304
|
+
} finally {
|
|
305
|
+
vi.useRealTimers();
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
|
|
258
309
|
it('should handle a v2 RPC error response', async () => {
|
|
259
310
|
const errorCode = 101;
|
|
260
311
|
const errorMessage = 'Test error message';
|
|
@@ -108,22 +108,13 @@ export default class RpcClientManager extends (EventEmitter as new () => TypedEm
|
|
|
108
108
|
participantIdentity: destinationIdentity,
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
method,
|
|
115
|
-
payload,
|
|
116
|
-
effectiveTimeoutMs,
|
|
117
|
-
remoteClientProtocol,
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
responseTimeoutId = setTimeout(() => {
|
|
121
|
-
this.pendingResponses.delete(id);
|
|
122
|
-
completionFuture.reject?.(RpcError.builtIn('RESPONSE_TIMEOUT'));
|
|
123
|
-
}, responseTimeoutMs);
|
|
124
|
-
|
|
111
|
+
// Observe the future before publishing: a slow send can outlast the ack timer.
|
|
112
|
+
// Keep the returned promise rejected for callers, while marking its rejection
|
|
113
|
+
// handled until performRpc has finished publishing and can return it.
|
|
125
114
|
const completionPromise = completionFuture.promise.finally(() => {
|
|
126
|
-
|
|
115
|
+
if (responseTimeoutId !== null) {
|
|
116
|
+
clearTimeout(responseTimeoutId);
|
|
117
|
+
}
|
|
127
118
|
|
|
128
119
|
if (this.pendingAcks.has(id)) {
|
|
129
120
|
this.log.warn('RPC response received before ack', id);
|
|
@@ -131,6 +122,32 @@ export default class RpcClientManager extends (EventEmitter as new () => TypedEm
|
|
|
131
122
|
clearTimeout(ackTimeoutId);
|
|
132
123
|
}
|
|
133
124
|
});
|
|
125
|
+
completionPromise.catch(() => {});
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
await this.publishRpcRequest(
|
|
129
|
+
destinationIdentity,
|
|
130
|
+
id,
|
|
131
|
+
method,
|
|
132
|
+
payload,
|
|
133
|
+
effectiveTimeoutMs,
|
|
134
|
+
remoteClientProtocol,
|
|
135
|
+
);
|
|
136
|
+
} catch (e) {
|
|
137
|
+
// The caller receives the publish error. Do not leave an ack timer that
|
|
138
|
+
// later rejects a future the caller never received.
|
|
139
|
+
clearTimeout(ackTimeoutId);
|
|
140
|
+
this.pendingAcks.delete(id);
|
|
141
|
+
this.pendingResponses.delete(id);
|
|
142
|
+
throw e;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (this.pendingResponses.has(id)) {
|
|
146
|
+
responseTimeoutId = setTimeout(() => {
|
|
147
|
+
this.pendingResponses.delete(id);
|
|
148
|
+
completionFuture.reject?.(RpcError.builtIn('RESPONSE_TIMEOUT'));
|
|
149
|
+
}, responseTimeoutMs);
|
|
150
|
+
}
|
|
134
151
|
|
|
135
152
|
return [id, completionPromise];
|
|
136
153
|
}
|
|
@@ -5,12 +5,13 @@ import { debounce } from '../debounce';
|
|
|
5
5
|
import { DeviceUnsupportedError, TrackInvalidError } from '../errors';
|
|
6
6
|
import { TrackEvent } from '../events';
|
|
7
7
|
import type { LoggerOptions } from '../types';
|
|
8
|
-
import { compareVersions, isMobile, sleep, unwrapConstraint } from '../utils';
|
|
8
|
+
import { compareVersions, isAppleMobile, isMobile, sleep, unwrapConstraint } from '../utils';
|
|
9
9
|
import { Track, attachToElement, detachTrack } from './Track';
|
|
10
10
|
import type { VideoCodec } from './options';
|
|
11
11
|
import type { TrackProcessor } from './processor/types';
|
|
12
12
|
import { LocalTrackRecorder, isRecordingSupported } from './record';
|
|
13
13
|
import type { ReplaceTrackOptions } from './types';
|
|
14
|
+
import { waitForFirstVideoFrame } from './utils';
|
|
14
15
|
|
|
15
16
|
const DEFAULT_DIMENSIONS_TIMEOUT = 1000;
|
|
16
17
|
const PRE_CONNECT_BUFFER_TIMEOUT = 10_000;
|
|
@@ -224,18 +225,28 @@ export default abstract class LocalTrack<
|
|
|
224
225
|
throw new Error('cannot get dimensions for audio tracks');
|
|
225
226
|
}
|
|
226
227
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
const started = Date.now();
|
|
229
|
+
|
|
230
|
+
if (isAppleMobile()) {
|
|
231
|
+
// iOS and iPadOS keep reporting the camera's sensor frame from getSettings() until the
|
|
232
|
+
// camera has delivered its first picture, so a portrait capture initially reads as
|
|
233
|
+
// landscape. Wait for that first frame instead of guessing at a delay.
|
|
234
|
+
// Gated to the Apple capture pipeline rather than run everywhere: elsewhere getSettings() is
|
|
235
|
+
// already right and the first frame can be hundreds of milliseconds out (measured ~500ms on
|
|
236
|
+
// macOS Safari), which would be pure added publish latency.
|
|
237
|
+
// https://github.com/livekit/client-sdk-js/issues/2099
|
|
238
|
+
// https://github.com/livekit/client-sdk-js/issues/2107
|
|
239
|
+
await waitForFirstVideoFrame(this._mediaStreamTrack, timeout, this.attachedElements);
|
|
231
240
|
}
|
|
232
241
|
|
|
233
|
-
|
|
234
|
-
while (Date.now() - started < timeout) {
|
|
242
|
+
while (true) {
|
|
235
243
|
const dims = this.dimensions;
|
|
236
244
|
if (dims) {
|
|
237
245
|
return dims;
|
|
238
246
|
}
|
|
247
|
+
if (Date.now() - started >= timeout) {
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
239
250
|
await sleep(50);
|
|
240
251
|
}
|
|
241
252
|
throw new TrackInvalidError('unable to get track dimensions after timeout');
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import type { VideoSenderStats } from '../stats';
|
|
17
17
|
import { computeBitrate, monitorFrequency } from '../stats';
|
|
18
18
|
import type { LoggerOptions } from '../types';
|
|
19
|
-
import { isFireFox, isMobile, isSVCCodec, isWeb } from '../utils';
|
|
19
|
+
import { isFireFox, isMobile, isSVCCodec, isSVCSimulcast, isWeb } from '../utils';
|
|
20
20
|
import LocalTrack from './LocalTrack';
|
|
21
21
|
import { Track, VideoQuality } from './Track';
|
|
22
22
|
import type { TrackPublishOptions, VideoCaptureOptions, VideoCodec } from './options';
|
|
@@ -243,6 +243,16 @@ export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
|
|
243
243
|
return items;
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
/**
|
|
247
|
+
* Whether `codec` is being published as SVC (a single stream carrying all spatial
|
|
248
|
+
* layers) as opposed to rid based simulcast. VP9/AV1 are SVC unless the publisher
|
|
249
|
+
* opted into simulcast, in which case each rid is an independent stream and the
|
|
250
|
+
* layers can be enabled/disabled individually.
|
|
251
|
+
*/
|
|
252
|
+
private isSvcPublish(codec?: string): boolean {
|
|
253
|
+
return isSVCCodec(codec) && !isSVCSimulcast(codec, this.publishOptions);
|
|
254
|
+
}
|
|
255
|
+
|
|
246
256
|
setPublishingQuality(maxQuality: VideoQuality) {
|
|
247
257
|
const qualities: SubscribedQuality[] = [];
|
|
248
258
|
for (let q = VideoQuality.LOW; q <= VideoQuality.HIGH; q += 1) {
|
|
@@ -254,7 +264,7 @@ export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
|
|
254
264
|
);
|
|
255
265
|
}
|
|
256
266
|
this.log.debug(`setting publishing quality. max quality ${maxQuality}`, this.logContext);
|
|
257
|
-
this.setPublishingLayers(
|
|
267
|
+
this.setPublishingLayers(this.isSvcPublish(this.codec), qualities);
|
|
258
268
|
}
|
|
259
269
|
|
|
260
270
|
async restartTrack(options?: VideoCaptureOptions) {
|
|
@@ -472,12 +482,19 @@ export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
|
|
472
482
|
// browser will reenable disabled codec/layers after new codec has been published,
|
|
473
483
|
// so refresh subscribedCodecs after publish a new codec
|
|
474
484
|
setTimeout(() => {
|
|
475
|
-
|
|
476
|
-
this.setPublishingCodecs(this.subscribedCodecs);
|
|
477
|
-
}
|
|
485
|
+
this.refreshSubscribedCodecs();
|
|
478
486
|
}, refreshSubscribedCodecAfterNewCodec);
|
|
479
487
|
}
|
|
480
488
|
|
|
489
|
+
/** @interal */
|
|
490
|
+
async refreshSubscribedCodecs() {
|
|
491
|
+
if (this.subscribedCodecs) {
|
|
492
|
+
return this.setPublishingCodecs(this.subscribedCodecs).catch((e) =>
|
|
493
|
+
this.log.warn(`failed to refresh codec for track`, { ...this.logContext, error: e }),
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
481
498
|
/**
|
|
482
499
|
* @internal
|
|
483
500
|
* Sets codecs that should be publishing, returns new codecs that have not yet
|
|
@@ -491,7 +508,7 @@ export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
|
|
491
508
|
});
|
|
492
509
|
// only enable simulcast codec for preference codec setted
|
|
493
510
|
if (!this.codec && codecs.length > 0) {
|
|
494
|
-
await this.setPublishingLayers(
|
|
511
|
+
await this.setPublishingLayers(this.isSvcPublish(codecs[0].codec), codecs[0].qualities);
|
|
495
512
|
|
|
496
513
|
return [];
|
|
497
514
|
}
|
|
@@ -501,7 +518,7 @@ export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
|
|
501
518
|
const newCodecs: VideoCodec[] = [];
|
|
502
519
|
for await (const codec of codecs) {
|
|
503
520
|
if (!this.codec || this.codec === codec.codec) {
|
|
504
|
-
await this.setPublishingLayers(
|
|
521
|
+
await this.setPublishingLayers(this.isSvcPublish(codec.codec), codec.qualities);
|
|
505
522
|
} else {
|
|
506
523
|
const simulcastCodecInfo = this.simulcastCodecs.get(codec.codec as VideoCodec);
|
|
507
524
|
this.log.debug(`try setPublishingCodec for ${codec.codec}`, {
|
|
@@ -522,7 +539,7 @@ export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
|
|
522
539
|
simulcastCodecInfo.encodings!,
|
|
523
540
|
codec.qualities,
|
|
524
541
|
this.senderLock,
|
|
525
|
-
|
|
542
|
+
this.isSvcPublish(codec.codec),
|
|
526
543
|
this.log,
|
|
527
544
|
this.logContext,
|
|
528
545
|
);
|
|
@@ -60,7 +60,7 @@ export default class RemoteAudioTrack extends RemoteTrack<Track.Kind.Audio> {
|
|
|
60
60
|
* gets the volume of attached audio elements (loudest)
|
|
61
61
|
*/
|
|
62
62
|
getVolume(): number {
|
|
63
|
-
if (this.elementVolume) {
|
|
63
|
+
if (this.elementVolume !== undefined) {
|
|
64
64
|
return this.elementVolume;
|
|
65
65
|
}
|
|
66
66
|
if (isReactNative()) {
|
|
@@ -115,7 +115,7 @@ export default class RemoteAudioTrack extends RemoteTrack<Track.Kind.Audio> {
|
|
|
115
115
|
element.muted = true;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
if (this.elementVolume) {
|
|
118
|
+
if (this.elementVolume !== undefined) {
|
|
119
119
|
// make sure volume setting is being applied to the newly attached element
|
|
120
120
|
this.setVolume(this.elementVolume);
|
|
121
121
|
}
|
|
@@ -191,7 +191,7 @@ export default class RemoteAudioTrack extends RemoteTrack<Track.Kind.Audio> {
|
|
|
191
191
|
lastNode.connect(this.gainNode);
|
|
192
192
|
this.gainNode.connect(context.destination);
|
|
193
193
|
|
|
194
|
-
if (this.elementVolume) {
|
|
194
|
+
if (this.elementVolume !== undefined) {
|
|
195
195
|
this.gainNode.gain.setTargetAtTime(this.elementVolume, 0, 0.1);
|
|
196
196
|
}
|
|
197
197
|
|