@stream-io/video-client 1.44.6-beta.0 → 1.45.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
@@ -4804,7 +4804,7 @@ class StreamVideoWriteableStateStore {
4804
4804
  * The currently connected user.
4805
4805
  */
4806
4806
  get connectedUser() {
4807
- return this.connectedUserSubject.getValue();
4807
+ return getCurrentValue(this.connectedUserSubject);
4808
4808
  }
4809
4809
  /**
4810
4810
  * A list of {@link Call} objects created/tracked by this client.
@@ -6303,7 +6303,7 @@ const getSdkVersion = (sdk) => {
6303
6303
  return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
6304
6304
  };
6305
6305
 
6306
- const version = "1.44.6-beta.0";
6306
+ const version = "1.45.0";
6307
6307
  const [major, minor, patch] = version.split('.');
6308
6308
  let sdkInfo = {
6309
6309
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -9002,7 +9002,6 @@ const watchCallRejected = (call) => {
9002
9002
  else {
9003
9003
  if (rejectedBy[eventCall.created_by.id]) {
9004
9004
  call.logger.info('call creator rejected, leaving call');
9005
- globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
9006
9005
  await call.leave({ message: 'ring: creator rejected' });
9007
9006
  }
9008
9007
  }
@@ -9013,7 +9012,6 @@ const watchCallRejected = (call) => {
9013
9012
  */
9014
9013
  const watchCallEnded = (call) => {
9015
9014
  return function onCallEnded() {
9016
- globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
9017
9015
  const { callingState } = call.state;
9018
9016
  if (callingState !== exports.CallingState.IDLE &&
9019
9017
  callingState !== exports.CallingState.LEFT) {
@@ -9045,7 +9043,6 @@ const watchSfuCallEnded = (call) => {
9045
9043
  // update the call state to reflect the call has ended.
9046
9044
  call.state.setEndedAt(new Date());
9047
9045
  const reason = CallEndedReason[e.reason];
9048
- globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
9049
9046
  await call.leave({ message: `callEnded received: ${reason}` });
9050
9047
  }
9051
9048
  catch (err) {
@@ -9572,11 +9569,14 @@ class AudioBindingsWatchdog {
9572
9569
  for (const p of this.state.participants) {
9573
9570
  if (p.isLocalParticipant)
9574
9571
  continue;
9575
- const { audioStream, screenShareAudioStream, sessionId, userId } = p;
9576
- if (audioStream && !this.bindings.has(toBindingKey(sessionId))) {
9572
+ const { audioStream, screenShareAudioStream, sessionId, userId, publishedTracks, } = p;
9573
+ if (audioStream &&
9574
+ publishedTracks.includes(TrackType.AUDIO) &&
9575
+ !this.bindings.has(toBindingKey(sessionId))) {
9577
9576
  danglingUserIds.push(userId);
9578
9577
  }
9579
9578
  if (screenShareAudioStream &&
9579
+ publishedTracks.includes(TrackType.SCREEN_SHARE_AUDIO) &&
9580
9580
  !this.bindings.has(toBindingKey(sessionId, 'screenShareAudioTrack'))) {
9581
9581
  danglingUserIds.push(userId);
9582
9582
  }
@@ -11210,6 +11210,7 @@ class DeviceManager {
11210
11210
  isDeviceReplaced = true;
11211
11211
  }
11212
11212
  if (isDeviceDisconnected) {
11213
+ this.dispatchDeviceDisconnectedEvent(prevDevice);
11213
11214
  await this.disable();
11214
11215
  await this.select(undefined);
11215
11216
  }
@@ -11219,7 +11220,7 @@ class DeviceManager {
11219
11220
  await this.enable();
11220
11221
  this.isTrackStoppedDueToTrackEnd = false;
11221
11222
  }
11222
- else {
11223
+ else if (!hasPending(this.statusChangeConcurrencyTag)) {
11223
11224
  await this.applySettingsToStream();
11224
11225
  }
11225
11226
  }
@@ -11233,6 +11234,20 @@ class DeviceManager {
11233
11234
  const kind = this.mediaDeviceKind;
11234
11235
  return devices.find((d) => d.deviceId === deviceId && d.kind === kind);
11235
11236
  }
11237
+ dispatchDeviceDisconnectedEvent(device) {
11238
+ const event = {
11239
+ type: 'device.disconnected',
11240
+ call_cid: this.call.cid,
11241
+ status: this.isTrackStoppedDueToTrackEnd
11242
+ ? this.state.prevStatus
11243
+ : this.state.status,
11244
+ deviceId: device.deviceId,
11245
+ label: device.label,
11246
+ kind: device.kind,
11247
+ };
11248
+ this.call.tracer.trace('device.disconnected', event);
11249
+ this.call.streamClient.dispatchEvent(event);
11250
+ }
11236
11251
  persistPreference(selectedDevice, status) {
11237
11252
  const deviceKind = this.mediaDeviceKind;
11238
11253
  const deviceKey = deviceKind === 'audioinput' ? 'microphone' : 'camera';
@@ -12649,7 +12664,6 @@ class SpeakerManager {
12649
12664
  this.defaultDevice = defaultDevice;
12650
12665
  globalThis.streamRNVideoSDK?.callManager.setup({
12651
12666
  defaultDevice,
12652
- isRingingTypeCall: this.call.ringing,
12653
12667
  });
12654
12668
  }
12655
12669
  }
@@ -12849,7 +12863,6 @@ class Call {
12849
12863
  const currentUserId = this.currentUserId;
12850
12864
  if (currentUserId && blockedUserIds.includes(currentUserId)) {
12851
12865
  this.logger.info('Leaving call because of being blocked');
12852
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'restricted');
12853
12866
  await this.leave({ message: 'user blocked' }).catch((err) => {
12854
12867
  this.logger.error('Error leaving call after being blocked', err);
12855
12868
  });
@@ -12886,7 +12899,6 @@ class Call {
12886
12899
  const isAcceptedElsewhere = isAcceptedByMe && this.state.callingState === exports.CallingState.RINGING;
12887
12900
  if ((isAcceptedElsewhere || isRejectedByMe) &&
12888
12901
  !hasPending(this.joinLeaveConcurrencyTag)) {
12889
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, isAcceptedElsewhere ? 'answeredElsewhere' : 'rejected');
12890
12902
  this.leave().catch(() => {
12891
12903
  this.logger.error('Could not leave a call that was accepted or rejected elsewhere');
12892
12904
  });
@@ -12898,9 +12910,6 @@ class Call {
12898
12910
  const receiver_id = this.clientStore.connectedUser?.id;
12899
12911
  const ended_at = callSession?.ended_at;
12900
12912
  const created_by_id = this.state.createdBy?.id;
12901
- if (this.currentUserId && created_by_id === this.currentUserId) {
12902
- globalThis.streamRNVideoSDK?.callingX?.registerOutgoingCall(this);
12903
- }
12904
12913
  const rejected_by = callSession?.rejected_by;
12905
12914
  const accepted_by = callSession?.accepted_by;
12906
12915
  let leaveCallIdle = false;
@@ -13039,28 +13048,17 @@ class Call {
13039
13048
  }
13040
13049
  if (callingState === exports.CallingState.RINGING && reject !== false) {
13041
13050
  if (reject) {
13042
- const reasonToEndCallReason = {
13043
- timeout: 'missed',
13044
- cancel: 'canceled',
13045
- busy: 'busy',
13046
- decline: 'rejected',
13047
- };
13048
- const rejectReason = reason ?? 'decline';
13049
- const endCallReason = reasonToEndCallReason[rejectReason] ?? 'rejected';
13050
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, endCallReason);
13051
- await this.reject(rejectReason);
13051
+ await this.reject(reason ?? 'decline');
13052
13052
  }
13053
13053
  else {
13054
13054
  // if reject was undefined, we still have to cancel the call automatically
13055
13055
  // when I am the creator and everyone else left the call
13056
13056
  const hasOtherParticipants = this.state.remoteParticipants.length > 0;
13057
13057
  if (this.isCreatedByMe && !hasOtherParticipants) {
13058
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'canceled');
13059
13058
  await this.reject('cancel');
13060
13059
  }
13061
13060
  }
13062
13061
  }
13063
- globalThis.streamRNVideoSDK?.callingX?.endCall(this);
13064
13062
  this.statsReporter?.stop();
13065
13063
  this.statsReporter = undefined;
13066
13064
  const leaveReason = message ?? reason ?? 'user is leaving the call';
@@ -13087,9 +13085,7 @@ class Call {
13087
13085
  this.ringingSubject.next(false);
13088
13086
  this.cancelAutoDrop();
13089
13087
  this.clientStore.unregisterCall(this);
13090
- globalThis.streamRNVideoSDK?.callManager.stop({
13091
- isRingingTypeCall: this.ringing,
13092
- });
13088
+ globalThis.streamRNVideoSDK?.callManager.stop();
13093
13089
  this.camera.dispose();
13094
13090
  this.microphone.dispose();
13095
13091
  this.screenShare.dispose();
@@ -13255,19 +13251,11 @@ class Call {
13255
13251
  * @returns a promise which resolves once the call join-flow has finished.
13256
13252
  */
13257
13253
  this.join = async ({ maxJoinRetries = 3, joinResponseTimeout, rpcRequestTimeout, ...data } = {}) => {
13254
+ await this.setup();
13258
13255
  const callingState = this.state.callingState;
13259
13256
  if ([exports.CallingState.JOINED, exports.CallingState.JOINING].includes(callingState)) {
13260
13257
  throw new Error(`Illegal State: call.join() shall be called only once`);
13261
13258
  }
13262
- if (data?.ring) {
13263
- this.ringingSubject.next(true);
13264
- }
13265
- const callingX = globalThis.streamRNVideoSDK?.callingX;
13266
- if (callingX) {
13267
- // for Android/iOS, we need to start the call in the callingx library as soon as possible
13268
- await callingX.joinCall(this, this.clientStore.calls);
13269
- }
13270
- await this.setup();
13271
13259
  this.joinResponseTimeout = joinResponseTimeout;
13272
13260
  this.rpcRequestTimeout = rpcRequestTimeout;
13273
13261
  // we will count the number of join failures per SFU.
@@ -13276,44 +13264,38 @@ class Call {
13276
13264
  const sfuJoinFailures = new Map();
13277
13265
  const joinData = data;
13278
13266
  maxJoinRetries = Math.max(maxJoinRetries, 1);
13279
- try {
13280
- for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13281
- try {
13282
- this.logger.trace(`Joining call (${attempt})`, this.cid);
13283
- await this.doJoin(data);
13284
- delete joinData.migrating_from;
13285
- delete joinData.migrating_from_list;
13286
- break;
13267
+ for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13268
+ try {
13269
+ this.logger.trace(`Joining call (${attempt})`, this.cid);
13270
+ await this.doJoin(data);
13271
+ delete joinData.migrating_from;
13272
+ delete joinData.migrating_from_list;
13273
+ break;
13274
+ }
13275
+ catch (err) {
13276
+ this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13277
+ if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13278
+ (err instanceof SfuJoinError && err.unrecoverable)) {
13279
+ // if the error is unrecoverable, we should not retry as that signals
13280
+ // that connectivity is good, but the coordinator doesn't allow the user
13281
+ // to join the call due to some reason (e.g., ended call, expired token...)
13282
+ throw err;
13287
13283
  }
13288
- catch (err) {
13289
- this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13290
- if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13291
- (err instanceof SfuJoinError && err.unrecoverable)) {
13292
- // if the error is unrecoverable, we should not retry as that signals
13293
- // that connectivity is good, but the coordinator doesn't allow the user
13294
- // to join the call due to some reason (e.g., ended call, expired token...)
13295
- throw err;
13296
- }
13297
- // immediately switch to a different SFU in case of recoverable join error
13298
- const switchSfu = err instanceof SfuJoinError &&
13299
- SfuJoinError.isJoinErrorCode(err.errorEvent);
13300
- const sfuId = this.credentials?.server.edge_name || '';
13301
- const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13302
- sfuJoinFailures.set(sfuId, failures);
13303
- if (switchSfu || failures >= 2) {
13304
- joinData.migrating_from = sfuId;
13305
- joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13306
- }
13307
- if (attempt === maxJoinRetries - 1) {
13308
- throw err;
13309
- }
13284
+ // immediately switch to a different SFU in case of recoverable join error
13285
+ const switchSfu = err instanceof SfuJoinError &&
13286
+ SfuJoinError.isJoinErrorCode(err.errorEvent);
13287
+ const sfuId = this.credentials?.server.edge_name || '';
13288
+ const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13289
+ sfuJoinFailures.set(sfuId, failures);
13290
+ if (switchSfu || failures >= 2) {
13291
+ joinData.migrating_from = sfuId;
13292
+ joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13293
+ }
13294
+ if (attempt === maxJoinRetries - 1) {
13295
+ throw err;
13310
13296
  }
13311
- await sleep(retryInterval(attempt));
13312
13297
  }
13313
- }
13314
- catch (error) {
13315
- callingX?.endCall(this, 'error');
13316
- throw error;
13298
+ await sleep(retryInterval(attempt));
13317
13299
  }
13318
13300
  };
13319
13301
  /**
@@ -13460,9 +13442,7 @@ class Call {
13460
13442
  // re-apply them on later reconnections or server-side data fetches
13461
13443
  if (!this.deviceSettingsAppliedOnce && this.state.settings) {
13462
13444
  await this.applyDeviceConfig(this.state.settings, true, false);
13463
- globalThis.streamRNVideoSDK?.callManager.start({
13464
- isRingingTypeCall: this.ringing,
13465
- });
13445
+ globalThis.streamRNVideoSDK?.callManager.start();
13466
13446
  this.deviceSettingsAppliedOnce = true;
13467
13447
  }
13468
13448
  // We shouldn't persist the `ring` and `notify` state after joining the call
@@ -13890,7 +13870,6 @@ class Call {
13890
13870
  if (strategy === WebsocketReconnectStrategy.UNSPECIFIED)
13891
13871
  return;
13892
13872
  if (strategy === WebsocketReconnectStrategy.DISCONNECT) {
13893
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'error');
13894
13873
  this.leave({ message: 'SFU instructed to disconnect' }).catch((err) => {
13895
13874
  this.logger.warn(`Can't leave call after disconnect request`, err);
13896
13875
  });
@@ -14912,7 +14891,7 @@ class Call {
14912
14891
  * A flag indicating whether the call was created by the current user.
14913
14892
  */
14914
14893
  get isCreatedByMe() {
14915
- return (this.currentUserId && this.state.createdBy?.id === this.currentUserId);
14894
+ return this.state.createdBy?.id === this.currentUserId;
14916
14895
  }
14917
14896
  }
14918
14897
 
@@ -16036,7 +16015,7 @@ class StreamClient {
16036
16015
  this.getUserAgent = () => {
16037
16016
  if (!this.cachedUserAgent) {
16038
16017
  const { clientAppIdentifier = {} } = this.options;
16039
- const { sdkName = 'js', sdkVersion = "1.44.6-beta.0", ...extras } = clientAppIdentifier;
16018
+ const { sdkName = 'js', sdkVersion = "1.45.0", ...extras } = clientAppIdentifier;
16040
16019
  this.cachedUserAgent = [
16041
16020
  `stream-video-${sdkName}-v${sdkVersion}`,
16042
16021
  ...Object.entries(extras).map(([key, value]) => `${key}=${value}`),