@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.es.js CHANGED
@@ -4785,7 +4785,7 @@ class StreamVideoWriteableStateStore {
4785
4785
  * The currently connected user.
4786
4786
  */
4787
4787
  get connectedUser() {
4788
- return this.connectedUserSubject.getValue();
4788
+ return getCurrentValue(this.connectedUserSubject);
4789
4789
  }
4790
4790
  /**
4791
4791
  * A list of {@link Call} objects created/tracked by this client.
@@ -6284,7 +6284,7 @@ const getSdkVersion = (sdk) => {
6284
6284
  return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
6285
6285
  };
6286
6286
 
6287
- const version = "1.44.6-beta.0";
6287
+ const version = "1.45.0";
6288
6288
  const [major, minor, patch] = version.split('.');
6289
6289
  let sdkInfo = {
6290
6290
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -8983,7 +8983,6 @@ const watchCallRejected = (call) => {
8983
8983
  else {
8984
8984
  if (rejectedBy[eventCall.created_by.id]) {
8985
8985
  call.logger.info('call creator rejected, leaving call');
8986
- globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8987
8986
  await call.leave({ message: 'ring: creator rejected' });
8988
8987
  }
8989
8988
  }
@@ -8994,7 +8993,6 @@ const watchCallRejected = (call) => {
8994
8993
  */
8995
8994
  const watchCallEnded = (call) => {
8996
8995
  return function onCallEnded() {
8997
- globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
8998
8996
  const { callingState } = call.state;
8999
8997
  if (callingState !== CallingState.IDLE &&
9000
8998
  callingState !== CallingState.LEFT) {
@@ -9026,7 +9024,6 @@ const watchSfuCallEnded = (call) => {
9026
9024
  // update the call state to reflect the call has ended.
9027
9025
  call.state.setEndedAt(new Date());
9028
9026
  const reason = CallEndedReason[e.reason];
9029
- globalThis.streamRNVideoSDK?.callingX?.endCall(call, 'remote');
9030
9027
  await call.leave({ message: `callEnded received: ${reason}` });
9031
9028
  }
9032
9029
  catch (err) {
@@ -9553,11 +9550,14 @@ class AudioBindingsWatchdog {
9553
9550
  for (const p of this.state.participants) {
9554
9551
  if (p.isLocalParticipant)
9555
9552
  continue;
9556
- const { audioStream, screenShareAudioStream, sessionId, userId } = p;
9557
- if (audioStream && !this.bindings.has(toBindingKey(sessionId))) {
9553
+ const { audioStream, screenShareAudioStream, sessionId, userId, publishedTracks, } = p;
9554
+ if (audioStream &&
9555
+ publishedTracks.includes(TrackType.AUDIO) &&
9556
+ !this.bindings.has(toBindingKey(sessionId))) {
9558
9557
  danglingUserIds.push(userId);
9559
9558
  }
9560
9559
  if (screenShareAudioStream &&
9560
+ publishedTracks.includes(TrackType.SCREEN_SHARE_AUDIO) &&
9561
9561
  !this.bindings.has(toBindingKey(sessionId, 'screenShareAudioTrack'))) {
9562
9562
  danglingUserIds.push(userId);
9563
9563
  }
@@ -11191,6 +11191,7 @@ class DeviceManager {
11191
11191
  isDeviceReplaced = true;
11192
11192
  }
11193
11193
  if (isDeviceDisconnected) {
11194
+ this.dispatchDeviceDisconnectedEvent(prevDevice);
11194
11195
  await this.disable();
11195
11196
  await this.select(undefined);
11196
11197
  }
@@ -11200,7 +11201,7 @@ class DeviceManager {
11200
11201
  await this.enable();
11201
11202
  this.isTrackStoppedDueToTrackEnd = false;
11202
11203
  }
11203
- else {
11204
+ else if (!hasPending(this.statusChangeConcurrencyTag)) {
11204
11205
  await this.applySettingsToStream();
11205
11206
  }
11206
11207
  }
@@ -11214,6 +11215,20 @@ class DeviceManager {
11214
11215
  const kind = this.mediaDeviceKind;
11215
11216
  return devices.find((d) => d.deviceId === deviceId && d.kind === kind);
11216
11217
  }
11218
+ dispatchDeviceDisconnectedEvent(device) {
11219
+ const event = {
11220
+ type: 'device.disconnected',
11221
+ call_cid: this.call.cid,
11222
+ status: this.isTrackStoppedDueToTrackEnd
11223
+ ? this.state.prevStatus
11224
+ : this.state.status,
11225
+ deviceId: device.deviceId,
11226
+ label: device.label,
11227
+ kind: device.kind,
11228
+ };
11229
+ this.call.tracer.trace('device.disconnected', event);
11230
+ this.call.streamClient.dispatchEvent(event);
11231
+ }
11217
11232
  persistPreference(selectedDevice, status) {
11218
11233
  const deviceKind = this.mediaDeviceKind;
11219
11234
  const deviceKey = deviceKind === 'audioinput' ? 'microphone' : 'camera';
@@ -12630,7 +12645,6 @@ class SpeakerManager {
12630
12645
  this.defaultDevice = defaultDevice;
12631
12646
  globalThis.streamRNVideoSDK?.callManager.setup({
12632
12647
  defaultDevice,
12633
- isRingingTypeCall: this.call.ringing,
12634
12648
  });
12635
12649
  }
12636
12650
  }
@@ -12830,7 +12844,6 @@ class Call {
12830
12844
  const currentUserId = this.currentUserId;
12831
12845
  if (currentUserId && blockedUserIds.includes(currentUserId)) {
12832
12846
  this.logger.info('Leaving call because of being blocked');
12833
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'restricted');
12834
12847
  await this.leave({ message: 'user blocked' }).catch((err) => {
12835
12848
  this.logger.error('Error leaving call after being blocked', err);
12836
12849
  });
@@ -12867,7 +12880,6 @@ class Call {
12867
12880
  const isAcceptedElsewhere = isAcceptedByMe && this.state.callingState === CallingState.RINGING;
12868
12881
  if ((isAcceptedElsewhere || isRejectedByMe) &&
12869
12882
  !hasPending(this.joinLeaveConcurrencyTag)) {
12870
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, isAcceptedElsewhere ? 'answeredElsewhere' : 'rejected');
12871
12883
  this.leave().catch(() => {
12872
12884
  this.logger.error('Could not leave a call that was accepted or rejected elsewhere');
12873
12885
  });
@@ -12879,9 +12891,6 @@ class Call {
12879
12891
  const receiver_id = this.clientStore.connectedUser?.id;
12880
12892
  const ended_at = callSession?.ended_at;
12881
12893
  const created_by_id = this.state.createdBy?.id;
12882
- if (this.currentUserId && created_by_id === this.currentUserId) {
12883
- globalThis.streamRNVideoSDK?.callingX?.registerOutgoingCall(this);
12884
- }
12885
12894
  const rejected_by = callSession?.rejected_by;
12886
12895
  const accepted_by = callSession?.accepted_by;
12887
12896
  let leaveCallIdle = false;
@@ -13020,28 +13029,17 @@ class Call {
13020
13029
  }
13021
13030
  if (callingState === CallingState.RINGING && reject !== false) {
13022
13031
  if (reject) {
13023
- const reasonToEndCallReason = {
13024
- timeout: 'missed',
13025
- cancel: 'canceled',
13026
- busy: 'busy',
13027
- decline: 'rejected',
13028
- };
13029
- const rejectReason = reason ?? 'decline';
13030
- const endCallReason = reasonToEndCallReason[rejectReason] ?? 'rejected';
13031
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, endCallReason);
13032
- await this.reject(rejectReason);
13032
+ await this.reject(reason ?? 'decline');
13033
13033
  }
13034
13034
  else {
13035
13035
  // if reject was undefined, we still have to cancel the call automatically
13036
13036
  // when I am the creator and everyone else left the call
13037
13037
  const hasOtherParticipants = this.state.remoteParticipants.length > 0;
13038
13038
  if (this.isCreatedByMe && !hasOtherParticipants) {
13039
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'canceled');
13040
13039
  await this.reject('cancel');
13041
13040
  }
13042
13041
  }
13043
13042
  }
13044
- globalThis.streamRNVideoSDK?.callingX?.endCall(this);
13045
13043
  this.statsReporter?.stop();
13046
13044
  this.statsReporter = undefined;
13047
13045
  const leaveReason = message ?? reason ?? 'user is leaving the call';
@@ -13068,9 +13066,7 @@ class Call {
13068
13066
  this.ringingSubject.next(false);
13069
13067
  this.cancelAutoDrop();
13070
13068
  this.clientStore.unregisterCall(this);
13071
- globalThis.streamRNVideoSDK?.callManager.stop({
13072
- isRingingTypeCall: this.ringing,
13073
- });
13069
+ globalThis.streamRNVideoSDK?.callManager.stop();
13074
13070
  this.camera.dispose();
13075
13071
  this.microphone.dispose();
13076
13072
  this.screenShare.dispose();
@@ -13236,19 +13232,11 @@ class Call {
13236
13232
  * @returns a promise which resolves once the call join-flow has finished.
13237
13233
  */
13238
13234
  this.join = async ({ maxJoinRetries = 3, joinResponseTimeout, rpcRequestTimeout, ...data } = {}) => {
13235
+ await this.setup();
13239
13236
  const callingState = this.state.callingState;
13240
13237
  if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
13241
13238
  throw new Error(`Illegal State: call.join() shall be called only once`);
13242
13239
  }
13243
- if (data?.ring) {
13244
- this.ringingSubject.next(true);
13245
- }
13246
- const callingX = globalThis.streamRNVideoSDK?.callingX;
13247
- if (callingX) {
13248
- // for Android/iOS, we need to start the call in the callingx library as soon as possible
13249
- await callingX.joinCall(this, this.clientStore.calls);
13250
- }
13251
- await this.setup();
13252
13240
  this.joinResponseTimeout = joinResponseTimeout;
13253
13241
  this.rpcRequestTimeout = rpcRequestTimeout;
13254
13242
  // we will count the number of join failures per SFU.
@@ -13257,44 +13245,38 @@ class Call {
13257
13245
  const sfuJoinFailures = new Map();
13258
13246
  const joinData = data;
13259
13247
  maxJoinRetries = Math.max(maxJoinRetries, 1);
13260
- try {
13261
- for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13262
- try {
13263
- this.logger.trace(`Joining call (${attempt})`, this.cid);
13264
- await this.doJoin(data);
13265
- delete joinData.migrating_from;
13266
- delete joinData.migrating_from_list;
13267
- break;
13248
+ for (let attempt = 0; attempt < maxJoinRetries; attempt++) {
13249
+ try {
13250
+ this.logger.trace(`Joining call (${attempt})`, this.cid);
13251
+ await this.doJoin(data);
13252
+ delete joinData.migrating_from;
13253
+ delete joinData.migrating_from_list;
13254
+ break;
13255
+ }
13256
+ catch (err) {
13257
+ this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13258
+ if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13259
+ (err instanceof SfuJoinError && err.unrecoverable)) {
13260
+ // if the error is unrecoverable, we should not retry as that signals
13261
+ // that connectivity is good, but the coordinator doesn't allow the user
13262
+ // to join the call due to some reason (e.g., ended call, expired token...)
13263
+ throw err;
13268
13264
  }
13269
- catch (err) {
13270
- this.logger.warn(`Failed to join call (${attempt})`, this.cid);
13271
- if ((err instanceof ErrorFromResponse && err.unrecoverable) ||
13272
- (err instanceof SfuJoinError && err.unrecoverable)) {
13273
- // if the error is unrecoverable, we should not retry as that signals
13274
- // that connectivity is good, but the coordinator doesn't allow the user
13275
- // to join the call due to some reason (e.g., ended call, expired token...)
13276
- throw err;
13277
- }
13278
- // immediately switch to a different SFU in case of recoverable join error
13279
- const switchSfu = err instanceof SfuJoinError &&
13280
- SfuJoinError.isJoinErrorCode(err.errorEvent);
13281
- const sfuId = this.credentials?.server.edge_name || '';
13282
- const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13283
- sfuJoinFailures.set(sfuId, failures);
13284
- if (switchSfu || failures >= 2) {
13285
- joinData.migrating_from = sfuId;
13286
- joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13287
- }
13288
- if (attempt === maxJoinRetries - 1) {
13289
- throw err;
13290
- }
13265
+ // immediately switch to a different SFU in case of recoverable join error
13266
+ const switchSfu = err instanceof SfuJoinError &&
13267
+ SfuJoinError.isJoinErrorCode(err.errorEvent);
13268
+ const sfuId = this.credentials?.server.edge_name || '';
13269
+ const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
13270
+ sfuJoinFailures.set(sfuId, failures);
13271
+ if (switchSfu || failures >= 2) {
13272
+ joinData.migrating_from = sfuId;
13273
+ joinData.migrating_from_list = Array.from(sfuJoinFailures.keys());
13274
+ }
13275
+ if (attempt === maxJoinRetries - 1) {
13276
+ throw err;
13291
13277
  }
13292
- await sleep(retryInterval(attempt));
13293
13278
  }
13294
- }
13295
- catch (error) {
13296
- callingX?.endCall(this, 'error');
13297
- throw error;
13279
+ await sleep(retryInterval(attempt));
13298
13280
  }
13299
13281
  };
13300
13282
  /**
@@ -13441,9 +13423,7 @@ class Call {
13441
13423
  // re-apply them on later reconnections or server-side data fetches
13442
13424
  if (!this.deviceSettingsAppliedOnce && this.state.settings) {
13443
13425
  await this.applyDeviceConfig(this.state.settings, true, false);
13444
- globalThis.streamRNVideoSDK?.callManager.start({
13445
- isRingingTypeCall: this.ringing,
13446
- });
13426
+ globalThis.streamRNVideoSDK?.callManager.start();
13447
13427
  this.deviceSettingsAppliedOnce = true;
13448
13428
  }
13449
13429
  // We shouldn't persist the `ring` and `notify` state after joining the call
@@ -13871,7 +13851,6 @@ class Call {
13871
13851
  if (strategy === WebsocketReconnectStrategy.UNSPECIFIED)
13872
13852
  return;
13873
13853
  if (strategy === WebsocketReconnectStrategy.DISCONNECT) {
13874
- globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'error');
13875
13854
  this.leave({ message: 'SFU instructed to disconnect' }).catch((err) => {
13876
13855
  this.logger.warn(`Can't leave call after disconnect request`, err);
13877
13856
  });
@@ -14893,7 +14872,7 @@ class Call {
14893
14872
  * A flag indicating whether the call was created by the current user.
14894
14873
  */
14895
14874
  get isCreatedByMe() {
14896
- return (this.currentUserId && this.state.createdBy?.id === this.currentUserId);
14875
+ return this.state.createdBy?.id === this.currentUserId;
14897
14876
  }
14898
14877
  }
14899
14878
 
@@ -16017,7 +15996,7 @@ class StreamClient {
16017
15996
  this.getUserAgent = () => {
16018
15997
  if (!this.cachedUserAgent) {
16019
15998
  const { clientAppIdentifier = {} } = this.options;
16020
- const { sdkName = 'js', sdkVersion = "1.44.6-beta.0", ...extras } = clientAppIdentifier;
15999
+ const { sdkName = 'js', sdkVersion = "1.45.0", ...extras } = clientAppIdentifier;
16021
16000
  this.cachedUserAgent = [
16022
16001
  `stream-video-${sdkName}-v${sdkVersion}`,
16023
16002
  ...Object.entries(extras).map(([key, value]) => `${key}=${value}`),