Skip to content

Commit ffb86a8

Browse files
authored
fix: set outgoing call active from callingstate (#2172)
### 💡 Overview Outgoing call can start with ways 1. getOrCreate( ring: true ) 2. join(ring: true) we have to start reporting in callkit on 1 itself.. we did only on 2.. this PR fixes that and also we now report that connection is done only after join.. so that we get correct time in callkit
1 parent 5f6e708 commit ffb86a8

5 files changed

Lines changed: 100 additions & 26 deletions

File tree

packages/client/src/Call.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,10 @@ export class Call {
484484
const receiver_id = this.clientStore.connectedUser?.id;
485485
const ended_at = callSession?.ended_at;
486486
const created_by_id = this.state.createdBy?.id;
487+
488+
if (created_by_id === this.currentUserId) {
489+
globalThis.streamRNVideoSDK?.callingX?.registerOutgoingCall(this);
490+
}
487491
const rejected_by = callSession?.rejected_by;
488492
const accepted_by = callSession?.accepted_by;
489493
let leaveCallIdle = false;
@@ -944,7 +948,7 @@ export class Call {
944948
const callingX = globalThis.streamRNVideoSDK?.callingX;
945949
if (callingX) {
946950
// for Android/iOS, we need to start the call in the callingx library as soon as possible
947-
await callingX.startCall(this, this.clientStore.calls);
951+
await callingX.joinCall(this, this.clientStore.calls);
948952
}
949953

950954
await this.setup();

packages/client/src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,11 +425,12 @@ type StreamRNVideoSDKEndCallReason =
425425
| 'unknown';
426426

427427
type StreamRNVideoSDKCallingX = {
428-
startCall: (call: Call, activeCalls: Call[]) => Promise<void>;
428+
joinCall: (call: Call, activeCalls: Call[]) => Promise<void>;
429429
endCall: (
430430
call: Call,
431431
reason?: StreamRNVideoSDKEndCallReason,
432432
) => Promise<void>;
433+
registerOutgoingCall: (call: Call) => Promise<void>;
433434
};
434435

435436
export type StreamRNVideoSDKGlobals = {

packages/react-native-sdk/src/hooks/push/useCallingExpWithCallingStateEffect.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { videoLoggerSystem } from '@stream-io/video-client';
1+
import { Call, CallingState, videoLoggerSystem } from '@stream-io/video-client';
22
import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
33
import { useEffect, useMemo } from 'react';
4+
import { filter, take } from 'rxjs/operators';
45
import { getCallDisplayName } from '../../utils/internal/callingx/callingx';
56
import { getCallingxLibIfAvailable } from '../../utils/push/libs/callingx';
67

@@ -26,6 +27,40 @@ export const useCallingExpWithCallingStateEffect = () => {
2627
[callMembers, participants, currentUserId],
2728
);
2829

30+
useEffect(() => {
31+
const callingx = getCallingxLibIfAvailable();
32+
if (!callingx?.isSetup || !activeCall) {
33+
return;
34+
}
35+
// need to capture RINGING -> Joining -> Joined state change for the first time
36+
// and inform callingx that the call is active
37+
const shouldMakeCallActive = (call: Call): boolean => {
38+
// only for outgoing calls or non-ringing ongoing calls in callingx
39+
// Note: incoming calls are handled by callingx pending states instead
40+
return (
41+
(call.ringing && call.isCreatedByMe) ||
42+
(!call.ringing && callingx.isOngoingCallsEnabled)
43+
);
44+
};
45+
const subscription = activeCall.state.callingState$
46+
.pipe(
47+
filter(
48+
(callingState) =>
49+
shouldMakeCallActive(activeCall) &&
50+
callingState === CallingState.JOINED &&
51+
callingx.isCallTracked(activeCall.cid),
52+
),
53+
take(1), // only need to capture the first joined state for outgoing calls
54+
// then subscription completes and is automatically unsubscribed
55+
)
56+
.subscribe(() => {
57+
callingx.setCurrentCallActive(activeCall.cid);
58+
});
59+
return () => {
60+
subscription.unsubscribe();
61+
};
62+
}, [activeCall]);
63+
2964
useEffect(() => {
3065
return () => {
3166
const callingx = getCallingxLibIfAvailable();

packages/react-native-sdk/src/utils/internal/callingx/callingx.ts

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export function getCallDisplayName(
2121
callMembers: MemberResponse[] | undefined,
2222
participants: StreamVideoParticipant[] | undefined,
2323
currentUserId: string | undefined,
24-
) {
24+
): string {
2525
if (!callMembers || !participants || !currentUserId) {
2626
return 'Call';
2727
}
@@ -53,6 +53,42 @@ export function getCallDisplayName(
5353
return names.sort().join(', ');
5454
}
5555

56+
function getCallDisplayNameFromCall(call: Call): string {
57+
return getCallDisplayName(
58+
call.state.members,
59+
call.state.participants,
60+
call.currentUserId,
61+
);
62+
}
63+
64+
export async function registerOutgoingCall(call: Call) {
65+
if (!CallingxModule || !CallingxModule.isSetup) {
66+
return;
67+
}
68+
69+
const isOutcomingCall = call.ringing && call.isCreatedByMe;
70+
if (!isOutcomingCall) {
71+
return;
72+
}
73+
74+
const logger = videoLoggerSystem.getLogger('callingx');
75+
76+
try {
77+
logger.debug(`registerOutgoingCall: Registering outgoing call ${call.cid}`);
78+
await CallingxModule.startCall(
79+
call.cid, // unique id for call
80+
call.id, // phone number for display in dialer (we use call id as phone number)
81+
getCallDisplayNameFromCall(call), // display name for display in call screen
82+
call.state.settings?.video?.enabled ?? false, // is video call?
83+
);
84+
} catch (error) {
85+
logger.error(
86+
`registerOutgoingCall: Error registering outgoing call in callingx: ${call.cid}`,
87+
error,
88+
);
89+
}
90+
}
91+
5692
/**
5793
* Starts the call in the callingx library.
5894
* It is done by client on every join
@@ -61,7 +97,7 @@ export function getCallDisplayName(
6197
* 2. Displays the incoming call in the callingx library
6298
* 3. Optionally for non-ringing calls also when ongoing calls are enabled.
6399
*/
64-
export async function startCallingxCall(call: Call, activeCalls: Call[]) {
100+
export async function joinCallingxCall(call: Call, activeCalls: Call[]) {
65101
if (!CallingxModule || !CallingxModule.isSetup) {
66102
return;
67103
}
@@ -70,38 +106,31 @@ export async function startCallingxCall(call: Call, activeCalls: Call[]) {
70106
const isOutcomingCall = call.ringing && call.isCreatedByMe;
71107
const isIncomingCall = call.ringing && !call.isCreatedByMe;
72108

73-
const callDisplayName = getCallDisplayName(
74-
call.state.members,
75-
call.state.participants,
76-
call.currentUserId,
77-
);
78-
79109
if (
80-
!CallingxModule.isCallTracked(call.cid) &&
81-
(isOutcomingCall || (!call.ringing && CallingxModule.isOngoingCallsEnabled))
110+
isOutcomingCall ||
111+
(!call.ringing && CallingxModule.isOngoingCallsEnabled)
82112
) {
113+
logger.debug(`joinCallingxCall: Joining call ${call.cid}`);
83114
try {
84115
await CallingxModule.startCall(
85116
call.cid, // unique id for call
86117
call.id, // phone number for display in dialer (we use call id as phone number)
87-
callDisplayName, // display name for display in call screen
118+
getCallDisplayNameFromCall(call), // display name for display in call screen
88119
call.state.settings?.video?.enabled ?? false, // is video call?
89120
);
90121

91122
// Wait for audio session activation on iOS only
92123
if (Platform.OS === 'ios') {
93124
await waitForAudioSessionActivation();
94125
}
95-
96-
// TODO: this must be done after join call is complete
97-
CallingxModule.setCurrentCallActive(call.cid);
98126
} catch (error) {
99127
logger.error(
100128
`startCallingxCall: Error starting call in callingx: ${call.cid}`,
101129
error,
102130
);
103131
}
104132
} else if (isIncomingCall) {
133+
logger.debug(`joinCallingxCall: Joining incoming call ${call.cid}`);
105134
try {
106135
// Leave any existing active ringing calls before joining a new ringing call
107136
const activeCallsToLeave = activeCalls.filter(
@@ -125,7 +154,7 @@ export async function startCallingxCall(call: Call, activeCalls: Call[]) {
125154
await CallingxModule.displayIncomingCall(
126155
call.cid, // unique id for call
127156
call.id, // phone number for display in dialer (we use call id as phone number)
128-
callDisplayName, // display name for display in call screen
157+
getCallDisplayNameFromCall(call), // display name for display in call screen
129158
call.state.settings?.video?.enabled ?? false, // is video call?
130159
);
131160

@@ -152,14 +181,14 @@ export async function endCallingxCall(call: Call, reason?: EndCallReason) {
152181
return;
153182
}
154183

184+
const logger = videoLoggerSystem.getLogger('callingx');
155185
try {
186+
logger.debug(`endCallingxCall: Ending call ${call.cid}`);
156187
await CallingxModule.endCallWithReason(call.cid, reason ?? 'local');
157188
} catch (error) {
158-
videoLoggerSystem
159-
.getLogger('callingx')
160-
.error(
161-
`endCallingxCall: Error ending call in callingx: ${call.cid}`,
162-
error,
163-
);
189+
logger.error(
190+
`endCallingxCall: Error ending call in callingx: ${call.cid}`,
191+
error,
192+
);
164193
}
165194
}

packages/react-native-sdk/src/utils/internal/registerSDKGlobals.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { StreamRNVideoSDKGlobals } from '@stream-io/video-client';
22
import { NativeModules, PermissionsAndroid, Platform } from 'react-native';
33
import { getCallingxLibIfAvailable } from '../push/libs/callingx';
4-
import { endCallingxCall, startCallingxCall } from './callingx/callingx';
4+
import {
5+
endCallingxCall,
6+
registerOutgoingCall,
7+
joinCallingxCall,
8+
} from './callingx/callingx';
59

610
const StreamInCallManagerNativeModule = NativeModules.StreamInCallManager;
711
const StreamVideoReactNativeModule = NativeModules.StreamVideoReactNative as {
@@ -38,8 +42,9 @@ const shouldBypassForCallKit = ({
3842

3943
const streamRNVideoSDKGlobals: StreamRNVideoSDKGlobals = {
4044
callingX: {
41-
startCall: startCallingxCall,
45+
joinCall: joinCallingxCall,
4246
endCall: endCallingxCall,
47+
registerOutgoingCall: registerOutgoingCall,
4348
},
4449
callManager: {
4550
setup: ({ defaultDevice, isRingingTypeCall }) => {

0 commit comments

Comments
 (0)