@stream-io/video-client 1.4.5 → 1.4.7
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 +15 -0
- package/dist/index.browser.es.js +128 -75
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +128 -75
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +128 -75
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +3 -0
- package/package.json +1 -1
- package/src/Call.ts +146 -96
- package/src/__tests__/Call.test.ts +114 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
### [1.4.7](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.4.6...@stream-io/video-client-1.4.7) (2024-07-30)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* ringing state issues when call was already ended ([#1451](https://github.com/GetStream/stream-video-js/issues/1451)) ([4a3556e](https://github.com/GetStream/stream-video-js/commit/4a3556e0f7b0bd58d0022cc635aa4391014063d7))
|
|
11
|
+
|
|
12
|
+
### [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)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* 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)
|
|
18
|
+
* 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))
|
|
19
|
+
|
|
5
20
|
### [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
21
|
|
|
7
22
|
|
package/dist/index.browser.es.js
CHANGED
|
@@ -6535,7 +6535,7 @@ function getIceCandidate(candidate) {
|
|
|
6535
6535
|
}
|
|
6536
6536
|
}
|
|
6537
6537
|
|
|
6538
|
-
const version = "1.4.
|
|
6538
|
+
const version = "1.4.7" ;
|
|
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
|
-
|
|
12539
|
-
|
|
12540
|
-
|
|
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
|
-
|
|
12557
|
-
|
|
12558
|
-
await this.reject();
|
|
12545
|
+
if (callingState === CallingState.JOINING) {
|
|
12546
|
+
await this.assertCallJoined();
|
|
12559
12547
|
}
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
12568
|
-
|
|
12569
|
-
|
|
12570
|
-
|
|
12571
|
-
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12576
|
-
|
|
12577
|
-
|
|
12578
|
-
|
|
12579
|
-
|
|
12580
|
-
|
|
12581
|
-
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
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,13 +12601,15 @@ 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
|
-
if (params?.ring && !this.ringing) {
|
|
12602
|
-
this.ringingSubject.next(true);
|
|
12603
|
-
}
|
|
12604
12606
|
this.state.updateFromCallResponse(response.call);
|
|
12605
12607
|
this.state.setMembers(response.members);
|
|
12606
12608
|
this.state.setOwnCapabilities(response.own_capabilities);
|
|
12609
|
+
if (params?.ring || this.ringing) {
|
|
12610
|
+
// the call response can indicate where the call is still ringing or not
|
|
12611
|
+
this.ringingSubject.next(true);
|
|
12612
|
+
}
|
|
12607
12613
|
if (this.streamClient._hasConnectionID()) {
|
|
12608
12614
|
this.watching = true;
|
|
12609
12615
|
this.clientStore.registerCall(this);
|
|
@@ -12617,13 +12623,15 @@ class Call {
|
|
|
12617
12623
|
* @param data the data to create the call with.
|
|
12618
12624
|
*/
|
|
12619
12625
|
this.getOrCreate = async (data) => {
|
|
12626
|
+
await this.setup();
|
|
12620
12627
|
const response = await this.streamClient.post(this.streamClientBasePath, data);
|
|
12621
|
-
if (data?.ring && !this.ringing) {
|
|
12622
|
-
this.ringingSubject.next(true);
|
|
12623
|
-
}
|
|
12624
12628
|
this.state.updateFromCallResponse(response.call);
|
|
12625
12629
|
this.state.setMembers(response.members);
|
|
12626
12630
|
this.state.setOwnCapabilities(response.own_capabilities);
|
|
12631
|
+
if (data?.ring || this.ringing) {
|
|
12632
|
+
// the call response can indicate where the call is still ringing or not
|
|
12633
|
+
this.ringingSubject.next(true);
|
|
12634
|
+
}
|
|
12627
12635
|
if (this.streamClient._hasConnectionID()) {
|
|
12628
12636
|
this.watching = true;
|
|
12629
12637
|
this.clientStore.registerCall(this);
|
|
@@ -12681,14 +12689,12 @@ class Call {
|
|
|
12681
12689
|
* @returns a promise which resolves once the call join-flow has finished.
|
|
12682
12690
|
*/
|
|
12683
12691
|
this.join = async (data) => {
|
|
12692
|
+
await this.setup();
|
|
12684
12693
|
const callingState = this.state.callingState;
|
|
12685
12694
|
if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
|
|
12686
12695
|
this.logger('warn', 'Join method called twice, you should only call this once');
|
|
12687
12696
|
throw new Error(`Illegal State: Already joined.`);
|
|
12688
12697
|
}
|
|
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
12698
|
const isMigrating = callingState === CallingState.MIGRATING;
|
|
12693
12699
|
const isReconnecting = callingState === CallingState.RECONNECTING;
|
|
12694
12700
|
this.state.setCallingState(CallingState.JOINING);
|
|
@@ -13822,20 +13828,31 @@ class Call {
|
|
|
13822
13828
|
this.state.setMembers(members || []);
|
|
13823
13829
|
this.state.setOwnCapabilities(ownCapabilities || []);
|
|
13824
13830
|
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
13831
|
this.camera = new CameraManager(this);
|
|
13835
13832
|
this.microphone = new MicrophoneManager(this);
|
|
13836
13833
|
this.speaker = new SpeakerManager(this);
|
|
13837
13834
|
this.screenShare = new ScreenShareManager(this);
|
|
13838
13835
|
}
|
|
13836
|
+
async setup() {
|
|
13837
|
+
await withoutConcurrency(this.joinLeaveConcurrencyTag, async () => {
|
|
13838
|
+
if (this.initialized) {
|
|
13839
|
+
return;
|
|
13840
|
+
}
|
|
13841
|
+
this.leaveCallHooks.add(this.on('all', (event) => {
|
|
13842
|
+
// update state with the latest event data
|
|
13843
|
+
this.state.updateFromEvent(event);
|
|
13844
|
+
}));
|
|
13845
|
+
this.leaveCallHooks.add(registerEventHandlers(this, this.state, this.dispatcher));
|
|
13846
|
+
this.registerEffects();
|
|
13847
|
+
this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$1((v) => v.data)), (subscriptions) => this.sfuClient?.updateSubscriptions(subscriptions).catch((err) => {
|
|
13848
|
+
this.logger('debug', `Failed to update track subscriptions`, err);
|
|
13849
|
+
})));
|
|
13850
|
+
if (this.state.callingState === CallingState.LEFT) {
|
|
13851
|
+
this.state.setCallingState(CallingState.IDLE);
|
|
13852
|
+
}
|
|
13853
|
+
this.initialized = true;
|
|
13854
|
+
});
|
|
13855
|
+
}
|
|
13839
13856
|
registerEffects() {
|
|
13840
13857
|
this.leaveCallHooks.add(
|
|
13841
13858
|
// handles updating the permissions context when the settings change.
|
|
@@ -13914,11 +13931,47 @@ class Call {
|
|
|
13914
13931
|
createSubscription(this.ringingSubject, (isRinging) => {
|
|
13915
13932
|
if (!isRinging)
|
|
13916
13933
|
return;
|
|
13917
|
-
this.
|
|
13918
|
-
|
|
13919
|
-
|
|
13934
|
+
const callSession = this.state.session;
|
|
13935
|
+
const receiver_id = this.clientStore.connectedUser?.id;
|
|
13936
|
+
const endedAt = this.state.endedAt;
|
|
13937
|
+
const created_by_id = this.state.createdBy?.id;
|
|
13938
|
+
const rejected_by = callSession?.rejected_by;
|
|
13939
|
+
const accepted_by = callSession?.accepted_by;
|
|
13940
|
+
let leaveCallIdle = false;
|
|
13941
|
+
if (endedAt) {
|
|
13942
|
+
// call was ended before it was accepted or rejected so we should leave it to idle
|
|
13943
|
+
leaveCallIdle = true;
|
|
13944
|
+
}
|
|
13945
|
+
else if (created_by_id && rejected_by) {
|
|
13946
|
+
if (rejected_by[created_by_id]) {
|
|
13947
|
+
// call was cancelled by the caller
|
|
13948
|
+
leaveCallIdle = true;
|
|
13949
|
+
}
|
|
13950
|
+
}
|
|
13951
|
+
else if (receiver_id && rejected_by) {
|
|
13952
|
+
if (rejected_by[receiver_id]) {
|
|
13953
|
+
// call was rejected by the receiver in some other device
|
|
13954
|
+
leaveCallIdle = true;
|
|
13955
|
+
}
|
|
13956
|
+
}
|
|
13957
|
+
else if (receiver_id && accepted_by) {
|
|
13958
|
+
if (accepted_by[receiver_id]) {
|
|
13959
|
+
// call was accepted by the receiver in some other device
|
|
13960
|
+
leaveCallIdle = true;
|
|
13961
|
+
}
|
|
13962
|
+
}
|
|
13963
|
+
if (leaveCallIdle) {
|
|
13964
|
+
if (this.state.callingState !== CallingState.IDLE) {
|
|
13965
|
+
this.state.setCallingState(CallingState.IDLE);
|
|
13966
|
+
}
|
|
13967
|
+
}
|
|
13968
|
+
else {
|
|
13969
|
+
this.scheduleAutoDrop();
|
|
13970
|
+
if (this.state.callingState === CallingState.IDLE) {
|
|
13971
|
+
this.state.setCallingState(CallingState.RINGING);
|
|
13972
|
+
}
|
|
13973
|
+
this.leaveCallHooks.add(registerRingingCallEventHandlers(this));
|
|
13920
13974
|
}
|
|
13921
|
-
this.leaveCallHooks.add(registerRingingCallEventHandlers(this));
|
|
13922
13975
|
}));
|
|
13923
13976
|
}
|
|
13924
13977
|
/**
|
|
@@ -15521,7 +15574,7 @@ class StreamClient {
|
|
|
15521
15574
|
});
|
|
15522
15575
|
};
|
|
15523
15576
|
this.getUserAgent = () => {
|
|
15524
|
-
const version = "1.4.
|
|
15577
|
+
const version = "1.4.7" ;
|
|
15525
15578
|
return (this.userAgent ||
|
|
15526
15579
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
15527
15580
|
};
|