@stream-io/video-client 1.7.0 → 1.7.2
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/CHANGELOG.md +14 -0
- package/dist/index.browser.es.js +57 -29
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +57 -29
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +57 -29
- package/dist/index.es.js.map +1 -1
- package/dist/src/StreamSfuClient.d.ts +8 -1
- package/dist/src/devices/CameraManager.d.ts +19 -20
- package/dist/src/rtc/videoLayers.d.ts +4 -4
- package/dist/src/types.d.ts +7 -1
- package/package.json +1 -1
- package/src/Call.ts +1 -0
- package/src/StreamSfuClient.ts +21 -0
- package/src/devices/CameraManager.ts +31 -29
- package/src/devices/__tests__/CameraManager.test.ts +1 -3
- package/src/rtc/Publisher.ts +5 -16
- package/src/rtc/__tests__/Publisher.test.ts +2 -0
- package/src/rtc/__tests__/Subscriber.test.ts +2 -0
- package/src/rtc/videoLayers.ts +9 -6
- package/src/types.ts +8 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [1.7.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.7.1...@stream-io/video-client-1.7.2) (2024-09-20)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* overridable bitrate and bitrate downscale factor ([#1493](https://github.com/GetStream/stream-video-js/issues/1493)) ([cce5d8e](https://github.com/GetStream/stream-video-js/commit/cce5d8e641a9182a1779952e4e62aa16ec21ab92))
|
|
11
|
+
|
|
12
|
+
## [1.7.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.7.0...@stream-io/video-client-1.7.1) (2024-09-20)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* don't attempt to recover broken WebSockets when there isn't a network connection ([#1490](https://github.com/GetStream/stream-video-js/issues/1490)) ([d576f48](https://github.com/GetStream/stream-video-js/commit/d576f48c7f819d48008359a3c30fe5d1a3372145))
|
|
18
|
+
|
|
5
19
|
## [1.7.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.6.5...@stream-io/video-client-1.7.0) (2024-09-19)
|
|
6
20
|
|
|
7
21
|
|
package/dist/index.browser.es.js
CHANGED
|
@@ -3013,7 +3013,7 @@ const retryable = async (rpc, signal) => {
|
|
|
3013
3013
|
return result;
|
|
3014
3014
|
};
|
|
3015
3015
|
|
|
3016
|
-
const version = "1.7.
|
|
3016
|
+
const version = "1.7.2";
|
|
3017
3017
|
const [major, minor, patch] = version.split('.');
|
|
3018
3018
|
let sdkInfo = {
|
|
3019
3019
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -3290,14 +3290,16 @@ const defaultBitratePerRid = {
|
|
|
3290
3290
|
*
|
|
3291
3291
|
* @param videoTrack the video track to find optimal layers for.
|
|
3292
3292
|
* @param targetResolution the expected target resolution.
|
|
3293
|
-
* @param
|
|
3293
|
+
* @param publishOptions the publish options for the track.
|
|
3294
3294
|
*/
|
|
3295
|
-
const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetResolution,
|
|
3295
|
+
const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetResolution, publishOptions) => {
|
|
3296
3296
|
const optimalVideoLayers = [];
|
|
3297
3297
|
const settings = videoTrack.getSettings();
|
|
3298
3298
|
const { width: w = 0, height: h = 0 } = settings;
|
|
3299
|
+
const { preferredBitrate, bitrateDownscaleFactor = 2 } = publishOptions || {};
|
|
3299
3300
|
const maxBitrate = getComputedMaxBitrate(targetResolution, w, h, preferredBitrate);
|
|
3300
3301
|
let downscaleFactor = 1;
|
|
3302
|
+
let bitrateFactor = 1;
|
|
3301
3303
|
['f', 'h', 'q'].forEach((rid) => {
|
|
3302
3304
|
// Reversing the order [f, h, q] to [q, h, f] as Chrome uses encoding index
|
|
3303
3305
|
// when deciding which layer to disable when CPU or bandwidth is constrained.
|
|
@@ -3307,11 +3309,12 @@ const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetReso
|
|
|
3307
3309
|
rid,
|
|
3308
3310
|
width: Math.round(w / downscaleFactor),
|
|
3309
3311
|
height: Math.round(h / downscaleFactor),
|
|
3310
|
-
maxBitrate: Math.round(maxBitrate /
|
|
3312
|
+
maxBitrate: Math.round(maxBitrate / bitrateFactor) || defaultBitratePerRid[rid],
|
|
3311
3313
|
scaleResolutionDownBy: downscaleFactor,
|
|
3312
3314
|
maxFramerate: 30,
|
|
3313
3315
|
});
|
|
3314
3316
|
downscaleFactor *= 2;
|
|
3317
|
+
bitrateFactor *= bitrateDownscaleFactor;
|
|
3315
3318
|
});
|
|
3316
3319
|
// for simplicity, we start with all layers enabled, then this function
|
|
3317
3320
|
// will clear/reassign the layers that are not needed
|
|
@@ -3371,7 +3374,8 @@ const withSimulcastConstraints = (settings, optimalVideoLayers) => {
|
|
|
3371
3374
|
rid: ridMapping[index], // reassign rid
|
|
3372
3375
|
}));
|
|
3373
3376
|
};
|
|
3374
|
-
const findOptimalScreenSharingLayers = (videoTrack,
|
|
3377
|
+
const findOptimalScreenSharingLayers = (videoTrack, publishOptions, defaultMaxBitrate = 3000000) => {
|
|
3378
|
+
const { screenShareSettings: preferences } = publishOptions || {};
|
|
3375
3379
|
const settings = videoTrack.getSettings();
|
|
3376
3380
|
return [
|
|
3377
3381
|
{
|
|
@@ -5152,11 +5156,10 @@ class Publisher {
|
|
|
5152
5156
|
const targetResolution = settings?.video
|
|
5153
5157
|
.target_resolution;
|
|
5154
5158
|
const screenShareBitrate = settings?.screensharing.target_resolution?.bitrate;
|
|
5155
|
-
const { preferredBitrate, preferredCodec, screenShareSettings } = opts;
|
|
5156
5159
|
const videoEncodings = trackType === TrackType.VIDEO
|
|
5157
|
-
? findOptimalVideoLayers(track, targetResolution,
|
|
5160
|
+
? findOptimalVideoLayers(track, targetResolution, opts)
|
|
5158
5161
|
: trackType === TrackType.SCREEN_SHARE
|
|
5159
|
-
? findOptimalScreenSharingLayers(track,
|
|
5162
|
+
? findOptimalScreenSharingLayers(track, opts, screenShareBitrate)
|
|
5160
5163
|
: undefined;
|
|
5161
5164
|
// listen for 'ended' event on the track as it might be ended abruptly
|
|
5162
5165
|
// by an external factor as permission revokes, device disconnected, etc.
|
|
@@ -5176,6 +5179,7 @@ class Publisher {
|
|
|
5176
5179
|
this.transceiverInitOrder.push(trackType);
|
|
5177
5180
|
this.transceiverRegistry[trackType] = transceiver;
|
|
5178
5181
|
this.publishOptionsPerTrackType.set(trackType, opts);
|
|
5182
|
+
const { preferredCodec } = opts;
|
|
5179
5183
|
const codec = isReactNative() && trackType === TrackType.VIDEO && !preferredCodec
|
|
5180
5184
|
? getRNOptimalCodec()
|
|
5181
5185
|
: preferredCodec;
|
|
@@ -5494,9 +5498,9 @@ class Publisher {
|
|
|
5494
5498
|
const publishOpts = this.publishOptionsPerTrackType.get(trackType);
|
|
5495
5499
|
optimalLayers =
|
|
5496
5500
|
trackType === TrackType.VIDEO
|
|
5497
|
-
? findOptimalVideoLayers(track, targetResolution, publishOpts
|
|
5501
|
+
? findOptimalVideoLayers(track, targetResolution, publishOpts)
|
|
5498
5502
|
: trackType === TrackType.SCREEN_SHARE
|
|
5499
|
-
? findOptimalScreenSharingLayers(track, publishOpts
|
|
5503
|
+
? findOptimalScreenSharingLayers(track, publishOpts)
|
|
5500
5504
|
: [];
|
|
5501
5505
|
this.trackLayersCache[trackType] = optimalLayers;
|
|
5502
5506
|
}
|
|
@@ -5887,7 +5891,7 @@ class StreamSfuClient {
|
|
|
5887
5891
|
/**
|
|
5888
5892
|
* Constructs a new SFU client.
|
|
5889
5893
|
*/
|
|
5890
|
-
constructor({ dispatcher, credentials, sessionId, logTag, joinResponseTimeout = 5000, onSignalClose, }) {
|
|
5894
|
+
constructor({ dispatcher, credentials, sessionId, logTag, joinResponseTimeout = 5000, onSignalClose, streamClient, }) {
|
|
5891
5895
|
/**
|
|
5892
5896
|
* A buffer for ICE Candidates that are received before
|
|
5893
5897
|
* the Publisher and Subscriber Peer Connections are ready to handle them.
|
|
@@ -5936,6 +5940,7 @@ class StreamSfuClient {
|
|
|
5936
5940
|
};
|
|
5937
5941
|
this.restoreWebSocket = () => {
|
|
5938
5942
|
withoutConcurrency(this.restoreWebSocketConcurrencyTag, async () => {
|
|
5943
|
+
await this.networkAvailableTask?.promise;
|
|
5939
5944
|
this.logger('debug', 'Restoring SFU WS connection');
|
|
5940
5945
|
this.cleanUpWebSocket();
|
|
5941
5946
|
await sleep(500);
|
|
@@ -5959,6 +5964,7 @@ class StreamSfuClient {
|
|
|
5959
5964
|
this.dispose = () => {
|
|
5960
5965
|
this.logger('debug', 'Disposing SFU client');
|
|
5961
5966
|
this.unsubscribeIceTrickle();
|
|
5967
|
+
this.unsubscribeNetworkChanged();
|
|
5962
5968
|
clearInterval(this.keepAliveInterval);
|
|
5963
5969
|
clearTimeout(this.connectionCheckTimeout);
|
|
5964
5970
|
clearTimeout(this.migrateAwayTimeout);
|
|
@@ -6144,6 +6150,16 @@ class StreamSfuClient {
|
|
|
6144
6150
|
this.unsubscribeIceTrickle = dispatcher.on('iceTrickle', (iceTrickle) => {
|
|
6145
6151
|
this.iceTrickleBuffer.push(iceTrickle);
|
|
6146
6152
|
});
|
|
6153
|
+
// listen to network changes to handle offline state
|
|
6154
|
+
// we shouldn't attempt to recover websocket connection when offline
|
|
6155
|
+
this.unsubscribeNetworkChanged = streamClient.on('network.changed', (e) => {
|
|
6156
|
+
if (!e.online) {
|
|
6157
|
+
this.networkAvailableTask = promiseWithResolvers();
|
|
6158
|
+
}
|
|
6159
|
+
else {
|
|
6160
|
+
this.networkAvailableTask?.resolve();
|
|
6161
|
+
}
|
|
6162
|
+
});
|
|
6147
6163
|
this.createWebSocket();
|
|
6148
6164
|
}
|
|
6149
6165
|
get isHealthy() {
|
|
@@ -8368,6 +8384,11 @@ class CameraManagerState extends InputMediaDeviceManagerState {
|
|
|
8368
8384
|
}
|
|
8369
8385
|
|
|
8370
8386
|
class CameraManager extends InputMediaDeviceManager {
|
|
8387
|
+
/**
|
|
8388
|
+
* Constructs a new CameraManager.
|
|
8389
|
+
*
|
|
8390
|
+
* @param call the call instance.
|
|
8391
|
+
*/
|
|
8371
8392
|
constructor(call) {
|
|
8372
8393
|
super(call, new CameraManagerState(), TrackType.VIDEO);
|
|
8373
8394
|
this.targetResolution = {
|
|
@@ -8375,17 +8396,6 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
8375
8396
|
height: 720,
|
|
8376
8397
|
};
|
|
8377
8398
|
}
|
|
8378
|
-
/**
|
|
8379
|
-
* The publish options for the camera.
|
|
8380
|
-
*
|
|
8381
|
-
* @internal internal use only, not part of the public API.
|
|
8382
|
-
*/
|
|
8383
|
-
get publishOptions() {
|
|
8384
|
-
return {
|
|
8385
|
-
preferredCodec: this.preferredCodec,
|
|
8386
|
-
preferredBitrate: this.preferredBitrate,
|
|
8387
|
-
};
|
|
8388
|
-
}
|
|
8389
8399
|
/**
|
|
8390
8400
|
* Select the camera direction.
|
|
8391
8401
|
*
|
|
@@ -8440,16 +8450,33 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
8440
8450
|
* @param codec the codec to use for encoding the video.
|
|
8441
8451
|
*/
|
|
8442
8452
|
setPreferredCodec(codec) {
|
|
8443
|
-
this.preferredCodec
|
|
8453
|
+
this.updatePublishOptions({ preferredCodec: codec });
|
|
8444
8454
|
}
|
|
8445
8455
|
/**
|
|
8446
|
-
*
|
|
8456
|
+
* Updates the preferred publish options for the video stream.
|
|
8447
8457
|
*
|
|
8448
|
-
* @internal
|
|
8449
|
-
* @param
|
|
8458
|
+
* @internal
|
|
8459
|
+
* @param options the options to use.
|
|
8460
|
+
*/
|
|
8461
|
+
updatePublishOptions(options) {
|
|
8462
|
+
this.publishOptions = { ...this.publishOptions, ...options };
|
|
8463
|
+
}
|
|
8464
|
+
/**
|
|
8465
|
+
* Returns the capture resolution of the camera.
|
|
8450
8466
|
*/
|
|
8451
|
-
|
|
8452
|
-
|
|
8467
|
+
getCaptureResolution() {
|
|
8468
|
+
const { mediaStream } = this.state;
|
|
8469
|
+
if (!mediaStream)
|
|
8470
|
+
return;
|
|
8471
|
+
const [videoTrack] = mediaStream.getVideoTracks();
|
|
8472
|
+
if (!videoTrack)
|
|
8473
|
+
return;
|
|
8474
|
+
const settings = videoTrack.getSettings();
|
|
8475
|
+
return {
|
|
8476
|
+
width: settings.width,
|
|
8477
|
+
height: settings.height,
|
|
8478
|
+
frameRate: settings.frameRate,
|
|
8479
|
+
};
|
|
8453
8480
|
}
|
|
8454
8481
|
getDevices() {
|
|
8455
8482
|
return getVideoDevices();
|
|
@@ -9435,6 +9462,7 @@ class Call {
|
|
|
9435
9462
|
logTag: String(this.sfuClientTag++),
|
|
9436
9463
|
dispatcher: this.dispatcher,
|
|
9437
9464
|
credentials: this.credentials,
|
|
9465
|
+
streamClient: this.streamClient,
|
|
9438
9466
|
// a new session_id is necessary for the REJOIN strategy.
|
|
9439
9467
|
// we use the previous session_id if available
|
|
9440
9468
|
sessionId: performingRejoin ? undefined : previousSessionId,
|
|
@@ -12310,7 +12338,7 @@ class StreamClient {
|
|
|
12310
12338
|
});
|
|
12311
12339
|
};
|
|
12312
12340
|
this.getUserAgent = () => {
|
|
12313
|
-
const version = "1.7.
|
|
12341
|
+
const version = "1.7.2";
|
|
12314
12342
|
return (this.userAgent ||
|
|
12315
12343
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
12316
12344
|
};
|