await client.call("default", "test-outgoing-call").getOrCreate({
ring: true,
data: {
members: [{ user_id: "myself" }, { user_id: "my friend" }],
},
});
Ringing calls
The Call
object provides several options to ring and notify users about a call.
Create call
To create a ring call, we need to set the ring
flag to true
and provide the list of members we want to call.
It is important to note that the caller should also be included in the list of members.
Call creation options
The following options are supported when creating a call:
Option | Description | Default |
---|---|---|
members | A list of members to add to this call. You can specify the role and custom data on these members | - |
custom | Any custom data you want to store | - |
settings | You can overwrite certain call settings for this specific call. This overwrites the call type standard settings | - |
startsAt | When the call will start. Used for calls scheduled in the future, livestreams, audio rooms etc | - |
team | Restrict the access to this call to a specific team | - |
ring | If you want the call to ring for each member | false |
notify | If you want the call to notify each member by sending push notification. | false |
This step will start the signaling flow. The caller will automatically join the call once the first callee accepts the call. The call will automatically stop if every callee rejects the call.
When ring
is true
, a push notification will be sent to the members, provided their app have the required setup.
For more details around push notifications, please check this page.
Watch for incoming and outgoing calls
The easiest way to watch for incoming and outgoing calls is to use the useCalls
hook and the RingingCallContent
component.
Important: Make sure that the ringing calls are watched in the root component of your app. This makes sure that in whichever screen the user is in, or if the app was opened from a push notification it is shown. Below is an example of how to watch for ringing calls in the root component of your App.
import { SafeAreaView, StyleSheet } from "react-native";
import {
StreamCall,
StreamVideo,
useCalls,
RingingCallContent,
StreamVideoClient,
User,
} from "@stream-io/video-react-native-sdk";
const user: User = {
id: "sara",
};
const apiKey = "<STREAM-API-KEY>";
const tokenProvider = () => Promise.resolve("<USER-TOKEN>");
const client = StreamVideoClient.getOrCreateInstance({
apiKey,
tokenProvider,
user,
});
const RingingCalls = () => {
// filter for ringing calls
const calls = useCalls().filter((c) => c.ringing);
const call = calls[0];
if (!call) return null;
return (
<StreamCall call={call}>
<SafeAreaView style={StyleSheet.absoluteFill}>
<RingingCallContent />
</SafeAreaView>
</StreamCall>
);
};
const App = () => {
return (
<StreamVideo client={client}>
{/* MyApp - your parent navigator or equivalent */}
<MyApp />
<RingingCalls />
</StreamVideo>
);
};
export default App;
In the above example, the component RingingCalls
renders over the rest of the App whenever there is a incoming or outgoing call. Alternatively you can use a Modal view or Dialog to show there is a ringing call over the rest of your app.
Optional: Adding ringing sound to incoming and outgoing call UIs
If push notifications are setup, ringing sound is already added via the notifications. However, if you do not use push notifications please see the snippet below on how to add the sounds.
import {
useCallStateHooks,
CallingState,
useCall,
RingingCallContent,
} from "@stream-io/video-react-native-sdk";
const RingingSound = () => {
const call = useCall();
const isCallCreatedByMe = call?.isCreatedByMe;
const { useCallingState } = useCallStateHooks();
const callingState = useCallingState();
useEffect(() => {
if (callingState === CallingState.RINGING) {
if (isCallCreatedByMe) {
// TODO: play outgoing call sound
} else {
// TODO: play incoming call sound
}
return () => {
// TODO: stop the ringing sound here
};
}
}, [callingState, isCallCreatedByMe]);
// renderless component
return null;
};
// ... later add the above component anywhere below StreamCall
<StreamCall call={call}>
<RingingSound />
<SafeAreaView style={StyleSheet.absoluteFill}>
<RingingCallContent />
</SafeAreaView>
</StreamCall>;
Canceling an outgoing call
A caller can cancel an outgoing call until the first callee accepts the call. Canceling a call will stop the signaling flow.
await call.leave({ reject: true, reason: "cancel" });
Please note that calling call.leave()
after joining the call won’t stop the signaling flow.
Rejecting an incoming call
A callee can accept or reject an incoming call. To reject the call:
await call.leave({ reject: true, reason: "decline" });
Accepting a call
A callee can accept or reject an incoming call. To accept and join the call:
await call.join();
Please note that it’s possible to join multiple calls. If you only want to allow one active call, you must leave joined calls before accepting an incoming call.
Leave call
To leave a joined call, you can use the leave
method:
await call.leave();
End call
Ending a call requires a special permission. This action terminates the call for everyone.
await call.endCall();
Notifying
In some cases, you just want to notify users that you joined a call, instead of ringing.
To do this, you should use the notify
option:
await call.getOrCreate({ notify: true });
When notify is true, a regular push notification will be sent to all the members. This can be useful for livestreams apps or huddles.
Similarly to ringing, you can use the get method if you are sure that the call exists:
await call.get({ notify: true });