@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.es.js
CHANGED
|
@@ -4,9 +4,9 @@ import { ServiceType, stackIntercept, RpcError } from '@protobuf-ts/runtime-rpc'
|
|
|
4
4
|
import axios, { AxiosHeaders } from 'axios';
|
|
5
5
|
export { AxiosError } from 'axios';
|
|
6
6
|
import { TwirpFetchTransport, TwirpErrorCode } from '@protobuf-ts/twirp-transport';
|
|
7
|
+
import { UAParser } from 'ua-parser-js';
|
|
7
8
|
import { ReplaySubject, combineLatest, BehaviorSubject, map as map$1, shareReplay, distinctUntilChanged, takeWhile, distinctUntilKeyChanged, fromEventPattern, startWith, concatMap, merge, from, fromEvent, debounceTime, pairwise, of, debounce, timer } from 'rxjs';
|
|
8
9
|
import * as SDP from 'sdp-transform';
|
|
9
|
-
import { UAParser } from 'ua-parser-js';
|
|
10
10
|
import https from 'https';
|
|
11
11
|
import WebSocket$1 from 'isomorphic-ws';
|
|
12
12
|
import { fromByteArray } from 'base64-js';
|
|
@@ -6821,6 +6821,72 @@ const retryable = async (rpc, signal) => {
|
|
|
6821
6821
|
return result;
|
|
6822
6822
|
};
|
|
6823
6823
|
|
|
6824
|
+
const version = "1.6.4" ;
|
|
6825
|
+
const [major, minor, patch] = version.split('.');
|
|
6826
|
+
let sdkInfo = {
|
|
6827
|
+
type: SdkType.PLAIN_JAVASCRIPT,
|
|
6828
|
+
major,
|
|
6829
|
+
minor,
|
|
6830
|
+
patch,
|
|
6831
|
+
};
|
|
6832
|
+
let osInfo;
|
|
6833
|
+
let deviceInfo;
|
|
6834
|
+
let webRtcInfo;
|
|
6835
|
+
const setSdkInfo = (info) => {
|
|
6836
|
+
sdkInfo = info;
|
|
6837
|
+
};
|
|
6838
|
+
const getSdkInfo = () => {
|
|
6839
|
+
return sdkInfo;
|
|
6840
|
+
};
|
|
6841
|
+
const setOSInfo = (info) => {
|
|
6842
|
+
osInfo = info;
|
|
6843
|
+
};
|
|
6844
|
+
const getOSInfo = () => {
|
|
6845
|
+
return osInfo;
|
|
6846
|
+
};
|
|
6847
|
+
const setDeviceInfo = (info) => {
|
|
6848
|
+
deviceInfo = info;
|
|
6849
|
+
};
|
|
6850
|
+
const getDeviceInfo = () => {
|
|
6851
|
+
return deviceInfo;
|
|
6852
|
+
};
|
|
6853
|
+
const getWebRTCInfo = () => {
|
|
6854
|
+
return webRtcInfo;
|
|
6855
|
+
};
|
|
6856
|
+
const setWebRTCInfo = (info) => {
|
|
6857
|
+
webRtcInfo = info;
|
|
6858
|
+
};
|
|
6859
|
+
const getClientDetails = () => {
|
|
6860
|
+
if (isReactNative()) {
|
|
6861
|
+
// Since RN doesn't support web, sharing browser info is not required
|
|
6862
|
+
return {
|
|
6863
|
+
sdk: getSdkInfo(),
|
|
6864
|
+
os: getOSInfo(),
|
|
6865
|
+
device: getDeviceInfo(),
|
|
6866
|
+
};
|
|
6867
|
+
}
|
|
6868
|
+
const userAgent = new UAParser(navigator.userAgent);
|
|
6869
|
+
const { browser, os, device, cpu } = userAgent.getResult();
|
|
6870
|
+
return {
|
|
6871
|
+
sdk: getSdkInfo(),
|
|
6872
|
+
browser: {
|
|
6873
|
+
name: browser.name || navigator.userAgent,
|
|
6874
|
+
version: browser.version || '',
|
|
6875
|
+
},
|
|
6876
|
+
os: {
|
|
6877
|
+
name: os.name || '',
|
|
6878
|
+
version: os.version || '',
|
|
6879
|
+
architecture: cpu.architecture || '',
|
|
6880
|
+
},
|
|
6881
|
+
device: {
|
|
6882
|
+
name: [device.vendor, device.model, device.type]
|
|
6883
|
+
.filter(Boolean)
|
|
6884
|
+
.join(' '),
|
|
6885
|
+
version: '',
|
|
6886
|
+
},
|
|
6887
|
+
};
|
|
6888
|
+
};
|
|
6889
|
+
|
|
6824
6890
|
/**
|
|
6825
6891
|
* Returns back a list of sorted codecs, with the preferred codec first.
|
|
6826
6892
|
*
|
|
@@ -6895,6 +6961,20 @@ const getGenericSdp = async (direction) => {
|
|
|
6895
6961
|
tempPc.close();
|
|
6896
6962
|
return sdp;
|
|
6897
6963
|
};
|
|
6964
|
+
/**
|
|
6965
|
+
* Returns the optimal codec for RN.
|
|
6966
|
+
*/
|
|
6967
|
+
const getRNOptimalCodec = () => {
|
|
6968
|
+
const osName = getOSInfo()?.name.toLowerCase();
|
|
6969
|
+
// in ipads it was noticed that if vp8 codec is used
|
|
6970
|
+
// then the bytes sent is 0 in the outbound-rtp
|
|
6971
|
+
// so we are forcing h264 codec for ipads
|
|
6972
|
+
if (osName === 'ipados')
|
|
6973
|
+
return 'h264';
|
|
6974
|
+
if (osName === 'android')
|
|
6975
|
+
return 'vp8';
|
|
6976
|
+
return undefined;
|
|
6977
|
+
};
|
|
6898
6978
|
|
|
6899
6979
|
const sfuEventKinds = {
|
|
6900
6980
|
subscriberOffer: undefined,
|
|
@@ -7018,12 +7098,13 @@ const defaultBitratePerRid = {
|
|
|
7018
7098
|
*
|
|
7019
7099
|
* @param videoTrack the video track to find optimal layers for.
|
|
7020
7100
|
* @param targetResolution the expected target resolution.
|
|
7101
|
+
* @param preferredBitrate the preferred bitrate for the video track.
|
|
7021
7102
|
*/
|
|
7022
|
-
const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetResolution) => {
|
|
7103
|
+
const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetResolution, preferredBitrate) => {
|
|
7023
7104
|
const optimalVideoLayers = [];
|
|
7024
7105
|
const settings = videoTrack.getSettings();
|
|
7025
7106
|
const { width: w = 0, height: h = 0 } = settings;
|
|
7026
|
-
const maxBitrate = getComputedMaxBitrate(targetResolution, w, h);
|
|
7107
|
+
const maxBitrate = getComputedMaxBitrate(targetResolution, w, h, preferredBitrate);
|
|
7027
7108
|
let downscaleFactor = 1;
|
|
7028
7109
|
['f', 'h', 'q'].forEach((rid) => {
|
|
7029
7110
|
// Reversing the order [f, h, q] to [q, h, f] as Chrome uses encoding index
|
|
@@ -7054,18 +7135,20 @@ const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetReso
|
|
|
7054
7135
|
* @param targetResolution the target resolution.
|
|
7055
7136
|
* @param currentWidth the current width of the track.
|
|
7056
7137
|
* @param currentHeight the current height of the track.
|
|
7138
|
+
* @param preferredBitrate the preferred bitrate for the track.
|
|
7057
7139
|
*/
|
|
7058
|
-
const getComputedMaxBitrate = (targetResolution, currentWidth, currentHeight) => {
|
|
7140
|
+
const getComputedMaxBitrate = (targetResolution, currentWidth, currentHeight, preferredBitrate) => {
|
|
7059
7141
|
// if the current resolution is lower than the target resolution,
|
|
7060
7142
|
// we want to proportionally reduce the target bitrate
|
|
7061
|
-
const { width: targetWidth, height: targetHeight } = targetResolution;
|
|
7143
|
+
const { width: targetWidth, height: targetHeight, bitrate: targetBitrate, } = targetResolution;
|
|
7144
|
+
const bitrate = preferredBitrate || targetBitrate;
|
|
7062
7145
|
if (currentWidth < targetWidth || currentHeight < targetHeight) {
|
|
7063
7146
|
const currentPixels = currentWidth * currentHeight;
|
|
7064
7147
|
const targetPixels = targetWidth * targetHeight;
|
|
7065
7148
|
const reductionFactor = currentPixels / targetPixels;
|
|
7066
|
-
return Math.round(
|
|
7149
|
+
return Math.round(bitrate * reductionFactor);
|
|
7067
7150
|
}
|
|
7068
|
-
return
|
|
7151
|
+
return bitrate;
|
|
7069
7152
|
};
|
|
7070
7153
|
/**
|
|
7071
7154
|
* Browsers have different simulcast constraints for different video resolutions.
|
|
@@ -8749,72 +8832,6 @@ const enableHighQualityAudio = (sdp, trackMid, maxBitrate = 510000) => {
|
|
|
8749
8832
|
return SDP.write(parsedSdp);
|
|
8750
8833
|
};
|
|
8751
8834
|
|
|
8752
|
-
const version = "1.6.3" ;
|
|
8753
|
-
const [major, minor, patch] = version.split('.');
|
|
8754
|
-
let sdkInfo = {
|
|
8755
|
-
type: SdkType.PLAIN_JAVASCRIPT,
|
|
8756
|
-
major,
|
|
8757
|
-
minor,
|
|
8758
|
-
patch,
|
|
8759
|
-
};
|
|
8760
|
-
let osInfo;
|
|
8761
|
-
let deviceInfo;
|
|
8762
|
-
let webRtcInfo;
|
|
8763
|
-
const setSdkInfo = (info) => {
|
|
8764
|
-
sdkInfo = info;
|
|
8765
|
-
};
|
|
8766
|
-
const getSdkInfo = () => {
|
|
8767
|
-
return sdkInfo;
|
|
8768
|
-
};
|
|
8769
|
-
const setOSInfo = (info) => {
|
|
8770
|
-
osInfo = info;
|
|
8771
|
-
};
|
|
8772
|
-
const getOSInfo = () => {
|
|
8773
|
-
return osInfo;
|
|
8774
|
-
};
|
|
8775
|
-
const setDeviceInfo = (info) => {
|
|
8776
|
-
deviceInfo = info;
|
|
8777
|
-
};
|
|
8778
|
-
const getDeviceInfo = () => {
|
|
8779
|
-
return deviceInfo;
|
|
8780
|
-
};
|
|
8781
|
-
const getWebRTCInfo = () => {
|
|
8782
|
-
return webRtcInfo;
|
|
8783
|
-
};
|
|
8784
|
-
const setWebRTCInfo = (info) => {
|
|
8785
|
-
webRtcInfo = info;
|
|
8786
|
-
};
|
|
8787
|
-
const getClientDetails = () => {
|
|
8788
|
-
if (isReactNative()) {
|
|
8789
|
-
// Since RN doesn't support web, sharing browser info is not required
|
|
8790
|
-
return {
|
|
8791
|
-
sdk: getSdkInfo(),
|
|
8792
|
-
os: getOSInfo(),
|
|
8793
|
-
device: getDeviceInfo(),
|
|
8794
|
-
};
|
|
8795
|
-
}
|
|
8796
|
-
const userAgent = new UAParser(navigator.userAgent);
|
|
8797
|
-
const { browser, os, device, cpu } = userAgent.getResult();
|
|
8798
|
-
return {
|
|
8799
|
-
sdk: getSdkInfo(),
|
|
8800
|
-
browser: {
|
|
8801
|
-
name: browser.name || navigator.userAgent,
|
|
8802
|
-
version: browser.version || '',
|
|
8803
|
-
},
|
|
8804
|
-
os: {
|
|
8805
|
-
name: os.name || '',
|
|
8806
|
-
version: os.version || '',
|
|
8807
|
-
architecture: cpu.architecture || '',
|
|
8808
|
-
},
|
|
8809
|
-
device: {
|
|
8810
|
-
name: [device.vendor, device.model, device.type]
|
|
8811
|
-
.filter(Boolean)
|
|
8812
|
-
.join(' '),
|
|
8813
|
-
version: '',
|
|
8814
|
-
},
|
|
8815
|
-
};
|
|
8816
|
-
};
|
|
8817
|
-
|
|
8818
8835
|
/**
|
|
8819
8836
|
* The `Publisher` is responsible for publishing/unpublishing media streams to/from the SFU
|
|
8820
8837
|
*
|
|
@@ -8943,24 +8960,12 @@ class Publisher {
|
|
|
8943
8960
|
const targetResolution = settings?.video
|
|
8944
8961
|
.target_resolution;
|
|
8945
8962
|
const screenShareBitrate = settings?.screensharing.target_resolution?.bitrate;
|
|
8963
|
+
const { preferredBitrate, preferredCodec, screenShareSettings } = opts;
|
|
8946
8964
|
const videoEncodings = trackType === TrackType.VIDEO
|
|
8947
|
-
? findOptimalVideoLayers(track, targetResolution)
|
|
8965
|
+
? findOptimalVideoLayers(track, targetResolution, preferredBitrate)
|
|
8948
8966
|
: trackType === TrackType.SCREEN_SHARE
|
|
8949
|
-
? findOptimalScreenSharingLayers(track,
|
|
8967
|
+
? findOptimalScreenSharingLayers(track, screenShareSettings, screenShareBitrate)
|
|
8950
8968
|
: undefined;
|
|
8951
|
-
let preferredCodec = opts.preferredCodec;
|
|
8952
|
-
if (!preferredCodec && trackType === TrackType.VIDEO && isReactNative()) {
|
|
8953
|
-
const osName = getOSInfo()?.name.toLowerCase();
|
|
8954
|
-
if (osName === 'ipados') {
|
|
8955
|
-
// in ipads it was noticed that if vp8 codec is used
|
|
8956
|
-
// then the bytes sent is 0 in the outbound-rtp
|
|
8957
|
-
// so we are forcing h264 codec for ipads
|
|
8958
|
-
preferredCodec = 'H264';
|
|
8959
|
-
}
|
|
8960
|
-
else if (osName === 'android') {
|
|
8961
|
-
preferredCodec = 'VP8';
|
|
8962
|
-
}
|
|
8963
|
-
}
|
|
8964
8969
|
// listen for 'ended' event on the track as it might be ended abruptly
|
|
8965
8970
|
// by an external factor as permission revokes, device disconnected, etc.
|
|
8966
8971
|
// keep in mind that `track.stop()` doesn't trigger this event.
|
|
@@ -8979,8 +8984,11 @@ class Publisher {
|
|
|
8979
8984
|
this.transceiverInitOrder.push(trackType);
|
|
8980
8985
|
this.transceiverRegistry[trackType] = transceiver;
|
|
8981
8986
|
this.publishOptionsPerTrackType.set(trackType, opts);
|
|
8987
|
+
const codec = isReactNative() && trackType === TrackType.VIDEO && !preferredCodec
|
|
8988
|
+
? getRNOptimalCodec()
|
|
8989
|
+
: preferredCodec;
|
|
8982
8990
|
const codecPreferences = 'setCodecPreferences' in transceiver
|
|
8983
|
-
? this.getCodecPreferences(trackType,
|
|
8991
|
+
? this.getCodecPreferences(trackType, codec)
|
|
8984
8992
|
: undefined;
|
|
8985
8993
|
if (codecPreferences) {
|
|
8986
8994
|
this.logger('info', `Setting ${TrackType[trackType]} codec preferences`, codecPreferences);
|
|
@@ -9294,7 +9302,7 @@ class Publisher {
|
|
|
9294
9302
|
const publishOpts = this.publishOptionsPerTrackType.get(trackType);
|
|
9295
9303
|
optimalLayers =
|
|
9296
9304
|
trackType === TrackType.VIDEO
|
|
9297
|
-
? findOptimalVideoLayers(track, targetResolution)
|
|
9305
|
+
? findOptimalVideoLayers(track, targetResolution, publishOpts?.preferredBitrate)
|
|
9298
9306
|
: trackType === TrackType.SCREEN_SHARE
|
|
9299
9307
|
? findOptimalScreenSharingLayers(track, publishOpts?.screenShareSettings)
|
|
9300
9308
|
: [];
|
|
@@ -12168,6 +12176,17 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
12168
12176
|
height: 720,
|
|
12169
12177
|
};
|
|
12170
12178
|
}
|
|
12179
|
+
/**
|
|
12180
|
+
* The publish options for the camera.
|
|
12181
|
+
*
|
|
12182
|
+
* @internal internal use only, not part of the public API.
|
|
12183
|
+
*/
|
|
12184
|
+
get publishOptions() {
|
|
12185
|
+
return {
|
|
12186
|
+
preferredCodec: this.preferredCodec,
|
|
12187
|
+
preferredBitrate: this.preferredBitrate,
|
|
12188
|
+
};
|
|
12189
|
+
}
|
|
12171
12190
|
/**
|
|
12172
12191
|
* Select the camera direction.
|
|
12173
12192
|
*
|
|
@@ -12224,6 +12243,15 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
12224
12243
|
setPreferredCodec(codec) {
|
|
12225
12244
|
this.preferredCodec = codec;
|
|
12226
12245
|
}
|
|
12246
|
+
/**
|
|
12247
|
+
* Sets the preferred bitrate for encoding the video.
|
|
12248
|
+
*
|
|
12249
|
+
* @internal internal use only, not part of the public API.
|
|
12250
|
+
* @param bitrate the bitrate to use for encoding the video.
|
|
12251
|
+
*/
|
|
12252
|
+
setPreferredBitrate(bitrate) {
|
|
12253
|
+
this.preferredBitrate = bitrate;
|
|
12254
|
+
}
|
|
12227
12255
|
getDevices() {
|
|
12228
12256
|
return getVideoDevices();
|
|
12229
12257
|
}
|
|
@@ -12239,9 +12267,7 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
12239
12267
|
return getVideoStream(constraints);
|
|
12240
12268
|
}
|
|
12241
12269
|
publishStream(stream) {
|
|
12242
|
-
return this.call.publishVideoStream(stream,
|
|
12243
|
-
preferredCodec: this.preferredCodec,
|
|
12244
|
-
});
|
|
12270
|
+
return this.call.publishVideoStream(stream, this.publishOptions);
|
|
12245
12271
|
}
|
|
12246
12272
|
stopPublishStream(stopTracks) {
|
|
12247
12273
|
return this.call.stopPublish(TrackType.VIDEO, stopTracks);
|
|
@@ -13634,9 +13660,7 @@ class Call {
|
|
|
13634
13660
|
case TrackType.VIDEO:
|
|
13635
13661
|
const videoStream = this.camera.state.mediaStream;
|
|
13636
13662
|
if (videoStream) {
|
|
13637
|
-
await this.publishVideoStream(videoStream,
|
|
13638
|
-
preferredCodec: this.camera.preferredCodec,
|
|
13639
|
-
});
|
|
13663
|
+
await this.publishVideoStream(videoStream, this.camera.publishOptions);
|
|
13640
13664
|
}
|
|
13641
13665
|
break;
|
|
13642
13666
|
case TrackType.SCREEN_SHARE:
|
|
@@ -14312,9 +14336,7 @@ class Call {
|
|
|
14312
14336
|
if (this.camera.enabled &&
|
|
14313
14337
|
this.camera.state.mediaStream &&
|
|
14314
14338
|
!this.publisher?.isPublishing(TrackType.VIDEO)) {
|
|
14315
|
-
await this.publishVideoStream(this.camera.state.mediaStream,
|
|
14316
|
-
preferredCodec: this.camera.preferredCodec,
|
|
14317
|
-
});
|
|
14339
|
+
await this.publishVideoStream(this.camera.state.mediaStream, this.camera.publishOptions);
|
|
14318
14340
|
}
|
|
14319
14341
|
// Start camera if backend config specifies, and there is no local setting
|
|
14320
14342
|
if (this.camera.state.status === undefined &&
|
|
@@ -16091,7 +16113,7 @@ class StreamClient {
|
|
|
16091
16113
|
});
|
|
16092
16114
|
};
|
|
16093
16115
|
this.getUserAgent = () => {
|
|
16094
|
-
const version = "1.6.
|
|
16116
|
+
const version = "1.6.4" ;
|
|
16095
16117
|
return (this.userAgent ||
|
|
16096
16118
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
16097
16119
|
};
|