@stream-io/video-client 1.0.2 → 1.0.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 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.0.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.0.3...@stream-io/video-client-1.0.4) (2024-05-14)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * don't create publisher PC for anonymous users ([#1353](https://github.com/GetStream/stream-video-js/issues/1353)) ([7331767](https://github.com/GetStream/stream-video-js/commit/7331767bd9254082517b1f36895796032b7af149))
11
+
12
+ ### [1.0.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.0.2...@stream-io/video-client-1.0.3) (2024-05-13)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * improve error handling across the SDK ([#1350](https://github.com/GetStream/stream-video-js/issues/1350)) ([ac0ae3b](https://github.com/GetStream/stream-video-js/commit/ac0ae3b7d5da91152d0f41a203b73e6c99c42ff9))
18
+
5
19
  ### [1.0.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.0.1...@stream-io/video-client-1.0.2) (2024-05-13)
6
20
 
7
21
 
@@ -8399,15 +8399,19 @@ class Publisher {
8399
8399
  return getPreferredCodecs('audio', preferredCodec ?? defaultAudioCodec, codecToRemove);
8400
8400
  }
8401
8401
  };
8402
- this.onIceCandidate = async (e) => {
8402
+ this.onIceCandidate = (e) => {
8403
8403
  const { candidate } = e;
8404
8404
  if (!candidate) {
8405
8405
  logger$3('debug', 'null ice candidate');
8406
8406
  return;
8407
8407
  }
8408
- await this.sfuClient.iceTrickle({
8408
+ this.sfuClient
8409
+ .iceTrickle({
8409
8410
  iceCandidate: getIceCandidate(candidate),
8410
8411
  peerType: PeerType.PUBLISHER_UNSPECIFIED,
8412
+ })
8413
+ .catch((err) => {
8414
+ logger$3('warn', `ICETrickle failed`, err);
8411
8415
  });
8412
8416
  };
8413
8417
  /**
@@ -8448,8 +8452,8 @@ class Publisher {
8448
8452
  }
8449
8453
  await this.negotiate({ iceRestart: true });
8450
8454
  };
8451
- this.onNegotiationNeeded = async () => {
8452
- await this.negotiate();
8455
+ this.onNegotiationNeeded = () => {
8456
+ this.negotiate().catch((err) => logger$3('warn', `Negotiation failed.`, err));
8453
8457
  };
8454
8458
  /**
8455
8459
  * Initiates a new offer/answer exchange with the currently connected SFU.
@@ -8639,10 +8643,12 @@ class Publisher {
8639
8643
  this.isDtxEnabled = isDtxEnabled;
8640
8644
  this.isRedEnabled = isRedEnabled;
8641
8645
  this.iceRestartDelay = iceRestartDelay;
8642
- this.unsubscribeOnIceRestart = dispatcher.on('iceRestart', async (iceRestart) => {
8646
+ this.unsubscribeOnIceRestart = dispatcher.on('iceRestart', (iceRestart) => {
8643
8647
  if (iceRestart.peerType !== PeerType.PUBLISHER_UNSPECIFIED)
8644
8648
  return;
8645
- await this.restartIce();
8649
+ this.restartIce().catch((err) => {
8650
+ logger$3('warn', `ICERestart failed`, err);
8651
+ });
8646
8652
  });
8647
8653
  }
8648
8654
  }
@@ -8836,15 +8842,19 @@ class Subscriber {
8836
8842
  [streamKindProp]: primaryStream,
8837
8843
  });
8838
8844
  };
8839
- this.onIceCandidate = async (e) => {
8845
+ this.onIceCandidate = (e) => {
8840
8846
  const { candidate } = e;
8841
8847
  if (!candidate) {
8842
8848
  logger$2('debug', 'null ice candidate');
8843
8849
  return;
8844
8850
  }
8845
- await this.sfuClient.iceTrickle({
8851
+ this.sfuClient
8852
+ .iceTrickle({
8846
8853
  iceCandidate: getIceCandidate(candidate),
8847
8854
  peerType: PeerType.SUBSCRIBER,
8855
+ })
8856
+ .catch((err) => {
8857
+ logger$2('warn', `ICETrickle failed`, err);
8848
8858
  });
8849
8859
  };
8850
8860
  this.negotiate = async (subscriberOffer) => {
@@ -8916,13 +8926,17 @@ class Subscriber {
8916
8926
  this.state = state;
8917
8927
  this.iceRestartDelay = iceRestartDelay;
8918
8928
  this.pc = this.createPeerConnection(connectionConfig);
8919
- this.unregisterOnSubscriberOffer = dispatcher.on('subscriberOffer', async (subscriberOffer) => {
8920
- await this.negotiate(subscriberOffer);
8929
+ this.unregisterOnSubscriberOffer = dispatcher.on('subscriberOffer', (subscriberOffer) => {
8930
+ this.negotiate(subscriberOffer).catch((err) => {
8931
+ logger$2('warn', `Negotiation failed.`, err);
8932
+ });
8921
8933
  });
8922
- this.unregisterOnIceRestart = dispatcher.on('iceRestart', async (iceRestart) => {
8934
+ this.unregisterOnIceRestart = dispatcher.on('iceRestart', (iceRestart) => {
8923
8935
  if (iceRestart.peerType !== PeerType.SUBSCRIBER)
8924
8936
  return;
8925
- await this.restartIce();
8937
+ this.restartIce().catch((err) => {
8938
+ logger$2('warn', `ICERestart failed`, err);
8939
+ });
8926
8940
  });
8927
8941
  }
8928
8942
  }
@@ -9774,25 +9788,29 @@ const flatten = (report) => {
9774
9788
  };
9775
9789
  const getSdkSignature = (clientDetails) => {
9776
9790
  const { sdk, ...platform } = clientDetails;
9777
- const sdkName = sdk && sdk.type === SdkType.REACT
9778
- ? 'stream-react'
9779
- : sdk && sdk.type === SdkType.REACT_NATIVE
9780
- ? 'stream-react-native'
9781
- : 'stream-js';
9782
- const sdkVersion = sdk
9783
- ? `${sdk.major}.${sdk.minor}.${sdk.patch}`
9784
- : '0.0.0-development';
9791
+ const sdkName = getSdkName(sdk);
9792
+ const sdkVersion = getSdkVersion(sdk);
9785
9793
  return {
9786
9794
  sdkName,
9787
9795
  sdkVersion,
9788
9796
  ...platform,
9789
9797
  };
9790
9798
  };
9799
+ const getSdkName = (sdk) => {
9800
+ return sdk && sdk.type === SdkType.REACT
9801
+ ? 'stream-react'
9802
+ : sdk && sdk.type === SdkType.REACT_NATIVE
9803
+ ? 'stream-react-native'
9804
+ : 'stream-js';
9805
+ };
9806
+ const getSdkVersion = (sdk) => {
9807
+ return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
9808
+ };
9791
9809
 
9792
9810
  /**
9793
9811
  * Creates a new StatsReporter instance that collects metrics about the ongoing call and reports them to the state store
9794
9812
  */
9795
- const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs = 2000, }) => {
9813
+ const createStatsReporter = ({ subscriber, publisher, state, datacenter, pollingIntervalInMs = 2000, }) => {
9796
9814
  const logger = getLogger(['stats']);
9797
9815
  const getRawStatsForTrack = async (kind, selector) => {
9798
9816
  if (kind === 'subscriber' && subscriber) {
@@ -9802,12 +9820,13 @@ const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs
9802
9820
  return publisher.getStats(selector);
9803
9821
  }
9804
9822
  else {
9805
- logger('warn', `Can't retrieve RTC stats for ${kind}`);
9806
9823
  return undefined;
9807
9824
  }
9808
9825
  };
9809
9826
  const getStatsForStream = async (kind, mediaStream) => {
9810
9827
  const pc = kind === 'subscriber' ? subscriber : publisher;
9828
+ if (!pc)
9829
+ return [];
9811
9830
  const statsForStream = [];
9812
9831
  for (let track of mediaStream.getTracks()) {
9813
9832
  const report = await pc.getStats(track);
@@ -9853,7 +9872,7 @@ const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs
9853
9872
  });
9854
9873
  }
9855
9874
  catch (e) {
9856
- logger('error', `Failed to collect stats for ${kind} if ${participant.userId}`, e);
9875
+ logger('error', `Failed to collect stats for ${kind} of ${participant.userId}`, e);
9857
9876
  }
9858
9877
  }
9859
9878
  }
