@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.
package/dist/index.cjs.js CHANGED
@@ -6251,7 +6251,7 @@ const getSdkVersion = (sdk) => {
6251
6251
  return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
6252
6252
  };
6253
6253
 
6254
- const version = "1.44.1-beta.1";
6254
+ const version = "1.44.1-beta.2";
6255
6255
  const [major, minor, patch] = version.split('.');
6256
6256
  let sdkInfo = {
6257
6257
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -8944,6 +8944,7 @@ const watchCallRejected = (call) => {
8944
8944
  else {
8945
8945
  if (rejectedBy[eventCall.created_by.id]) {
8946
8946
  call.logger.info('call creator rejected, leaving call');
8947
+ globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8947
8948
  await call.leave({ message: 'ring: creator rejected' });
8948
8949
  }
8949
8950
  }
@@ -8957,6 +8958,7 @@ const watchCallEnded = (call) => {
8957
8958
  const { callingState } = call.state;
8958
8959
  if (callingState !== exports.CallingState.IDLE &&
8959
8960
  callingState !== exports.CallingState.LEFT) {
8961
+ globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8960
8962
  call
8961
8963
  .leave({ message: 'call.ended event received', reject: false })
8962
8964
  .catch((err) => {
@@ -8985,6 +8987,7 @@ const watchSfuCallEnded = (call) => {
8985
8987
  // update the call state to reflect the call has ended.
8986
8988
  call.state.setEndedAt(new Date());
8987
8989
  const reason = CallEndedReason[e.reason];
8990
+ globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8988
8991
  await call.leave({ message: `callEnded received: ${reason}` });
8989
8992
  }
8990
8993
  catch (err) {
@@ -12499,6 +12502,7 @@ class SpeakerManager {
12499
12502
  this.defaultDevice = defaultDevice;
12500
12503
  globalThis.streamRNVideoSDK?.callManager.setup({
12501
12504
  defaultDevice,
12505
+ isRingingTypeCall: this.call.ringing,
12502
12506
  });
12503
12507
  }
12504
12508
  }
@@ -12698,6 +12702,7 @@ class Call {
12698
12702
  const currentUserId = this.currentUserId;
12699
12703
  if (currentUserId && blockedUserIds.includes(currentUserId)) {
12700
12704
  this.logger.info('Leaving call because of being blocked');
12705
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'restricted');
12701
12706
  await this.leave({ message: 'user blocked' }).catch((err) => {
12702
12707
  this.logger.error('Error leaving call after being blocked', err);
12703
12708
  });
@@ -12734,6 +12739,7 @@ class Call {
12734
12739
  const isAcceptedElsewhere = isAcceptedByMe && this.state.callingState === exports.CallingState.RINGING;
12735
12740
  if ((isAcceptedElsewhere || isRejectedByMe) &&
12736
12741
  !hasPending(this.joinLeaveConcurrencyTag)) {
12742
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, isAcceptedElsewhere ? 'answeredElsewhere' : 'rejected');
12737
12743
  this.leave().catch(() => {
12738
12744
  this.logger.error('Could not leave a call that was accepted or rejected elsewhere');
12739
12745
  });
@@ -12883,17 +12889,28 @@ class Call {
12883
12889
  }
12884
12890
  if (callingState === exports.CallingState.RINGING && reject !== false) {
12885
12891
  if (reject) {
12886
- await this.reject(reason ?? 'decline');
12892
+ const reasonToEndCallReason = {
12893
+ timeout: 'missed',
12894
+ cancel: 'canceled',
12895
+ busy: 'busy',
12896
+ decline: 'rejected',
12897
+ };
12898
+ const rejectReason = reason ?? 'decline';
12899
+ const endCallReason = reasonToEndCallReason[rejectReason] ?? 'rejected';
12900
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, endCallReason);
12901
+ await this.reject(rejectReason);
12887
12902
  }
12888
12903
  else {
12889
12904
  // if reject was undefined, we still have to cancel the call automatically
12890
12905
  // when I am the creator and everyone else left the call
12891
12906
  const hasOtherParticipants = this.state.remoteParticipants.length > 0;
12892
12907
  if (this.isCreatedByMe && !hasOtherParticipants) {
12908
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'canceled');
12893
12909
  await this.reject('cancel');
12894
12910
  }
12895
12911
  }
12896
12912
  }
12913
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this);
12897
12914
  this.statsReporter?.stop();
12898
12915
  this.statsReporter = undefined;
12899
12916
  const leaveReason = message ?? reason ?? 'user is leaving the call';
@@ -12920,7 +12937,9 @@ class Call {
12920
12937
  this.ringingSubject.next(false);
12921
12938
  this.cancelAutoDrop();
12922
12939
  this.clientStore.unregisterCall(this);
12923
- globalThis.streamRNVideoSDK?.callManager.stop();
12940
+ globalThis.streamRNVideoSDK?.callManager.stop({
12941
+ isRingingTypeCall: this.ringing,
12942
+ });
12924
12943
  this.camera.dispose();
12925
12944
  this.microphone.dispose();
12926
12945
  this.screenShare.dispose();
@@ -12964,8 +12983,7 @@ class Call {
12964
12983
  // const calls = useCalls().filter((c) => c.ringing);
12965
12984
  const calls = this.clientStore.calls.filter((c) => c.cid !== this.cid);
12966
12985
  this.clientStore.setCalls([this, ...calls]);
12967
- const skipSpeakerApply = isReactNative() && true;
12968
- await this.applyDeviceConfig(settings, false, skipSpeakerApply);
12986
+ await this.applyDeviceConfig(settings, false);
12969
12987
  };
12970
12988
  /**
12971
12989
  * Loads the information about the call.
@@ -12988,10 +13006,7 @@ class Call {
12988
13006
  this.watching = true;
12989
13007
  this.clientStore.registerOrUpdateCall(this);
12990
13008
  }
12991
- const skipSpeakerApply = isReactNative()
12992
- ? (params?.ring ?? this.ringing)
12993
- : false;
12994
- await this.applyDeviceConfig(response.call.settings, false, skipSpeakerApply);
13009
+ await this.applyDeviceConfig(response.call.settings, false);
12995
13010
  return response;
12996
13011
  };
12997
13012
  /**
@@ -13012,10 +13027,7 @@ class Call {
13012
13027
  this.watching = true;
13013
13028
  this.clientStore.registerOrUpdateCall(this);
13014
13029
  }
13015
- const skipSpeakerApply = isReactNative()
13016
- ? (data?.ring ?? this.ringing)
13017
- : false;
13018
- await this.applyDeviceConfig(response.call.settings, false, skipSpeakerApply);
13030
+ await this.applyDeviceConfig(response.call.settings, false);
13019
13031
  return response;
13020
13032
  };
13021
13033
  /**
@@ -13080,11 +13092,19 @@ class Call {
13080
13092
  * @returns a promise which resolves once the call join-flow has finished.
13081
13093
  */
13082
13094
  this.join = async ({ maxJoinRetries = 3, joinResponseTimeout, rpcRequestTimeout, ...data } = {}) => {
13083
- await this.setup();
13084
13095
  const callingState = this.state.callingState;
13085
13096
  if ([exports.CallingState.JOINED, exports.CallingState.JOINING].includes(callingState)) {
13086
13097
  throw new Error(`Illegal State: call.join() shall be called only once`);
13087
13098
  }
13099
+ if (data?.ring) {
13100
+ this.ringingSubject.next(true);
13101
+ }
13102
+ const callingX = globalThis.streamRNVideoSDK?.callingX;
13103
+ if (callingX) {
13104
+ // for Android/iOS, we need to start the call in the callingx library as soon as possible
13105
+ await callingX.startCall(this, this.clientStore.calls);
13106
+ }
13107
+ await this.setup();
13088
13108
  this.joinResponseTimeout = joinResponseTimeout;
13089
13109
  this.rpcRequestTimeout = rpcRequestTimeout;
13090
13110
  // we will count the number of join failures per SFU.
@@ -13093,38 +13113,44 @@ class Call {
13093
13113
  const sfuJoinFailures = new Map();
13094
13114
  const joinData = data;
13095
13115
  maxJoinRetries = Math.max(maxJoinRetries, 1);
13096
- for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13097
- try {
13098
- this.logger.trace(`Joining call (${attempt})`, this.cid);
13099
- await this.doJoin(data);
13100
- delete joinData.migrating_from;
13101
- delete joinData.migrating_from_list;
13102
- break;
13103
- }
13104
- catch (err) {
13105
- this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13106
- if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13107
- (err instanceof SfuJoinError && err.unrecoverable)) {
13108
- // if the error is unrecoverable, we should not retry as that signals
13109
- // that connectivity is good, but the coordinator doesn't allow the user
13110
- // to join the call due to some reason (e.g., ended call, expired token...)
13111
- throw err;
13112
- }
13113
- // immediately switch to a different SFU in case of recoverable join error
13114
- const switchSfu = err instanceof SfuJoinError &&
13115
- SfuJoinError.isJoinErrorCode(err.errorEvent);
13116
- const sfuId = this.credentials?.server.edge_name || '';
13117
- const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13118
- sfuJoinFailures.set(sfuId, failures);
13119
- if (switchSfu || failures >= 2) {
13120
- joinData.migrating_from = sfuId;
13121
- joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13116
+ try {
13117
+ for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13118
+ try {
13119
+ this.logger.trace(`Joining call (${attempt})`, this.cid);
13120
+ await this.doJoin(data);
13121
+ delete joinData.migrating_from;
13122
+ delete joinData.migrating_from_list;
13123
+ break;
13122
13124
  }
13123
- if (attempt === maxJoinRetries - 1) {
13124
- throw err;
13125
+ catch (err) {
13126
+ this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13127
+ if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13128
+ (err instanceof SfuJoinError && err.unrecoverable)) {
13129
+ // if the error is unrecoverable, we should not retry as that signals
13130
+ // that connectivity is good, but the coordinator doesn't allow the user
13131
+ // to join the call due to some reason (e.g., ended call, expired token...)
13132
+ throw err;
13133
+ }
13134
+ // immediately switch to a different SFU in case of recoverable join error
13135
+ const switchSfu = err instanceof SfuJoinError &&
13136
+ SfuJoinError.isJoinErrorCode(err.errorEvent);
13137
+ const sfuId = this.credentials?.server.edge_name || '';
13138
+ const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13139
+ sfuJoinFailures.set(sfuId, failures);
13140
+ if (switchSfu || failures >= 2) {
13141
+ joinData.migrating_from = sfuId;
13142
+ joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13143
+ }
13144
+ if (attempt === maxJoinRetries - 1) {
13145
+ throw err;
13146
+ }
13125
13147
  }
13148
+ await sleep(retryInterval(attempt));
13126
13149
  }
13127
- await sleep(retryInterval(attempt));
13150
+ }
13151
+ catch (error) {
13152
+ callingX?.endCall(this, 'error');
13153
+ throw error;
13128
13154
  }
13129
13155
  };
13130
13156
  /**
@@ -13271,7 +13297,9 @@ class Call {
13271
13297
  // re-apply them on later reconnections or server-side data fetches
13272
13298
  if (!this.deviceSettingsAppliedOnce && this.state.settings) {
13273
13299
  await this.applyDeviceConfig(this.state.settings, true);
13274
- globalThis.streamRNVideoSDK?.callManager.start();
13300
+ globalThis.streamRNVideoSDK?.callManager.start({
13301
+ isRingingTypeCall: this.ringing,
13302
+ });
13275
13303
  this.deviceSettingsAppliedOnce = true;
13276
13304
  }
13277
13305
  // We shouldn't persist the `ring` and `notify` state after joining the call
@@ -13699,6 +13727,7 @@ class Call {
13699
13727
  if (strategy === WebsocketReconnectStrategy.UNSPECIFIED)
13700
13728
  return;
13701
13729
  if (strategy === WebsocketReconnectStrategy.DISCONNECT) {
13730
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'error');
13702
13731
  this.leave({ message: 'SFU instructed to disconnect' }).catch((err) => {
13703
13732
  this.logger.warn(`Can't leave call after disconnect request`, err);
13704
13733
  });
@@ -14528,10 +14557,8 @@ class Call {
14528
14557
  *
14529
14558
  * @internal
14530
14559
  */
14531
- this.applyDeviceConfig = async (settings, publish, skipSpeakerApply = false) => {
14532
- if (!skipSpeakerApply) {
14533
- this.speaker.apply(settings);
14534
- }
14560
+ this.applyDeviceConfig = async (settings, publish) => {
14561
+ this.speaker.apply(settings);
14535
14562
  await this.camera.apply(settings.video, publish).catch((err) => {
14536
14563
  this.logger.warn('Camera init failed', err);
14537
14564
  });
@@ -15844,7 +15871,7 @@ class StreamClient {
15844
15871
  this.getUserAgent = () => {
15845
15872
  if (!this.cachedUserAgent) {
15846
15873
  const { clientAppIdentifier = {} } = this.options;
15847
- const { sdkName = 'js', sdkVersion = "1.44.1-beta.1", ...extras } = clientAppIdentifier;
15874
+ const { sdkName = 'js', sdkVersion = "1.44.1-beta.2", ...extras } = clientAppIdentifier;
15848
15875
  this.cachedUserAgent = [
15849
15876
  `stream-video-${sdkName}-v${sdkVersion}`,
15850
15877
  ...Object.entries(extras).map(([key, value]) => `${key}=${value}`),