@stream-io/video-client 1.31.0 → 1.32.0

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
@@ -2951,6 +2951,12 @@ class JoinRequest$Type extends runtime.MessageType {
2951
2951
  super('stream.video.sfu.event.JoinRequest', [
2952
2952
  { no: 1, name: 'token', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
2953
2953
  { no: 2, name: 'session_id', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
2954
+ {
2955
+ no: 13,
2956
+ name: 'unified_session_id',
2957
+ kind: 'scalar',
2958
+ T: 9 /*ScalarType.STRING*/,
2959
+ },
2954
2960
  {
2955
2961
  no: 3,
2956
2962
  name: 'subscriber_sdp',
@@ -5760,7 +5766,7 @@ const getSdkVersion = (sdk) => {
5760
5766
  return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
5761
5767
  };
5762
5768
 
5763
- const version = "1.31.0";
5769
+ const version = "1.32.0";
5764
5770
  const [major, minor, patch] = version.split('.');
5765
5771
  let sdkInfo = {
5766
5772
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -11871,7 +11877,6 @@ class Call {
11871
11877
  if ([exports.CallingState.JOINED, exports.CallingState.JOINING].includes(callingState)) {
11872
11878
  throw new Error(`Illegal State: call.join() shall be called only once`);
11873
11879
  }
11874
- this.state.setCallingState(exports.CallingState.JOINING);
11875
11880
  // we will count the number of join failures per SFU.
11876
11881
  // once the number of failures reaches 2, we will piggyback on the `migrating_from`
11877
11882
  // field to force the coordinator to provide us another SFU
@@ -11900,8 +11905,6 @@ class Call {
11900
11905
  joinData.migrating_from = sfuId;
11901
11906
  }
11902
11907
  if (attempt === maxJoinRetries - 1) {
11903
- // restore the previous call state if the join-flow fails
11904
- this.state.setCallingState(callingState);
11905
11908
  throw err;
11906
11909
  }
11907
11910
  }
@@ -11961,6 +11964,7 @@ class Call {
11961
11964
  })
11962
11965
  : previousSfuClient;
11963
11966
  this.sfuClient = sfuClient;
11967
+ this.unifiedSessionId ?? (this.unifiedSessionId = sfuClient.sessionId);
11964
11968
  this.dynascaleManager.setSfuClient(sfuClient);
11965
11969
  const clientDetails = await getClientDetails();
11966
11970
  // we don't need to send JoinRequest if we are re-using an existing healthy SFU client
@@ -11984,6 +11988,7 @@ class Call {
11984
11988
  : [];
11985
11989
  try {
11986
11990
  const { callState, fastReconnectDeadlineSeconds, publishOptions } = await sfuClient.join({
11991
+ unifiedSessionId: this.unifiedSessionId,
11987
11992
  subscriberSdp,
11988
11993
  publisherSdp,
11989
11994
  clientDetails,
@@ -12029,6 +12034,7 @@ class Call {
12029
12034
  statsOptions,
12030
12035
  publishOptions: this.currentPublishOptions || [],
12031
12036
  closePreviousInstances: !performingMigration,
12037
+ unifiedSessionId: this.unifiedSessionId,
12032
12038
  });
12033
12039
  }
12034
12040
  // make sure we only track connection timing if we are not calling this method as part of a reconnection flow
@@ -12155,7 +12161,7 @@ class Call {
12155
12161
  * @internal
12156
12162
  */
12157
12163
  this.initPublisherAndSubscriber = (opts) => {
12158
- const { sfuClient, connectionConfig, clientDetails, statsOptions, publishOptions, closePreviousInstances, } = opts;
12164
+ const { sfuClient, connectionConfig, clientDetails, statsOptions, publishOptions, closePreviousInstances, unifiedSessionId, } = opts;
12159
12165
  const { enable_rtc_stats: enableTracing } = statsOptions;
12160
12166
  if (closePreviousInstances && this.subscriber) {
12161
12167
  this.subscriber.dispose();
@@ -12210,7 +12216,6 @@ class Call {
12210
12216
  this.tracer.setEnabled(enableTracing);
12211
12217
  this.sfuStatsReporter?.stop();
12212
12218
  if (statsOptions?.reporting_interval_ms > 0) {
12213
- this.unifiedSessionId ?? (this.unifiedSessionId = sfuClient.sessionId);
12214
12219
  this.sfuStatsReporter = new SfuStatsReporter(sfuClient, {
12215
12220
  clientDetails,
12216
12221
  options: statsOptions,
@@ -12220,7 +12225,7 @@ class Call {
12220
12225
  camera: this.camera,
12221
12226
  state: this.state,
12222
12227
  tracer: this.tracer,
12223
- unifiedSessionId: this.unifiedSessionId,
12228
+ unifiedSessionId,
12224
12229
  });
12225
12230
  this.sfuStatsReporter.start();
12226
12231
  }
@@ -14540,7 +14545,7 @@ class StreamClient {
14540
14545
  this.getUserAgent = () => {
14541
14546
  if (!this.cachedUserAgent) {
14542
14547
  const { clientAppIdentifier = {} } = this.options;
14543
- const { sdkName = 'js', sdkVersion = "1.31.0", ...extras } = clientAppIdentifier;
14548
+ const { sdkName = 'js', sdkVersion = "1.32.0", ...extras } = clientAppIdentifier;
14544
14549
  this.cachedUserAgent = [
14545
14550
  `stream-video-${sdkName}-v${sdkVersion}`,
14546
14551
  ...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
@@ -14729,6 +14734,7 @@ class StreamVideoClient {
14729
14734
  this.effectsRegistered = false;
14730
14735
  this.eventHandlersToUnregister = [];
14731
14736
  this.connectionConcurrencyTag = Symbol('connectionConcurrencyTag');
14737
+ this.rejectCallWhenBusy = false;
14732
14738
  this.registerClientInstance = (apiKey, user) => {
14733
14739
  const instanceKey = getInstanceKey(apiKey, user);
14734
14740
  if (StreamVideoClient._instances.has(instanceKey)) {
@@ -14774,7 +14780,16 @@ class StreamVideoClient {
14774
14780
  let call = this.writeableStateStore.findCall(e.call.type, e.call.id);
14775
14781
  if (call) {
14776
14782
  if (ringing) {
14777
- await call.updateFromRingingEvent(e);
14783
+ if (this.shouldRejectCall(call.cid)) {
14784
+ this.logger('info', `Leaving call with busy reject reason ${call.cid} because user is busy`);
14785
+ // remove the instance from the state store
14786
+ await call.leave();
14787
+ // explicitly reject the call with busy reason as calling state was not ringing before and leave would not call it therefore
14788
+ await call.reject('busy');
14789
+ }
14790
+ else {
14791
+ await call.updateFromRingingEvent(e);
14792
+ }
14778
14793
  }
14779
14794
  else {
14780
14795
  call.state.updateFromCallResponse(e.call);
@@ -14789,11 +14804,19 @@ class StreamVideoClient {
14789
14804
  clientStore: this.writeableStateStore,
14790
14805
  ringing,
14791
14806
  });
14792
- call.state.updateFromCallResponse(e.call);
14793
14807
  if (ringing) {
14794
- await call.get();
14808
+ if (this.shouldRejectCall(call.cid)) {
14809
+ this.logger('info', `Rejecting call ${call.cid} because user is busy`);
14810
+ // call is not in the state store yet, so just reject api is enough
14811
+ await call.reject('busy');
14812
+ }
14813
+ else {
14814
+ await call.updateFromRingingEvent(e);
14815
+ await call.get();
14816
+ }
14795
14817
  }
14796
14818
  else {
14819
+ call.state.updateFromCallResponse(e.call);
14797
14820
  this.writeableStateStore.registerCall(call);
14798
14821
  this.logger('info', `New call created and registered: ${call.cid}`);
14799
14822
  }
@@ -15060,6 +15083,16 @@ class StreamVideoClient {
15060
15083
  this.connectAnonymousUser = async (user, tokenOrProvider) => {
15061
15084
  return withoutConcurrency(this.connectionConcurrencyTag, () => this.streamClient.connectAnonymousUser(user, tokenOrProvider));
15062
15085
  };
15086
+ this.shouldRejectCall = (currentCallId) => {
15087
+ if (!this.rejectCallWhenBusy)
15088
+ return false;
15089
+ const hasOngoingRingingCall = this.state.calls.some((c) => c.cid !== currentCallId &&
15090
+ c.ringing &&
15091
+ c.state.callingState !== exports.CallingState.IDLE &&
15092
+ c.state.callingState !== exports.CallingState.LEFT &&
15093
+ c.state.callingState !== exports.CallingState.RECONNECTING_FAILED);
15094
+ return hasOngoingRingingCall;
15095
+ };
15063
15096
  const apiKey = typeof apiKeyOrArgs === 'string' ? apiKeyOrArgs : apiKeyOrArgs.apiKey;
15064
15097
  const clientOptions = typeof apiKeyOrArgs === 'string' ? opts : apiKeyOrArgs.options;
15065
15098
  if (clientOptions?.enableTimerWorker)
@@ -15067,6 +15100,7 @@ class StreamVideoClient {
15067
15100
  const rootLogger = clientOptions?.logger || logToConsole;
15068
15101
  setLogger(rootLogger, clientOptions?.logLevel || 'warn');
15069
15102
  this.logger = getLogger(['client']);
15103
+ this.rejectCallWhenBusy = clientOptions?.rejectCallWhenBusy ?? false;
15070
15104
  this.streamClient = createCoordinatorClient(apiKey, clientOptions);
15071
15105
  this.writeableStateStore = new StreamVideoWriteableStateStore();
15072
15106
  this.readOnlyStateStore = new StreamVideoReadOnlyStateStore(this.writeableStateStore);