@@ -9866,19 +9885,21 @@ const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs
9866
9885
  }))
9867
9886
  .then(aggregate),
9868
9887
  publisher
9869
- .getStats()
9870
- .then((report) => transform(report, {
9871
- kind: 'publisher',
9872
- trackKind: 'video',
9873
- }))
9874
- .then(aggregate),
9888
+ ? publisher
9889
+ .getStats()
9890
+ .then((report) => transform(report, {
9891
+ kind: 'publisher',
9892
+ trackKind: 'video',
9893
+ }))
9894
+ .then(aggregate)
9895
+ : getEmptyStats(),
9875
9896
  ]);
9876
9897
  const [subscriberRawStats, publisherRawStats] = await Promise.all([
9877
9898
  getRawStatsForTrack('subscriber'),
9878
- getRawStatsForTrack('publisher'),
9899
+ publisher ? getRawStatsForTrack('publisher') : undefined,
9879
9900
  ]);
9880
9901
  state.setCallStatsReport({
9881
- datacenter: publisher.sfuClient.edgeName,
9902
+ datacenter,
9882
9903
  publisherStats,
9883
9904
  subscriberStats,
9884
9905
  subscriberRawStats,
@@ -9955,14 +9976,9 @@ const transform = (report, opts) => {
9955
9976
  timestamp: Date.now(),
9956
9977
  };
9957
9978
  };
9958
- /**
9959
- * Aggregates generic stats.
9960
- *
9961
- * @param stats the stats to aggregate.
9962
- */
9963
- const aggregate = (stats) => {
9964
- const aggregatedStats = {
9965
- rawReport: stats,
9979
+ const getEmptyStats = (stats) => {
9980
+ return {
9981
+ rawReport: stats ?? { streams: [], timestamp: Date.now() },
9966
9982
  totalBytesSent: 0,
9967
9983
  totalBytesReceived: 0,
9968
9984
  averageJitterInMs: 0,
@@ -9973,6 +9989,14 @@ const aggregate = (stats) => {
9973
9989
  highestFramesPerSecond: 0,
9974
9990
  timestamp: Date.now(),
9975
9991
  };
9992
+ };
9993
+ /**
9994
+ * Aggregates generic stats.
9995
+ *
9996
+ * @param stats the stats to aggregate.
9997
+ */
9998
+ const aggregate = (stats) => {
9999
+ const aggregatedStats = getEmptyStats(stats);
9976
10000
  let maxArea = -1;
9977
10001
  const area = (w, h) => w * h;
9978
10002
  const qualityLimitationReasons = new Set();
@@ -10016,7 +10040,7 @@ class SfuStatsReporter {
10016
10040
  this.run = async () => {
10017
10041
  const [subscriberStats, publisherStats] = await Promise.all([
10018
10042
  this.subscriber.getStats().then(flatten).then(JSON.stringify),
10019
- this.publisher.getStats().then(flatten).then(JSON.stringify),
10043
+ this.publisher?.getStats().then(flatten).then(JSON.stringify) ?? '[]',
10020
10044
  ]);
10021
10045
  await this.sfuClient.sendStats({
10022
10046
  sdk: this.sdkName,
@@ -10045,15 +10069,8 @@ class SfuStatsReporter {
10045
10069
  this.publisher = publisher;
10046
10070
  const webRTCInfo = getWebRTCInfo();
10047
10071
  const { sdk, browser } = clientDetails;
10048
- this.sdkName =
10049
- sdk && sdk.type === SdkType.REACT
10050
- ? 'stream-react'
10051
- : sdk && sdk.type === SdkType.REACT_NATIVE
10052
- ? 'stream-react-native'
10053
- : 'stream-js';
10054
- this.sdkVersion = sdk
10055
- ? `${sdk.major}.${sdk.minor}.${sdk.patch}`
10056
- : '0.0.0-development';
10072
+ this.sdkName = getSdkName(sdk);
10073
+ this.sdkVersion = getSdkVersion(sdk);
10057
10074
  // The WebRTC version if passed from the SDK, it is taken else the browser info is sent.
10058
10075
  this.webRTCVersion =
10059
10076
  webRTCInfo?.version ||
@@ -12609,7 +12626,10 @@ class Call {
12609
12626
  connectionConfig,
12610
12627
  });
12611
12628
  }
12612
- if (!this.publisher) {
12629
+ // anonymous users can't publish anything hence, there is no need
12630
+ // to create Publisher Peer Connection for them
12631
+ const isAnonymous = this.streamClient.user?.type === 'anonymous';
12632
+ if (!this.publisher && !isAnonymous) {
12613
12633
  const audioSettings = this.state.settings?.audio;
12614
12634
  const isDtxEnabled = !!audioSettings?.opus_dtx_enabled;
12615
12635
  const isRedEnabled = !!audioSettings?.redundant_coding_enabled;
@@ -12627,6 +12647,7 @@ class Call {
12627
12647
  subscriber: this.subscriber,
12628
12648
  publisher: this.publisher,
12629
12649
  state: this.state,
12650
+ datacenter: this.sfuClient.edgeName,
12630
12651
  });
12631
12652
  }
12632
12653
  const clientDetails = getClientDetails();
@@ -12672,15 +12693,18 @@ class Call {
12672
12693
  }
12673
12694
  if (isMigrating) {
12674
12695
  await this.subscriber.migrateTo(sfuClient, connectionConfig);
12675
- await this.publisher.migrateTo(sfuClient, connectionConfig);
12696
+ await this.publisher?.migrateTo(sfuClient, connectionConfig);
12676
12697
  }
12677
12698
  else if (isReconnecting) {
12678
12699
  if (reconnected) {
12679
12700
  // update the SFU client instance on the subscriber and publisher
12680
12701
  this.subscriber.setSfuClient(sfuClient);
12681
- this.publisher.setSfuClient(sfuClient);
12682
- // and perform a full ICE restart on the publisher
12683
- await this.publisher.restartIce();
12702
+ // publisher might not be there (anonymous users)
12703
+ if (this.publisher) {
12704
+ this.publisher.setSfuClient(sfuClient);
12705
+ // and perform a full ICE restart on the publisher
12706
+ await this.publisher.restartIce();
12707
+ }
12684
12708
  }
12685
12709
  else if (previousSfuClient?.isFastReconnecting) {
12686
12710
  // reconnection wasn't possible, so we need to do a full rejoin
@@ -13488,7 +13512,9 @@ class Call {
13488
13512
  });
13489
13513
  this.leaveCallHooks.add(registerEventHandlers(this, this.state, this.dispatcher));
13490
13514
  this.registerEffects();
13491
- this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$1((v) => v.data)), (subscriptions) => this.sfuClient?.updateSubscriptions(subscriptions)));
13515
+ this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$1((v) => v.data)), (subscriptions) => this.sfuClient?.updateSubscriptions(subscriptions).catch((err) => {
13516
+ this.logger('debug', `Failed to update track subscriptions`, err);
13517
+ })));
13492
13518
  this.camera = new CameraManager(this);
13493
13519
  this.microphone = new MicrophoneManager(this);
13494
13520
  this.speaker = new SpeakerManager(this);
@@ -15177,7 +15203,7 @@ class StreamClient {
15177
15203
  });
15178
15204
  };
15179
15205
  this.getUserAgent = () => {
15180
- const version = "1.0.2" ;
15206
+ const version = "1.0.4" ;
15181
15207
  return (this.userAgent ||
15182
15208
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
15183
15209
  };