@stream-io/video-client 1.4.5 → 1.4.6

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/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ### [1.4.6](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.4.5...@stream-io/video-client-1.4.6) (2024-07-25)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * allow joining left call instances ([#1448](https://github.com/GetStream/stream-video-js/issues/1448)) ([2f72300](https://github.com/GetStream/stream-video-js/commit/2f72300f9377eac774516cee3366c28e99840425)), closes [#1433](https://github.com/GetStream/stream-video-js/issues/1433)
11
+ * allow reusing call instances after leaving ([#1433](https://github.com/GetStream/stream-video-js/issues/1433)) ([61e05af](https://github.com/GetStream/stream-video-js/commit/61e05af25c441b7db9db16166a6b4eca20ec7748))
12
+
5
13
  ### [1.4.5](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.4.4...@stream-io/video-client-1.4.5) (2024-07-12)
6
14
 
7
15
 
@@ -6535,7 +6535,7 @@ function getIceCandidate(candidate) {
6535
6535
  }
6536
6536
  }
6537
6537
 
6538
- const version = "1.4.5" ;
6538
+ const version = "1.4.6" ;
6539
6539
  const [major, minor, patch] = version.split('.');
6540
6540
  let sdkInfo = {
6541
6541
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -12484,6 +12484,8 @@ class Call {
12484
12484
  this.reconnectAttempts = 0;
12485
12485
  this.maxReconnectAttempts = 10;
12486
12486
  this.isLeaving = false;
12487
+ this.initialized = false;
12488
+ this.joinLeaveConcurrencyTag = Symbol('joinLeaveConcurrencyTag');
12487
12489
  /**
12488
12490
  * A list hooks/functions to invoke when the call is left.
12489
12491
  * A typical use case is to clean up some global event handlers.
@@ -12535,59 +12537,61 @@ class Call {
12535
12537
  * Leave the call and stop the media streams that were published by the call.
12536
12538
  */
12537
12539
  this.leave = async ({ reject = false, reason = 'user is leaving the call', } = {}) => {
12538
- const callingState = this.state.callingState;
12539
- if (callingState === CallingState.LEFT) {
12540
- throw new Error('Cannot leave call that has already been left.');
12541
- }
12542
- if (callingState === CallingState.JOINING) {
12543
- await this.assertCallJoined();
12544
- }
12545
- this.isLeaving = true;
12546
- if (this.ringing) {
12547
- // I'm the one who started the call, so I should cancel it.
12548
- const hasOtherParticipants = this.state.remoteParticipants.length > 0;
12549
- if (this.isCreatedByMe &&
12550
- !hasOtherParticipants &&
12551
- callingState === CallingState.RINGING) {
12552
- // Signals other users that I have cancelled my call to them
12553
- // before they accepted it.
12554
- await this.reject();
12540
+ await withoutConcurrency(this.joinLeaveConcurrencyTag, async () => {
12541
+ const callingState = this.state.callingState;
12542
+ if (callingState === CallingState.LEFT) {
12543
+ throw new Error('Cannot leave call that has already been left.');
12555
12544
  }
12556
- else if (reject && callingState === CallingState.RINGING) {
12557
- // Signals other users that I have rejected the incoming call.
12558
- await this.reject();
12545
+ if (callingState === CallingState.JOINING) {
12546
+ await this.assertCallJoined();
12559
12547
  }
12560
- }
12561
- this.statsReporter?.stop();
12562
- this.statsReporter = undefined;
12563
- this.sfuStatsReporter?.stop();
12564
- this.sfuStatsReporter = undefined;
12565
- this.subscriber?.close();
12566
- this.subscriber = undefined;
12567
- this.publisher?.close();
12568
- this.publisher = undefined;
12569
- this.sfuClient?.close(StreamSfuClient.NORMAL_CLOSURE, reason);
12570
- this.sfuClient = undefined;
12571
- this.dispatcher.offAll();
12572
- this.state.setCallingState(CallingState.LEFT);
12573
- // Call all leave call hooks, e.g. to clean up global event handlers
12574
- this.leaveCallHooks.forEach((hook) => hook());
12575
- this.clientStore.unregisterCall(this);
12576
- this.camera.dispose();
12577
- this.microphone.dispose();
12578
- this.screenShare.dispose();
12579
- this.speaker.dispose();
12580
- const stopOnLeavePromises = [];
12581
- if (this.camera.stopOnLeave) {
12582
- stopOnLeavePromises.push(this.camera.disable(true));
12583
- }
12584
- if (this.microphone.stopOnLeave) {
12585
- stopOnLeavePromises.push(this.microphone.disable(true));
12586
- }
12587
- if (this.screenShare.stopOnLeave) {
12588
- stopOnLeavePromises.push(this.screenShare.disable(true));
12589
- }
12590
- await Promise.all(stopOnLeavePromises);
12548
+ this.isLeaving = true;
12549
+ if (this.ringing) {
12550
+ // I'm the one who started the call, so I should cancel it.
12551
+ const hasOtherParticipants = this.state.remoteParticipants.length > 0;
12552
+ if (this.isCreatedByMe &&
12553
+ !hasOtherParticipants &&
12554
+ callingState === CallingState.RINGING) {
12555
+ // Signals other users that I have cancelled my call to them
12556
+ // before they accepted it.
12557
+ await this.reject();
12558
+ }
12559
+ else if (reject && callingState === CallingState.RINGING) {
12560
+ // Signals other users that I have rejected the incoming call.
12561
+ await this.reject();
12562
+ }
12563
+ }
12564
+ this.statsReporter?.stop();
12565
+ this.statsReporter = undefined;
12566
+ this.sfuStatsReporter?.stop();
12567
+ this.sfuStatsReporter = undefined;
12568
+ this.subscriber?.close();
12569
+ this.subscriber = undefined;
12570
+ this.publisher?.close();
12571
+ this.publisher = undefined;
12572
+ this.sfuClient?.close(StreamSfuClient.NORMAL_CLOSURE, reason);
12573
+ this.sfuClient = undefined;
12574
+ this.state.setCallingState(CallingState.LEFT);
12575
+ // Call all leave call hooks, e.g. to clean up global event handlers
12576
+ this.leaveCallHooks.forEach((hook) => hook());
12577
+ this.initialized = false;
12578
+ this.clientStore.unregisterCall(this);
12579
+ this.camera.dispose();
12580
+ this.microphone.dispose();
12581
+ this.screenShare.dispose();
12582
+ this.speaker.dispose();
12583
+ const stopOnLeavePromises = [];
12584
+ if (this.camera.stopOnLeave) {
12585
+ stopOnLeavePromises.push(this.camera.disable(true));
12586
+ }
12587
+ if (this.microphone.stopOnLeave) {
12588
+ stopOnLeavePromises.push(this.microphone.disable(true));
12589
+ }
12590
+ if (this.screenShare.stopOnLeave) {
12591
+ stopOnLeavePromises.push(this.screenShare.disable(true));
12592
+ }
12593
+ await Promise.all(stopOnLeavePromises);
12594
+ });
12591
12595
  };
12592
12596
  /**
12593
12597
  * Loads the information about the call.
@@ -12597,6 +12601,7 @@ class Call {
12597
12601
  * @param params.members_limit the total number of members to return as part of the response.
12598
12602
  */
12599
12603
  this.get = async (params) => {
12604
+ await this.setup();
12600
12605
  const response = await this.streamClient.get(this.streamClientBasePath, params);
12601
12606
  if (params?.ring && !this.ringing) {
12602
12607
  this.ringingSubject.next(true);
@@ -12617,6 +12622,7 @@ class Call {
12617
12622
  * @param data the data to create the call with.
12618
12623
  */
12619
12624
  this.getOrCreate = async (data) => {
12625
+ await this.setup();
12620
12626
  const response = await this.streamClient.post(this.streamClientBasePath, data);
12621
12627
  if (data?.ring && !this.ringing) {
12622
12628
  this.ringingSubject.next(true);
@@ -12681,14 +12687,12 @@ class Call {
12681
12687
  * @returns a promise which resolves once the call join-flow has finished.
12682
12688
  */
12683
12689
  this.join = async (data) => {
12690
+ await this.setup();
12684
12691
  const callingState = this.state.callingState;
12685
12692
  if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
12686
12693
  this.logger('warn', 'Join method called twice, you should only call this once');
12687
12694
  throw new Error(`Illegal State: Already joined.`);
12688
12695
  }
12689
- if (callingState === CallingState.LEFT) {
12690
- throw new Error('Illegal State: Cannot join already left call. Create a new Call instance to join a call.');
12691
- }
12692
12696
  const isMigrating = callingState === CallingState.MIGRATING;
12693
12697
  const isReconnecting = callingState === CallingState.RECONNECTING;
12694
12698
  this.state.setCallingState(CallingState.JOINING);
@@ -13822,20 +13826,31 @@ class Call {
13822
13826
  this.state.setMembers(members || []);
13823
13827
  this.state.setOwnCapabilities(ownCapabilities || []);
13824
13828
  this.state.setCallingState(ringing ? CallingState.RINGING : CallingState.IDLE);
13825
- this.on('all', (event) => {
13826
- // update state with the latest event data
13827
- this.state.updateFromEvent(event);
13828
- });
13829
- this.leaveCallHooks.add(registerEventHandlers(this, this.state, this.dispatcher));
13830
- this.registerEffects();
13831
- this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$1((v) => v.data)), (subscriptions) => this.sfuClient?.updateSubscriptions(subscriptions).catch((err) => {
13832
- this.logger('debug', `Failed to update track subscriptions`, err);
13833
- })));
13834
13829
  this.camera = new CameraManager(this);
13835
13830
  this.microphone = new MicrophoneManager(this);
13836
13831
  this.speaker = new SpeakerManager(this);
13837
13832
  this.screenShare = new ScreenShareManager(this);
13838
13833
  }
13834
+ async setup() {
13835
+ await withoutConcurrency(this.joinLeaveConcurrencyTag, async () => {
13836
+ if (this.initialized) {
13837
+ return;
13838
+ }
13839
+ this.leaveCallHooks.add(this.on('all', (event) => {
13840
+ // update state with the latest event data
13841
+ this.state.updateFromEvent(event);
13842
+ }));
13843
+ this.leaveCallHooks.add(registerEventHandlers(this, this.state, this.dispatcher));
13844
+ this.registerEffects();
13845
+ this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$1((v) => v.data)), (subscriptions) => this.sfuClient?.updateSubscriptions(subscriptions).catch((err) => {
13846
+ this.logger('debug', `Failed to update track subscriptions`, err);
13847
+ })));
13848
+ if (this.state.callingState === CallingState.LEFT) {
13849
+ this.state.setCallingState(CallingState.IDLE);
13850
+ }
13851
+ this.initialized = true;
13852
+ });
13853
+ }
13839
13854
  registerEffects() {
13840
13855
  this.leaveCallHooks.add(
13841
13856
  // handles updating the permissions context when the settings change.
@@ -15521,7 +15536,7 @@ class StreamClient {
15521
15536
  });
15522
15537
  };
15523
15538
  this.getUserAgent = () => {
15524
- const version = "1.4.5" ;
15539
+ const version = "1.4.6" ;
15525
15540
  return (this.userAgent ||
15526
15541
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
15527
15542
  };