@stream-io/video-client 1.6.3 → 1.6.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/CHANGELOG.md +7 -0
- package/dist/index.browser.es.js +122 -100
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +122 -100
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +122 -100
- package/dist/index.es.js.map +1 -1
- package/dist/src/devices/CameraManager.d.ts +20 -0
- package/dist/src/rtc/codecs.d.ts +4 -0
- package/dist/src/rtc/videoLayers.d.ts +4 -2
- package/dist/src/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/Call.ts +8 -6
- package/src/devices/CameraManager.ts +31 -3
- package/src/rtc/Publisher.ts +15 -19
- package/src/rtc/__tests__/videoLayers.test.ts +36 -6
- package/src/rtc/codecs.ts +15 -0
- package/src/rtc/videoLayers.ts +18 -4
- package/src/types.ts +1 -0
package/dist/index.cjs.js
CHANGED
|
@@ -5,9 +5,9 @@ var runtime = require('@protobuf-ts/runtime');
|
|
|
5
5
|
var runtimeRpc = require('@protobuf-ts/runtime-rpc');
|
|
6
6
|
var axios = require('axios');
|
|
7
7
|
var twirpTransport = require('@protobuf-ts/twirp-transport');
|
|
8
|
+
var uaParserJs = require('ua-parser-js');
|
|
8
9
|
var rxjs = require('rxjs');
|
|
9
10
|
var SDP = require('sdp-transform');
|
|
10
|
-
var uaParserJs = require('ua-parser-js');
|
|
11
11
|
var https = require('https');
|
|
12
12
|
var WebSocket$1 = require('isomorphic-ws');
|
|
13
13
|
var base64Js = require('base64-js');
|
|
@@ -6841,6 +6841,72 @@ const retryable = async (rpc, signal) => {
|
|
|
6841
6841
|
return result;
|
|
6842
6842
|
};
|
|
6843
6843
|
|
|
6844
|
+
const version = "1.6.4" ;
|
|
6845
|
+
const [major, minor, patch] = version.split('.');
|
|
6846
|
+
let sdkInfo = {
|
|
6847
|
+
type: SdkType.PLAIN_JAVASCRIPT,
|
|
6848
|
+
major,
|
|
6849
|
+
minor,
|
|
6850
|
+
patch,
|
|
6851
|
+
};
|
|
6852
|
+
let osInfo;
|
|
6853
|
+
let deviceInfo;
|
|
6854
|
+
let webRtcInfo;
|
|
6855
|
+
const setSdkInfo = (info) => {
|
|
6856
|
+
sdkInfo = info;
|
|
6857
|
+
};
|
|
6858
|
+
const getSdkInfo = () => {
|
|
6859
|
+
return sdkInfo;
|
|
6860
|
+
};
|
|
6861
|
+
const setOSInfo = (info) => {
|
|
6862
|
+
osInfo = info;
|
|
6863
|
+
};
|
|
6864
|
+
const getOSInfo = () => {
|
|
6865
|
+
return osInfo;
|
|
6866
|
+
};
|
|
6867
|
+
const setDeviceInfo = (info) => {
|
|
6868
|
+
deviceInfo = info;
|
|
6869
|
+
};
|
|
6870
|
+
const getDeviceInfo = () => {
|
|
6871
|
+
return deviceInfo;
|
|
6872
|
+
};
|
|
6873
|
+
const getWebRTCInfo = () => {
|
|
6874
|
+
return webRtcInfo;
|
|
6875
|
+
};
|
|
6876
|
+
const setWebRTCInfo = (info) => {
|
|
6877
|
+
webRtcInfo = info;
|
|
6878
|
+
};
|
|
6879
|
+
const getClientDetails = () => {
|
|
6880
|
+
if (isReactNative()) {
|
|
6881
|
+
// Since RN doesn't support web, sharing browser info is not required
|
|
6882
|
+
return {
|
|
6883
|
+
sdk: getSdkInfo(),
|
|
6884
|
+
os: getOSInfo(),
|
|
6885
|
+
device: getDeviceInfo(),
|
|
6886
|
+
};
|
|
6887
|
+
}
|
|
6888
|
+
const userAgent = new uaParserJs.UAParser(navigator.userAgent);
|
|
6889
|
+
const { browser, os, device, cpu } = userAgent.getResult();
|
|
6890
|
+
return {
|
|
6891
|
+
sdk: getSdkInfo(),
|
|
6892
|
+
browser: {
|
|
6893
|
+
name: browser.name || navigator.userAgent,
|
|
6894
|
+
version: browser.version || '',
|
|
6895
|
+
},
|
|
6896
|
+
os: {
|
|
6897
|
+
name: os.name || '',
|
|
6898
|
+
version: os.version || '',
|
|
6899
|
+
architecture: cpu.architecture || '',
|
|
6900
|
+
},
|
|
6901
|
+
device: {
|
|
6902
|
+
name: [device.vendor, device.model, device.type]
|
|
6903
|
+
.filter(Boolean)
|
|
6904
|
+
.join(' '),
|
|
6905
|
+
version: '',
|
|
6906
|
+
},
|
|
6907
|
+
};
|
|
6908
|
+
};
|
|
6909
|
+
|
|
6844
6910
|
/**
|
|
6845
6911
|
* Returns back a list of sorted codecs, with the preferred codec first.
|
|
6846
6912
|
*
|
|
@@ -6915,6 +6981,20 @@ const getGenericSdp = async (direction) => {
|
|
|
6915
6981
|
tempPc.close();
|
|
6916
6982
|
return sdp;
|
|
6917
6983
|
};
|
|
6984
|
+
/**
|
|
6985
|
+
* Returns the optimal codec for RN.
|
|
6986
|
+
*/
|
|
6987
|
+
const getRNOptimalCodec = () => {
|
|
6988
|
+
const osName = getOSInfo()?.name.toLowerCase();
|
|
6989
|
+
// in ipads it was noticed that if vp8 codec is used
|
|
6990
|
+
// then the bytes sent is 0 in the outbound-rtp
|
|
6991
|
+
// so we are forcing h264 codec for ipads
|
|
6992
|
+
if (osName === 'ipados')
|
|
6993
|
+
return 'h264';
|
|
6994
|
+
if (osName === 'android')
|
|
6995
|
+
return 'vp8';
|
|
6996
|
+
return undefined;
|
|
6997
|
+
};
|
|
6918
6998
|
|
|
6919
6999
|
const sfuEventKinds = {
|
|
6920
7000
|
subscriberOffer: undefined,
|
|
@@ -7038,12 +7118,13 @@ const defaultBitratePerRid = {
|
|
|
7038
7118
|
*
|
|
7039
7119
|
* @param videoTrack the video track to find optimal layers for.
|
|
7040
7120
|
* @param targetResolution the expected target resolution.
|
|
7121
|
+
* @param preferredBitrate the preferred bitrate for the video track.
|
|
7041
7122
|
*/
|
|
7042
|
-
const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetResolution) => {
|
|
7123
|
+
const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetResolution, preferredBitrate) => {
|
|
7043
7124
|
const optimalVideoLayers = [];
|
|
7044
7125
|
const settings = videoTrack.getSettings();
|
|
7045
7126
|
const { width: w = 0, height: h = 0 } = settings;
|
|
7046
|
-
const maxBitrate = getComputedMaxBitrate(targetResolution, w, h);
|
|
7127
|
+
const maxBitrate = getComputedMaxBitrate(targetResolution, w, h, preferredBitrate);
|
|
7047
7128
|
let downscaleFactor = 1;
|
|
7048
7129
|
['f', 'h', 'q'].forEach((rid) => {
|
|
7049
7130
|
// Reversing the order [f, h, q] to [q, h, f] as Chrome uses encoding index
|
|
@@ -7074,18 +7155,20 @@ const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetReso
|
|
|
7074
7155
|
* @param targetResolution the target resolution.
|
|
7075
7156
|
* @param currentWidth the current width of the track.
|
|
7076
7157
|
* @param currentHeight the current height of the track.
|
|
7158
|
+
* @param preferredBitrate the preferred bitrate for the track.
|
|
7077
7159
|
*/
|
|
7078
|
-
const getComputedMaxBitrate = (targetResolution, currentWidth, currentHeight) => {
|
|
7160
|
+
const getComputedMaxBitrate = (targetResolution, currentWidth, currentHeight, preferredBitrate) => {
|
|
7079
7161
|
// if the current resolution is lower than the target resolution,
|
|
7080
7162
|
// we want to proportionally reduce the target bitrate
|
|
7081
|
-
const { width: targetWidth, height: targetHeight } = targetResolution;
|
|
7163
|
+
const { width: targetWidth, height: targetHeight, bitrate: targetBitrate, } = targetResolution;
|
|
7164
|
+
const bitrate = preferredBitrate || targetBitrate;
|
|
7082
7165
|
if (currentWidth < targetWidth || currentHeight < targetHeight) {
|
|
7083
7166
|
const currentPixels = currentWidth * currentHeight;
|
|
7084
7167
|
const targetPixels = targetWidth * targetHeight;
|
|
7085
7168
|
const reductionFactor = currentPixels / targetPixels;
|
|
7086
|
-
return Math.round(
|
|
7169
|
+
return Math.round(bitrate * reductionFactor);
|
|
7087
7170
|
}
|
|
7088
|
-
return
|
|
7171
|
+
return bitrate;
|
|
7089
7172
|
};
|
|
7090
7173
|
/**
|
|
7091
7174
|
* Browsers have different simulcast constraints for different video resolutions.
|
|
@@ -8769,72 +8852,6 @@ const enableHighQualityAudio = (sdp, trackMid, maxBitrate = 510000) => {
|
|
|
8769
8852
|
return SDP__namespace.write(parsedSdp);
|
|
8770
8853
|
};
|
|
8771
8854
|
|
|
8772
|
-
const version = "1.6.3" ;
|
|
8773
|
-
const [major, minor, patch] = version.split('.');
|
|
8774
|
-
let sdkInfo = {
|
|
8775
|
-
type: SdkType.PLAIN_JAVASCRIPT,
|
|
8776
|
-
major,
|
|
8777
|
-
minor,
|
|
8778
|
-
patch,
|
|
8779
|
-
};
|
|
8780
|
-
let osInfo;
|
|
8781
|
-
let deviceInfo;
|
|
8782
|
-
let webRtcInfo;
|
|
8783
|
-
const setSdkInfo = (info) => {
|
|
8784
|
-
sdkInfo = info;
|
|
8785
|
-
};
|
|
8786
|
-
const getSdkInfo = () => {
|
|
8787
|
-
return sdkInfo;
|
|
8788
|
-
};
|
|
8789
|
-
const setOSInfo = (info) => {
|
|
8790
|
-
osInfo = info;
|
|
8791
|
-
};
|
|
8792
|
-
const getOSInfo = () => {
|
|
8793
|
-
return osInfo;
|
|
8794
|
-
};
|
|
8795
|
-
const setDeviceInfo = (info) => {
|
|
8796
|
-
deviceInfo = info;
|
|
8797
|
-
};
|
|
8798
|
-
const getDeviceInfo = () => {
|
|
8799
|
-
return deviceInfo;
|
|
8800
|
-
};
|
|
8801
|
-
const getWebRTCInfo = () => {
|
|
8802
|
-
return webRtcInfo;
|
|
8803
|
-
};
|
|
8804
|
-
const setWebRTCInfo = (info) => {
|
|
8805
|
-
webRtcInfo = info;
|
|
8806
|
-
};
|
|
8807
|
-
const getClientDetails = () => {
|
|
8808
|
-
if (isReactNative()) {
|
|
8809
|
-
// Since RN doesn't support web, sharing browser info is not required
|
|
8810
|
-
return {
|
|
8811
|
-
sdk: getSdkInfo(),
|
|
8812
|
-
os: getOSInfo(),
|
|
8813
|
-
device: getDeviceInfo(),
|
|
8814
|
-
};
|
|
8815
|
-
}
|
|
8816
|
-
const userAgent = new uaParserJs.UAParser(navigator.userAgent);
|
|
8817
|
-
const { browser, os, device, cpu } = userAgent.getResult();
|
|
8818
|
-
return {
|
|
8819
|
-
sdk: getSdkInfo(),
|
|
8820
|
-
browser: {
|
|
8821
|
-
name: browser.name || navigator.userAgent,
|
|
8822
|
-
version: browser.version || '',
|
|
8823
|
-
},
|
|
8824
|
-
os: {
|
|
8825
|
-
name: os.name || '',
|
|
8826
|
-
version: os.version || '',
|
|
8827
|
-
architecture: cpu.architecture || '',
|
|
8828
|
-
},
|
|
8829
|
-
device: {
|
|
8830
|
-
name: [device.vendor, device.model, device.type]
|
|
8831
|
-
.filter(Boolean)
|
|
8832
|
-
.join(' '),
|
|
8833
|
-
version: '',
|
|
8834
|
-
},
|
|
8835
|
-
};
|
|
8836
|
-
};
|
|
8837
|
-
|
|
8838
8855
|
/**
|
|
8839
8856
|
* The `Publisher` is responsible for publishing/unpublishing media streams to/from the SFU
|
|
8840
8857
|
*
|
|
@@ -8963,24 +8980,12 @@ class Publisher {
|
|
|
8963
8980
|
const targetResolution = settings?.video
|
|
8964
8981
|
.target_resolution;
|
|
8965
8982
|
const screenShareBitrate = settings?.screensharing.target_resolution?.bitrate;
|
|
8983
|
+
const { preferredBitrate, preferredCodec, screenShareSettings } = opts;
|
|
8966
8984
|
const videoEncodings = trackType === TrackType.VIDEO
|
|
8967
|
-
? findOptimalVideoLayers(track, targetResolution)
|
|
8985
|
+
? findOptimalVideoLayers(track, targetResolution, preferredBitrate)
|
|
8968
8986
|
: trackType === TrackType.SCREEN_SHARE
|
|
8969
|
-
? findOptimalScreenSharingLayers(track,
|
|
8987
|
+
? findOptimalScreenSharingLayers(track, screenShareSettings, screenShareBitrate)
|
|
8970
8988
|
: undefined;
|
|
8971
|
-
let preferredCodec = opts.preferredCodec;
|
|
8972
|
-
if (!preferredCodec && trackType === TrackType.VIDEO && isReactNative()) {
|
|
8973
|
-
const osName = getOSInfo()?.name.toLowerCase();
|
|
8974
|
-
if (osName === 'ipados') {
|
|
8975
|
-
// in ipads it was noticed that if vp8 codec is used
|
|
8976
|
-
// then the bytes sent is 0 in the outbound-rtp
|
|
8977
|
-
// so we are forcing h264 codec for ipads
|
|
8978
|
-
preferredCodec = 'H264';
|
|
8979
|
-
}
|
|
8980
|
-
else if (osName === 'android') {
|
|
8981
|
-
preferredCodec = 'VP8';
|
|
8982
|
-
}
|
|
8983
|
-
}
|
|
8984
8989
|
// listen for 'ended' event on the track as it might be ended abruptly
|
|
8985
8990
|
// by an external factor as permission revokes, device disconnected, etc.
|
|
8986
8991
|
// keep in mind that `track.stop()` doesn't trigger this event.
|
|
@@ -8999,8 +9004,11 @@ class Publisher {
|
|
|
8999
9004
|
this.transceiverInitOrder.push(trackType);
|
|
9000
9005
|
this.transceiverRegistry[trackType] = transceiver;
|
|
9001
9006
|
this.publishOptionsPerTrackType.set(trackType, opts);
|
|
9007
|
+
const codec = isReactNative() && trackType === TrackType.VIDEO && !preferredCodec
|
|
9008
|
+
? getRNOptimalCodec()
|
|
9009
|
+
: preferredCodec;
|
|
9002
9010
|
const codecPreferences = 'setCodecPreferences' in transceiver
|
|
9003
|
-
? this.getCodecPreferences(trackType,
|
|
9011
|
+
? this.getCodecPreferences(trackType, codec)
|
|
9004
9012
|
: undefined;
|
|
9005
9013
|
if (codecPreferences) {
|
|
9006
9014
|
this.logger('info', `Setting ${TrackType[trackType]} codec preferences`, codecPreferences);
|
|
@@ -9314,7 +9322,7 @@ class Publisher {
|
|
|
9314
9322
|
const publishOpts = this.publishOptionsPerTrackType.get(trackType);
|
|
9315
9323
|
optimalLayers =
|
|
9316
9324
|
trackType === TrackType.VIDEO
|
|
9317
|
-
? findOptimalVideoLayers(track, targetResolution)
|
|
9325
|
+
? findOptimalVideoLayers(track, targetResolution, publishOpts?.preferredBitrate)
|
|
9318
9326
|
: trackType === TrackType.SCREEN_SHARE
|
|
9319
9327
|
? findOptimalScreenSharingLayers(track, publishOpts?.screenShareSettings)
|
|
9320
9328
|
: [];
|
|
@@ -12188,6 +12196,17 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
12188
12196
|
height: 720,
|
|
12189
12197
|
};
|
|
12190
12198
|
}
|
|
12199
|
+
/**
|
|
12200
|
+
* The publish options for the camera.
|
|
12201
|
+
*
|
|
12202
|
+
* @internal internal use only, not part of the public API.
|
|
12203
|
+
*/
|
|
12204
|
+
get publishOptions() {
|
|
12205
|
+
return {
|
|
12206
|
+
preferredCodec: this.preferredCodec,
|
|
12207
|
+
preferredBitrate: this.preferredBitrate,
|
|
12208
|
+
};
|
|
12209
|
+
}
|
|
12191
12210
|
/**
|
|
12192
12211
|
* Select the camera direction.
|
|
12193
12212
|
*
|
|
@@ -12244,6 +12263,15 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
12244
12263
|
setPreferredCodec(codec) {
|
|
12245
12264
|
this.preferredCodec = codec;
|
|
12246
12265
|
}
|
|
12266
|
+
/**
|
|
12267
|
+
* Sets the preferred bitrate for encoding the video.
|
|
12268
|
+
*
|
|
12269
|
+
* @internal internal use only, not part of the public API.
|
|
12270
|
+
* @param bitrate the bitrate to use for encoding the video.
|
|
12271
|
+
*/
|
|
12272
|
+
setPreferredBitrate(bitrate) {
|
|
12273
|
+
this.preferredBitrate = bitrate;
|
|
12274
|
+
}
|
|
12247
12275
|
getDevices() {
|
|
12248
12276
|
return getVideoDevices();
|
|
12249
12277
|
}
|
|
@@ -12259,9 +12287,7 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
12259
12287
|
return getVideoStream(constraints);
|
|
12260
12288
|
}
|
|
12261
12289
|
publishStream(stream) {
|
|
12262
|
-
return this.call.publishVideoStream(stream,
|
|
12263
|
-
preferredCodec: this.preferredCodec,
|
|
12264
|
-
});
|
|
12290
|
+
return this.call.publishVideoStream(stream, this.publishOptions);
|
|
12265
12291
|
}
|
|
12266
12292
|
stopPublishStream(stopTracks) {
|
|
12267
12293
|
return this.call.stopPublish(TrackType.VIDEO, stopTracks);
|
|
@@ -13654,9 +13680,7 @@ class Call {
|
|
|
13654
13680
|
case TrackType.VIDEO:
|
|
13655
13681
|
const videoStream = this.camera.state.mediaStream;
|
|
13656
13682
|
if (videoStream) {
|
|
13657
|
-
await this.publishVideoStream(videoStream,
|
|
13658
|
-
preferredCodec: this.camera.preferredCodec,
|
|
13659
|
-
});
|
|
13683
|
+
await this.publishVideoStream(videoStream, this.camera.publishOptions);
|
|
13660
13684
|
}
|
|
13661
13685
|
break;
|
|
13662
13686
|
case TrackType.SCREEN_SHARE:
|
|
@@ -14332,9 +14356,7 @@ class Call {
|
|
|
14332
14356
|
if (this.camera.enabled &&
|
|
14333
14357
|
this.camera.state.mediaStream &&
|
|
14334
14358
|
!this.publisher?.isPublishing(TrackType.VIDEO)) {
|
|
14335
|
-
await this.publishVideoStream(this.camera.state.mediaStream,
|
|
14336
|
-
preferredCodec: this.camera.preferredCodec,
|
|
14337
|
-
});
|
|
14359
|
+
await this.publishVideoStream(this.camera.state.mediaStream, this.camera.publishOptions);
|
|
14338
14360
|
}
|
|
14339
14361
|
// Start camera if backend config specifies, and there is no local setting
|
|
14340
14362
|
if (this.camera.state.status === undefined &&
|
|
@@ -16111,7 +16133,7 @@ class StreamClient {
|
|
|
16111
16133
|
});
|
|
16112
16134
|
};
|
|
16113
16135
|
this.getUserAgent = () => {
|
|
16114
|
-
const version = "1.6.
|
|
16136
|
+
const version = "1.6.4" ;
|
|
16115
16137
|
return (this.userAgent ||
|
|
16116
16138
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
16117
16139
|
};
|