@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/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(targetResolution.bitrate * reductionFactor);
7169
+ return Math.round(bitrate * reductionFactor);
7087
7170
  }
7088
- return targetResolution.bitrate;
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, opts.screenShareSettings, screenShareBitrate)
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, preferredCodec)
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.3" ;
16136
+ const version = "1.6.4" ;
16115
16137
  return (this.userAgent ||
16116
16138
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
16117
16139
  };