@stream-io/video-client 1.44.1-beta.1 → 1.44.1-beta.2

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.
@@ -6231,7 +6231,7 @@ const getSdkVersion = (sdk) => {
6231
6231
  return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
6232
6232
  };
6233
6233
 
6234
- const version = "1.44.1-beta.1";
6234
+ const version = "1.44.1-beta.2";
6235
6235
  const [major, minor, patch] = version.split('.');
6236
6236
  let sdkInfo = {
6237
6237
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -8924,6 +8924,7 @@ const watchCallRejected = (call) => {
8924
8924
  else {
8925
8925
  if (rejectedBy[eventCall.created_by.id]) {
8926
8926
  call.logger.info('call creator rejected, leaving call');
8927
+ globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8927
8928
  await call.leave({ message: 'ring: creator rejected' });
8928
8929
  }
8929
8930
  }
@@ -8937,6 +8938,7 @@ const watchCallEnded = (call) => {
8937
8938
  const { callingState } = call.state;
8938
8939
  if (callingState !== CallingState.IDLE &&
8939
8940
  callingState !== CallingState.LEFT) {
8941
+ globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8940
8942
  call
8941
8943
  .leave({ message: 'call.ended event received', reject: false })
8942
8944
  .catch((err) => {
@@ -8965,6 +8967,7 @@ const watchSfuCallEnded = (call) => {
8965
8967
  // update the call state to reflect the call has ended.
8966
8968
  call.state.setEndedAt(new Date());
8967
8969
  const reason = CallEndedReason[e.reason];
8970
+ globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8968
8971
  await call.leave({ message: `callEnded received: ${reason}` });
8969
8972
  }
8970
8973
  catch (err) {
@@ -12479,6 +12482,7 @@ class SpeakerManager {
12479
12482
  this.defaultDevice = defaultDevice;
12480
12483
  globalThis.streamRNVideoSDK?.callManager.setup({
12481
12484
  defaultDevice,
12485
+ isRingingTypeCall: this.call.ringing,
12482
12486
  });
12483
12487
  }
12484
12488
  }
@@ -12678,6 +12682,7 @@ class Call {
12678
12682
  const currentUserId = this.currentUserId;
12679
12683
  if (currentUserId && blockedUserIds.includes(currentUserId)) {
12680
12684
  this.logger.info('Leaving call because of being blocked');
12685
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'restricted');
12681
12686
  await this.leave({ message: 'user blocked' }).catch((err) => {
12682
12687
  this.logger.error('Error leaving call after being blocked', err);
12683
12688
  });
@@ -12714,6 +12719,7 @@ class Call {
12714
12719
  const isAcceptedElsewhere = isAcceptedByMe && this.state.callingState === CallingState.RINGING;
12715
12720
  if ((isAcceptedElsewhere || isRejectedByMe) &&
12716
12721
  !hasPending(this.joinLeaveConcurrencyTag)) {
12722
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, isAcceptedElsewhere ? 'answeredElsewhere' : 'rejected');
12717
12723
  this.leave().catch(() => {
12718
12724
  this.logger.error('Could not leave a call that was accepted or rejected elsewhere');
12719
12725
  });
@@ -12863,17 +12869,28 @@ class Call {
12863
12869
  }
12864
12870
  if (callingState === CallingState.RINGING && reject !== false) {
12865
12871
  if (reject) {
12866
- await this.reject(reason ?? 'decline');
12872
+ const reasonToEndCallReason = {
12873
+ timeout: 'missed',
12874
+ cancel: 'canceled',
12875
+ busy: 'busy',
12876
+ decline: 'rejected',
12877
+ };
12878
+ const rejectReason = reason ?? 'decline';
12879
+ const endCallReason = reasonToEndCallReason[rejectReason] ?? 'rejected';
12880
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, endCallReason);
12881
+ await this.reject(rejectReason);
12867
12882
  }
12868
12883
  else {
12869
12884
  // if reject was undefined, we still have to cancel the call automatically
12870
12885
  // when I am the creator and everyone else left the call
12871
12886
  const hasOtherParticipants = this.state.remoteParticipants.length > 0;
12872
12887
  if (this.isCreatedByMe && !hasOtherParticipants) {
12888
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'canceled');
12873
12889
  await this.reject('cancel');
12874
12890
  }
12875
12891
  }
12876
12892
  }
12893
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this);
12877
12894
  this.statsReporter?.stop();
12878
12895
  this.statsReporter = undefined;
12879
12896
  const leaveReason = message ?? reason ?? 'user is leaving the call';
@@ -12900,7 +12917,9 @@ class Call {
12900
12917
  this.ringingSubject.next(false);
12901
12918
  this.cancelAutoDrop();
12902
12919
  this.clientStore.unregisterCall(this);
12903
- globalThis.streamRNVideoSDK?.callManager.stop();
12920
+ globalThis.streamRNVideoSDK?.callManager.stop({
12921
+ isRingingTypeCall: this.ringing,
12922
+ });
12904
12923
  this.camera.dispose();
12905
12924
  this.microphone.dispose();
12906
12925
  this.screenShare.dispose();
@@ -12944,8 +12963,7 @@ class Call {
12944
12963
  // const calls = useCalls().filter((c) => c.ringing);
12945
12964
  const calls = this.clientStore.calls.filter((c) => c.cid !== this.cid);
12946
12965
  this.clientStore.setCalls([this, ...calls]);
12947
- const skipSpeakerApply = isReactNative() && true;
12948
- await this.applyDeviceConfig(settings, false, skipSpeakerApply);
12966
+ await this.applyDeviceConfig(settings, false);
12949
12967
  };
12950
12968
  /**
12951
12969
  * Loads the information about the call.
@@ -12968,10 +12986,7 @@ class Call {
12968
12986
  this.watching = true;
12969
12987
  this.clientStore.registerOrUpdateCall(this);
12970
12988
  }
12971
- const skipSpeakerApply = isReactNative()
12972
- ? (params?.ring ?? this.ringing)
12973
- : false;
12974
- await this.applyDeviceConfig(response.call.settings, false, skipSpeakerApply);
12989
+ await this.applyDeviceConfig(response.call.settings, false);
12975
12990
  return response;
12976
12991
  };
12977
12992
  /**
@@ -12992,10 +13007,7 @@ class Call {
12992
13007
  this.watching = true;
12993
13008
  this.clientStore.registerOrUpdateCall(this);
12994
13009
  }
12995
- const skipSpeakerApply = isReactNative()
12996
- ? (data?.ring ?? this.ringing)
12997
- : false;
12998
- await this.applyDeviceConfig(response.call.settings, false, skipSpeakerApply);
13010
+ await this.applyDeviceConfig(response.call.settings, false);
12999
13011
  return response;
13000
13012
  };
13001
13013
  /**
@@ -13060,11 +13072,19 @@ class Call {
13060
13072
  * @returns a promise which resolves once the call join-flow has finished.
13061
13073
  */
13062
13074
  this.join = async ({ maxJoinRetries = 3, joinResponseTimeout, rpcRequestTimeout, ...data } = {}) => {
13063
- await this.setup();
13064
13075
  const callingState = this.state.callingState;
13065
13076
  if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
13066
13077
  throw new Error(`Illegal State: call.join() shall be called only once`);
13067
13078
  }
13079
+ if (data?.ring) {
13080
+ this.ringingSubject.next(true);
13081
+ }
13082
+ const callingX = globalThis.streamRNVideoSDK?.callingX;
13083
+ if (callingX) {
13084
+ // for Android/iOS, we need to start the call in the callingx library as soon as possible
13085
+ await callingX.startCall(this, this.clientStore.calls);
13086
+ }
13087
+ await this.setup();
13068
13088
  this.joinResponseTimeout = joinResponseTimeout;
13069
13089
  this.rpcRequestTimeout = rpcRequestTimeout;
13070
13090
  // we will count the number of join failures per SFU.
@@ -13073,38 +13093,44 @@ class Call {
13073
13093
  const sfuJoinFailures = new Map();
13074
13094
  const joinData = data;
13075
13095
  maxJoinRetries = Math.max(maxJoinRetries, 1);
13076
- for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13077
- try {
13078
- this.logger.trace(`Joining call (${attempt})`, this.cid);
13079
- await this.doJoin(data);
13080
- delete joinData.migrating_from;
13081
- delete joinData.migrating_from_list;
13082
- break;
13083
- }
13084
- catch (err) {
13085
- this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13086
- if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13087
- (err instanceof SfuJoinError && err.unrecoverable)) {
13088
- // if the error is unrecoverable, we should not retry as that signals
13089
- // that connectivity is good, but the coordinator doesn't allow the user
13090
- // to join the call due to some reason (e.g., ended call, expired token...)
13091
- throw err;
13092
- }
13093
- // immediately switch to a different SFU in case of recoverable join error
13094
- const switchSfu = err instanceof SfuJoinError &&
13095
- SfuJoinError.isJoinErrorCode(err.errorEvent);
13096
- const sfuId = this.credentials?.server.edge_name || '';
13097
- const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13098
- sfuJoinFailures.set(sfuId, failures);
13099
- if (switchSfu || failures >= 2) {
13100
- joinData.migrating_from = sfuId;
13101
- joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13096
+ try {
13097
+ for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13098
+ try {
13099
+ this.logger.trace(`Joining call (${attempt})`, this.cid);
13100
+ await this.doJoin(data);
13101
+ delete joinData.migrating_from;
13102
+ delete joinData.migrating_from_list;
13103
+ break;
13102
13104
  }
13103
- if (attempt === maxJoinRetries - 1) {
13104
- throw err;
13105
+ catch (err) {
13106
+ this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13107
+ if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13108
+ (err instanceof SfuJoinError && err.unrecoverable)) {
13109
+ // if the error is unrecoverable, we should not retry as that signals
13110
+ // that connectivity is good, but the coordinator doesn't allow the user
13111
+ // to join the call due to some reason (e.g., ended call, expired token...)
13112
+ throw err;
13113
+ }
13114
+ // immediately switch to a different SFU in case of recoverable join error
13115
+ const switchSfu = err instanceof SfuJoinError &&
13116
+ SfuJoinError.isJoinErrorCode(err.errorEvent);
13117
+ const sfuId = this.credentials?.server.edge_name || '';
13118
+ const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13119
+ sfuJoinFailures.set(sfuId, failures);
13120
+ if (switchSfu || failures >= 2) {
13121
+ joinData.migrating_from = sfuId;
13122
+ joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13123
+ }
13124
+ if (attempt === maxJoinRetries - 1) {
13125
+ throw err;
13126
+ }
13105
13127
  }
13128
+ await sleep(retryInterval(attempt));
13106
13129
  }
13107
- await sleep(retryInterval(attempt));
13130
+ }
13131
+ catch (error) {
13132
+ callingX?.endCall(this, 'error');
13133
+ throw error;
13108
13134
  }
13109
13135
  };
13110
13136
  /**
@@ -13251,7 +13277,9 @@ class Call {
13251
13277
  // re-apply them on later reconnections or server-side data fetches
13252
13278
  if (!this.deviceSettingsAppliedOnce && this.state.settings) {
13253
13279
  await this.applyDeviceConfig(this.state.settings, true);
13254
- globalThis.streamRNVideoSDK?.callManager.start();
13280
+ globalThis.streamRNVideoSDK?.callManager.start({
13281
+ isRingingTypeCall: this.ringing,
13282
+ });
13255
13283
  this.deviceSettingsAppliedOnce = true;
13256
13284
  }
13257
13285
  // We shouldn't persist the `ring` and `notify` state after joining the call
@@ -13679,6 +13707,7 @@ class Call {
13679
13707
  if (strategy === WebsocketReconnectStrategy.UNSPECIFIED)
13680
13708
  return;
13681
13709
  if (strategy === WebsocketReconnectStrategy.DISCONNECT) {
13710
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'error');
13682
13711
  this.leave({ message: 'SFU instructed to disconnect' }).catch((err) => {
13683
13712
  this.logger.warn(`Can't leave call after disconnect request`, err);
13684
13713
  });
@@ -14508,10 +14537,8 @@ class Call {
14508
14537
  *
14509
14538
  * @internal
14510
14539
  */
14511
- this.applyDeviceConfig = async (settings, publish, skipSpeakerApply = false) => {
14512
- if (!skipSpeakerApply) {
14513
- this.speaker.apply(settings);
14514
- }
14540
+ this.applyDeviceConfig = async (settings, publish) => {
14541
+ this.speaker.apply(settings);
14515
14542
  await this.camera.apply(settings.video, publish).catch((err) => {
14516
14543
  this.logger.warn('Camera init failed', err);
14517
14544
  });
@@ -15826,7 +15853,7 @@ class StreamClient {
15826
15853
  this.getUserAgent = () => {
15827
15854
  if (!this.cachedUserAgent) {
15828
15855
  const { clientAppIdentifier = {} } = this.options;
15829
- const { sdkName = 'js', sdkVersion = "1.44.1-beta.1", ...extras } = clientAppIdentifier;
15856
+ const { sdkName = 'js', sdkVersion = "1.44.1-beta.2", ...extras } = clientAppIdentifier;
15830
15857
  this.cachedUserAgent = [
15831
15858
  `stream-video-${sdkName}-v${sdkVersion}`,
15832
15859
  ...Object.entries(extras).map(([key, value]) => `${key}=${value}`),