@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.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(targetResolution.bitrate * reductionFactor);
7149
+ return Math.round(bitrate * reductionFactor);
7067
7150
  }
7068
- return targetResolution.bitrate;
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, opts.screenShareSettings, screenShareBitrate)
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, preferredCodec)
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.3" ;
16116
+ const version = "1.6.4" ;
16095
16117
  return (this.userAgent ||
16096
16118
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
16097
16119
  };