@stream-io/video-client 1.44.1 → 1.44.3

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.
@@ -761,7 +761,7 @@ export declare class Call {
761
761
  *
762
762
  * @internal
763
763
  */
764
- applyDeviceConfig: (settings: CallSettingsResponse, publish: boolean) => Promise<void>;
764
+ applyDeviceConfig: (settings: CallSettingsResponse, publish: boolean, skipSpeakerApply: boolean) => Promise<void>;
765
765
  /**
766
766
  * Will begin tracking the given element for visibility changes within the
767
767
  * configured viewport element (`call.setViewport`).
@@ -103,6 +103,7 @@ export declare class StreamSfuClient {
103
103
  private readonly credentials;
104
104
  private readonly dispatcher;
105
105
  private readonly joinResponseTimeout;
106
+ private readonly subscriptionsConcurrencyTag;
106
107
  private networkAvailableTask;
107
108
  /**
108
109
  * Promise that resolves when the JoinResponse is received.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "1.44.1",
3
+ "version": "1.44.3",
4
4
  "main": "dist/index.cjs.js",
5
5
  "module": "dist/index.es.js",
6
6
  "browser": "dist/index.browser.es.js",
package/src/Call.ts CHANGED
@@ -172,6 +172,7 @@ import {
172
172
  promiseWithResolvers,
173
173
  } from './helpers/promise';
174
174
  import { GetCallStatsResponse } from './gen/shims';
175
+ import { isReactNative } from './helpers/platforms';
175
176
 
176
177
  /**
177
178
  * An object representation of a `Call`.
@@ -746,7 +747,8 @@ export class Call {
746
747
  // const calls = useCalls().filter((c) => c.ringing);
747
748
  const calls = this.clientStore.calls.filter((c) => c.cid !== this.cid);
748
749
  this.clientStore.setCalls([this, ...calls]);
749
- await this.applyDeviceConfig(settings, false);
750
+ const skipSpeakerApply = isReactNative();
751
+ await this.applyDeviceConfig(settings, false, skipSpeakerApply);
750
752
  };
751
753
 
752
754
  /**
@@ -781,8 +783,17 @@ export class Call {
781
783
  this.watching = true;
782
784
  this.clientStore.registerOrUpdateCall(this);
783
785
  }
784
-
785
- await this.applyDeviceConfig(response.call.settings, false);
786
+ // Skip speaker setup on RN if ringing was requested or the call is already ringing
787
+ const skipSpeakerApply = isReactNative()
788
+ ? params?.ring === true
789
+ ? true
790
+ : this.ringing
791
+ : false;
792
+ await this.applyDeviceConfig(
793
+ response.call.settings,
794
+ false,
795
+ skipSpeakerApply,
796
+ );
786
797
 
787
798
  return response;
788
799
  };
@@ -812,7 +823,17 @@ export class Call {
812
823
  this.clientStore.registerOrUpdateCall(this);
813
824
  }
814
825
 
815
- await this.applyDeviceConfig(response.call.settings, false);
826
+ // Skip speaker setup on RN if ringing was requested or the call is already ringing
827
+ const skipSpeakerApply = isReactNative()
828
+ ? data?.ring === true
829
+ ? true
830
+ : this.ringing
831
+ : false;
832
+ await this.applyDeviceConfig(
833
+ response.call.settings,
834
+ false,
835
+ skipSpeakerApply,
836
+ );
816
837
 
817
838
  return response;
818
839
  };
@@ -1144,7 +1165,7 @@ export class Call {
1144
1165
  // device settings should be applied only once, we don't have to
1145
1166
  // re-apply them on later reconnections or server-side data fetches
1146
1167
  if (!this.deviceSettingsAppliedOnce && this.state.settings) {
1147
- await this.applyDeviceConfig(this.state.settings, true);
1168
+ await this.applyDeviceConfig(this.state.settings, true, false);
1148
1169
  globalThis.streamRNVideoSDK?.callManager.start();
1149
1170
  this.deviceSettingsAppliedOnce = true;
1150
1171
  }
@@ -2796,8 +2817,11 @@ export class Call {
2796
2817
  applyDeviceConfig = async (
2797
2818
  settings: CallSettingsResponse,
2798
2819
  publish: boolean,
2820
+ skipSpeakerApply: boolean,
2799
2821
  ) => {
2800
- this.speaker.apply(settings);
2822
+ if (!skipSpeakerApply) {
2823
+ this.speaker.apply(settings);
2824
+ }
2801
2825
  await this.camera.apply(settings.video, publish).catch((err) => {
2802
2826
  this.logger.warn('Camera init failed', err);
2803
2827
  });
@@ -37,6 +37,7 @@ import {
37
37
  promiseWithResolvers,
38
38
  SafePromise,
39
39
  } from './helpers/promise';
40
+ import { withoutConcurrency } from './helpers/concurrency';
40
41
  import { getTimers } from './timers';
41
42
  import { Tracer, TraceSlice } from './stats';
42
43
  import { SfuJoinError } from './errors';
@@ -164,6 +165,9 @@ export class StreamSfuClient {
164
165
  private readonly credentials: Credentials;
165
166
  private readonly dispatcher: Dispatcher;
166
167
  private readonly joinResponseTimeout: number;
168
+ private readonly subscriptionsConcurrencyTag = Symbol(
169
+ 'subscriptionsConcurrencyTag',
170
+ );
167
171
  private networkAvailableTask: PromiseWithResolvers<void> | undefined;
168
172
  /**
169
173
  * Promise that resolves when the JoinResponse is received.
@@ -391,15 +395,17 @@ export class StreamSfuClient {
391
395
  };
392
396
 
393
397
  updateSubscriptions = async (tracks: TrackSubscriptionDetails[]) => {
394
- await this.joinTask;
395
- return retryable(
396
- (invocationMeta) =>
397
- this.rpc.updateSubscriptions(
398
- { sessionId: this.sessionId, tracks },
399
- { invocationMeta },
400
- ),
401
- this.abortController.signal,
402
- );
398
+ return withoutConcurrency(this.subscriptionsConcurrencyTag, async () => {
399
+ await this.joinTask;
400
+ return retryable(
401
+ (invocationMeta) =>
402
+ this.rpc.updateSubscriptions(
403
+ { sessionId: this.sessionId, tracks },
404
+ { invocationMeta },
405
+ ),
406
+ this.abortController.signal,
407
+ );
408
+ });
403
409
  };
404
410
 
405
411
  setPublisher = async (data: Omit<SetPublisherRequest, 'sessionId'>) => {
@@ -39,6 +39,7 @@ import {
39
39
  getInstanceKey,
40
40
  } from './helpers/clientUtils';
41
41
  import { logToConsole, ScopedLogger, videoLoggerSystem } from './logger';
42
+ import { isReactNative } from './helpers/platforms';
42
43
  import { withoutConcurrency } from './helpers/concurrency';
43
44
  import { enableTimerWorker } from './timers';
44
45
 
@@ -455,7 +456,7 @@ export class StreamVideoClient {
455
456
  clientStore: this.writeableStateStore,
456
457
  });
457
458
  call.state.updateFromCallResponse(c.call);
458
- await call.applyDeviceConfig(c.call.settings, false);
459
+ await call.applyDeviceConfig(c.call.settings, false, isReactNative());
459
460
  if (data.watch) {
460
461
  await call.setup();
461
462
  this.writeableStateStore.registerCall(call);
@@ -44,6 +44,8 @@ export const retryable = async <
44
44
  let result: FinishedUnaryCall<I, O> | undefined = undefined;
45
45
  do {
46
46
  if (attempt > 0) await sleep(retryInterval(attempt));
47
+ if (signal?.aborted) throw new Error(signal.reason);
48
+
47
49
  try {
48
50
  result = await rpc({ attempt });
49
51
  } catch (err) {