@stream-io/video-client 1.44.5 → 1.44.6-beta.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.
@@ -4784,7 +4784,7 @@ class StreamVideoWriteableStateStore {
4784
4784
  * The currently connected user.
4785
4785
  */
4786
4786
  get connectedUser() {
4787
- return getCurrentValue(this.connectedUserSubject);
4787
+ return this.connectedUserSubject.getValue();
4788
4788
  }
4789
4789
  /**
4790
4790
  * A list of {@link Call} objects created/tracked by this client.
@@ -6283,7 +6283,7 @@ const getSdkVersion = (sdk) => {
6283
6283
  return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
6284
6284
  };
6285
6285
 
6286
- const version = "1.44.5";
6286
+ const version = "1.44.6-beta.0";
6287
6287
  const [major, minor, patch] = version.split('.');
6288
6288
  let sdkInfo = {
6289
6289
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -8982,6 +8982,7 @@ const watchCallRejected = (call) => {
8982
8982
  else {
8983
8983
  if (rejectedBy[eventCall.created_by.id]) {
8984
8984
  call.logger.info('call creator rejected, leaving call');
8985
+ globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8985
8986
  await call.leave({ message: 'ring: creator rejected' });
8986
8987
  }
8987
8988
  }
@@ -8992,6 +8993,7 @@ const watchCallRejected = (call) => {
8992
8993
  */
8993
8994
  const watchCallEnded = (call) => {
8994
8995
  return function onCallEnded() {
8996
+ globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8995
8997
  const { callingState } = call.state;
8996
8998
  if (callingState !== CallingState.IDLE &&
8997
8999
  callingState !== CallingState.LEFT) {
@@ -9023,6 +9025,7 @@ const watchSfuCallEnded = (call) => {
9023
9025
  // update the call state to reflect the call has ended.
9024
9026
  call.state.setEndedAt(new Date());
9025
9027
  const reason = CallEndedReason[e.reason];
9028
+ globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
9026
9029
  await call.leave({ message: `callEnded received: ${reason}` });
9027
9030
  }
9028
9031
  catch (err) {
@@ -12626,6 +12629,7 @@ class SpeakerManager {
12626
12629
  this.defaultDevice = defaultDevice;
12627
12630
  globalThis.streamRNVideoSDK?.callManager.setup({
12628
12631
  defaultDevice,
12632
+ isRingingTypeCall: this.call.ringing,
12629
12633
  });
12630
12634
  }
12631
12635
  }
@@ -12825,6 +12829,7 @@ class Call {
12825
12829
  const currentUserId = this.currentUserId;
12826
12830
  if (currentUserId && blockedUserIds.includes(currentUserId)) {
12827
12831
  this.logger.info('Leaving call because of being blocked');
12832
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'restricted');
12828
12833
  await this.leave({ message: 'user blocked' }).catch((err) => {
12829
12834
  this.logger.error('Error leaving call after being blocked', err);
12830
12835
  });
@@ -12861,6 +12866,7 @@ class Call {
12861
12866
  const isAcceptedElsewhere = isAcceptedByMe && this.state.callingState === CallingState.RINGING;
12862
12867
  if ((isAcceptedElsewhere || isRejectedByMe) &&
12863
12868
  !hasPending(this.joinLeaveConcurrencyTag)) {
12869
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, isAcceptedElsewhere ? 'answeredElsewhere' : 'rejected');
12864
12870
  this.leave().catch(() => {
12865
12871
  this.logger.error('Could not leave a call that was accepted or rejected elsewhere');
12866
12872
  });
@@ -12872,6 +12878,9 @@ class Call {
12872
12878
  const receiver_id = this.clientStore.connectedUser?.id;
12873
12879
  const ended_at = callSession?.ended_at;
12874
12880
  const created_by_id = this.state.createdBy?.id;
12881
+ if (this.currentUserId && created_by_id === this.currentUserId) {
12882
+ globalThis.streamRNVideoSDK?.callingX?.registerOutgoingCall(this);
12883
+ }
12875
12884
  const rejected_by = callSession?.rejected_by;
12876
12885
  const accepted_by = callSession?.accepted_by;
12877
12886
  let leaveCallIdle = false;
@@ -13010,17 +13019,28 @@ class Call {
13010
13019
  }
13011
13020
  if (callingState === CallingState.RINGING && reject !== false) {
13012
13021
  if (reject) {
13013
- await this.reject(reason ?? 'decline');
13022
+ const reasonToEndCallReason = {
13023
+ timeout: 'missed',
13024
+ cancel: 'canceled',
13025
+ busy: 'busy',
13026
+ decline: 'rejected',
13027
+ };
13028
+ const rejectReason = reason ?? 'decline';
13029
+ const endCallReason = reasonToEndCallReason[rejectReason] ?? 'rejected';
13030
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, endCallReason);
13031
+ await this.reject(rejectReason);
13014
13032
  }
13015
13033
  else {
13016
13034
  // if reject was undefined, we still have to cancel the call automatically
13017
13035
  // when I am the creator and everyone else left the call
13018
13036
  const hasOtherParticipants = this.state.remoteParticipants.length > 0;
13019
13037
  if (this.isCreatedByMe && !hasOtherParticipants) {
13038
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'canceled');
13020
13039
  await this.reject('cancel');
13021
13040
  }
13022
13041
  }
13023
13042
  }
13043
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this);
13024
13044
  this.statsReporter?.stop();
13025
13045
  this.statsReporter = undefined;
13026
13046
  const leaveReason = message ?? reason ?? 'user is leaving the call';
@@ -13047,7 +13067,9 @@ class Call {
13047
13067
  this.ringingSubject.next(false);
13048
13068
  this.cancelAutoDrop();
13049
13069
  this.clientStore.unregisterCall(this);
13050
- globalThis.streamRNVideoSDK?.callManager.stop();
13070
+ globalThis.streamRNVideoSDK?.callManager.stop({
13071
+ isRingingTypeCall: this.ringing,
13072
+ });
13051
13073
  this.camera.dispose();
13052
13074
  this.microphone.dispose();
13053
13075
  this.screenShare.dispose();
@@ -13213,11 +13235,19 @@ class Call {
13213
13235
  * @returns a promise which resolves once the call join-flow has finished.
13214
13236
  */
13215
13237
  this.join = async ({ maxJoinRetries = 3, joinResponseTimeout, rpcRequestTimeout, ...data } = {}) => {
13216
- await this.setup();
13217
13238
  const callingState = this.state.callingState;
13218
13239
  if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
13219
13240
  throw new Error(`Illegal State: call.join() shall be called only once`);
13220
13241
  }
13242
+ if (data?.ring) {
13243
+ this.ringingSubject.next(true);
13244
+ }
13245
+ const callingX = globalThis.streamRNVideoSDK?.callingX;
13246
+ if (callingX) {
13247
+ // for Android/iOS, we need to start the call in the callingx library as soon as possible
13248
+ await callingX.joinCall(this, this.clientStore.calls);
13249
+ }
13250
+ await this.setup();
13221
13251
  this.joinResponseTimeout = joinResponseTimeout;
13222
13252
  this.rpcRequestTimeout = rpcRequestTimeout;
13223
13253
  // we will count the number of join failures per SFU.
@@ -13226,38 +13256,44 @@ class Call {
13226
13256
  const sfuJoinFailures = new Map();
13227
13257
  const joinData = data;
13228
13258
  maxJoinRetries = Math.max(maxJoinRetries, 1);
13229
- for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13230
- try {
13231
- this.logger.trace(`Joining call (${attempt})`, this.cid);
13232
- await this.doJoin(data);
13233
- delete joinData.migrating_from;
13234
- delete joinData.migrating_from_list;
13235
- break;
13236
- }
13237
- catch (err) {
13238
- this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13239
- if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13240
- (err instanceof SfuJoinError && err.unrecoverable)) {
13241
- // if the error is unrecoverable, we should not retry as that signals
13242
- // that connectivity is good, but the coordinator doesn't allow the user
13243
- // to join the call due to some reason (e.g., ended call, expired token...)
13244
- throw err;
13245
- }
13246
- // immediately switch to a different SFU in case of recoverable join error
13247
- const switchSfu = err instanceof SfuJoinError &&
13248
- SfuJoinError.isJoinErrorCode(err.errorEvent);
13249
- const sfuId = this.credentials?.server.edge_name || '';
13250
- const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13251
- sfuJoinFailures.set(sfuId, failures);
13252
- if (switchSfu || failures >= 2) {
13253
- joinData.migrating_from = sfuId;
13254
- joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13259
+ try {
13260
+ for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13261
+ try {
13262
+ this.logger.trace(`Joining call (${attempt})`, this.cid);
13263
+ await this.doJoin(data);
13264
+ delete joinData.migrating_from;
13265
+ delete joinData.migrating_from_list;
13266
+ break;
13255
13267
  }
13256
- if (attempt === maxJoinRetries - 1) {
13257
- throw err;
13268
+ catch (err) {
13269
+ this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13270
+ if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13271
+ (err instanceof SfuJoinError && err.unrecoverable)) {
13272
+ // if the error is unrecoverable, we should not retry as that signals
13273
+ // that connectivity is good, but the coordinator doesn't allow the user
13274
+ // to join the call due to some reason (e.g., ended call, expired token...)
13275
+ throw err;
13276
+ }
13277
+ // immediately switch to a different SFU in case of recoverable join error
13278
+ const switchSfu = err instanceof SfuJoinError &&
13279
+ SfuJoinError.isJoinErrorCode(err.errorEvent);
13280
+ const sfuId = this.credentials?.server.edge_name || '';
13281
+ const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13282
+ sfuJoinFailures.set(sfuId, failures);
13283
+ if (switchSfu || failures >= 2) {
13284
+ joinData.migrating_from = sfuId;
13285
+ joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13286
+ }
13287
+ if (attempt === maxJoinRetries - 1) {
13288
+ throw err;
13289
+ }
13258
13290
  }
13291
+ await sleep(retryInterval(attempt));
13259
13292
  }
13260
- await sleep(retryInterval(attempt));
13293
+ }
13294
+ catch (error) {
13295
+ callingX?.endCall(this, 'error');
13296
+ throw error;
13261
13297
  }
13262
13298
  };
13263
13299
  /**
@@ -13404,7 +13440,9 @@ class Call {
13404
13440
  // re-apply them on later reconnections or server-side data fetches
13405
13441
  if (!this.deviceSettingsAppliedOnce && this.state.settings) {
13406
13442
  await this.applyDeviceConfig(this.state.settings, true, false);
13407
- globalThis.streamRNVideoSDK?.callManager.start();
13443
+ globalThis.streamRNVideoSDK?.callManager.start({
13444
+ isRingingTypeCall: this.ringing,
13445
+ });
13408
13446
  this.deviceSettingsAppliedOnce = true;
13409
13447
  }
13410
13448
  // We shouldn't persist the `ring` and `notify` state after joining the call
@@ -13832,6 +13870,7 @@ class Call {
13832
13870
  if (strategy === WebsocketReconnectStrategy.UNSPECIFIED)
13833
13871
  return;
13834
13872
  if (strategy === WebsocketReconnectStrategy.DISCONNECT) {
13873
+ globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'error');
13835
13874
  this.leave({ message: 'SFU instructed to disconnect' }).catch((err) => {
13836
13875
  this.logger.warn(`Can't leave call after disconnect request`, err);
13837
13876
  });
@@ -14853,7 +14892,7 @@ class Call {
14853
14892
  * A flag indicating whether the call was created by the current user.
14854
14893
  */
14855
14894
  get isCreatedByMe() {
14856
- return this.state.createdBy?.id === this.currentUserId;
14895
+ return (this.currentUserId && this.state.createdBy?.id === this.currentUserId);
14857
14896
  }
14858
14897
  }
14859
14898
 
@@ -15979,7 +16018,7 @@ class StreamClient {
15979
16018
  this.getUserAgent = () => {
15980
16019
  if (!this.cachedUserAgent) {
15981
16020
  const { clientAppIdentifier = {} } = this.options;
15982
- const { sdkName = 'js', sdkVersion = "1.44.5", ...extras } = clientAppIdentifier;
16021
+ const { sdkName = 'js', sdkVersion = "1.44.6-beta.0", ...extras } = clientAppIdentifier;
15983
16022
  this.cachedUserAgent = [
15984
16023
  `stream-video-${sdkName}-v${sdkVersion}`,
15985
16024
  ...Object.entries(extras).map(([key, value]) => `${key}=${value}`),