Built-in Alaznah Calling screens, overlay, controls, and video views.
UI components
Ready-made React Native UI for 1:1 voice and video. Pick one integration style, then wire props from Props.
All UI must sit under CallingProvider. Calling client.startCall() alone does not open a screen — you must mount CallingScreen or CallingUI (or your own screens).
Import paths
Main package — provider, hooks, screens overview, video views, and CallingUI:
import {
CallingProvider,
CallingScreen,
CallingUI,
useCallingClient,
useCall,
useIncomingCall,
useCallingReady,
LocalVideoView,
RemoteVideoView,
VideoView,
} from '@alaznah/calling';UI barrel — lower-level screens, controls, and theme helpers:
import {
IncomingCallScreen,
ActiveCallScreen,
CallControls,
AudioWave,
mergeTheme,
defaultCallingTheme,
} from '@alaznah/calling/ui';| Export | From |
|---|---|
CallingProvider, hooks | @alaznah/calling |
CallingScreen, CallingUI, LocalVideoView, RemoteVideoView, VideoView | @alaznah/calling |
IncomingCallScreen, ActiveCallScreen, CallControls, AudioWave, theme helpers | @alaznah/calling/ui |
Which component should I use?
| Goal | Use |
|---|---|
| Fastest demo / first call | CallingScreen inside CallingProvider |
| Your chat/contacts UI + Alaznah call overlay | CallingUI next to your navigator |
| Fully custom screens | Hooks + IncomingCallScreen / ActiveCallScreen / video views |
Narrative walkthrough: Call UI. Theming & slots: Customization.
1. CallingProvider (required)
Wrap the part of the app that places or receives calls (usually above your navigator):
import {
CallingProvider,
DEFAULT_HOSTED_SIGNALING_URL,
} from '@alaznah/calling';
export function App() {
return (
<CallingProvider
config={{
userId: 'alice',
getAuthToken: () => fetchCallingToken(),
// omit signalingUrl to use Hosted Signaling, or set explicitly:
signalingUrl: DEFAULT_HOSTED_SIGNALING_URL,
}}
>
{/* navigator / screens / CallingUI */}
</CallingProvider>
);
}| Prop | Required | Notes |
|---|---|---|
config | Yes | userId, getAuthToken, optional signalingUrl, … |
autoConnect | No | Default true |
children | Yes | Your app tree |
Full config table: Props · tokens: Authentication.
2. CallingScreen — all-in-one
Dialer + automatic routing between idle / outgoing / incoming / active.
import { CallingProvider, CallingScreen } from '@alaznah/calling';
<CallingProvider config={config}>
<CallingScreen
userId="alice"
defaultPeerId="bob"
// optional:
// pushToken={fcmOrApnsToken}
// pushPlatform="android"
// onError={(e) => console.warn(e)}
/>
</CallingProvider>| Prop | Required | Description |
|---|---|---|
userId | Yes | Same as config.userId |
defaultPeerId | No | Prefills who to call |
pushToken / pushPlatform | No | Registers for background wake |
onLogout / onError | No | App callbacks |
Use this for Quick Start and demos. For a real chat app, prefer CallingUI so dialer stays your UI.
3. CallingUI — overlay for your app
Shows incoming and active call UI as a modal/overlay. Idle = renders nothing (your screens stay visible).
import {
CallingProvider,
CallingUI,
useCallingClient,
useCallingReady,
} from '@alaznah/calling';
function CallingOverlay() {
const client = useCallingClient();
return <CallingUI client={client} onError={(e) => console.warn(e)} />;
}
function Root() {
return (
<CallingProvider config={config}>
<AppNavigator />
<CallingOverlay />
</CallingProvider>
);
}
// Somewhere in chat / contacts:
async function onAudioCall(peerId: string) {
const client = /* useCallingClient() in that screen */;
await client.startCall({ calleeId: peerId, mediaType: 'audio' });
// CallingUI picks up call:updated / incoming automatically
}| Prop | Required | Description |
|---|---|---|
client | Yes | From useCallingClient() |
theme | No | Partial CallingTheme |
backgroundColor / backgroundImage | No | Screen backdrop |
slots | No | Custom avatar / header / controls / overlay |
renderIncomingScreen / renderActiveCallScreen | No | Replace whole screens |
onError | No | Error callback |
What it shows
- Inbound
ringing→IncomingCallScreen(swipe-up accept) - Outbound / connecting / connected →
ActiveCallScreen - No call →
null
4. IncomingCallScreen
Default inbound layout (used by CallingUI / CallingScreen).
- Shows peer id/name treatment + avatar
- Decline = tap red
- Accept = swipe up on green (tap does not accept)
- Video: optional local preview + join-with-video
Prefer CallingUI instead of mounting this alone, so native suppress / drain stay correct — Incoming Calls.
5. ActiveCallScreen
In-call UI for connecting / connected / reconnecting states.
- Voice: avatar + status + controls
- Video: local / remote video layout
- Optional minimize → floating bubble (
MinimizedCallBubble) - On supported Android devices, an active connected video call automatically enters Picture-in-Picture when the user leaves the app (Home / another app). The call continues in the PiP window; tapping it returns to the full calling UI. Voice-only and ringing calls do not enter PiP. Host apps must declare
android:supportsPictureInPicture="true"on the main Activity and forwardonUserLeaveHint/onPictureInPictureModeChangedto the SDK (see the basic-call example).
Usually rendered via CallingUI. Manual use needs call, client, theme, and onEnd.
6. CallControls
Bottom dock: mute, speaker, camera (video), end.
Built into ActiveCallScreen. For a custom layout:
import { CallControls, defaultCallingTheme } from '@alaznah/calling/ui';
<CallControls
call={call}
client={client}
theme={defaultCallingTheme}
onEnd={() => client.end()}
/>7. Video views
import { LocalVideoView, RemoteVideoView } from '@alaznah/calling';
import { useCall } from '@alaznah/calling';
function CustomVideo() {
const call = useCall();
if (!call) return null;
return (
<>
<RemoteVideoView stream={call.remoteStream} objectFit="cover" />
<LocalVideoView stream={call.localStream} mirror objectFit="cover" />
</>
);
}CallingUI / ActiveCallScreen already wire these for the default experience.
8. Hooks used with UI
const client = useCallingClient(); // startCall, accept, end, …
const ready = useCallingReady(); // wait before dialing
const call = useCall(); // active / focused call
const incoming = useIncomingCall(); // ringing inbound (if any)Use useCall() — there is no useActiveCall.
More: Hooks · Client Methods.
Minimal patterns (copy-paste)
A — Demo with dialer
import { CallingProvider, CallingScreen } from '@alaznah/calling';
export default function App() {
return (
<CallingProvider
config={{
userId: 'alice',
getAuthToken: fetchCallingToken,
}}
>
<CallingScreen userId="alice" defaultPeerId="bob" />
</CallingProvider>
);
}B — Chat app + overlay
import { CallingProvider, CallingUI, useCallingClient } from '@alaznah/calling';
function Overlay() {
return <CallingUI client={useCallingClient()} />;
}
export default function App() {
return (
<CallingProvider config={config}>
<ChatNavigator />
<Overlay />
</CallingProvider>
);
}C — Permissions before dial
import { requestCallPermissions } from '@alaznah/calling';
// for audio call
await requestCallPermissions('audio');
await client.startCall({ calleeId: peerId, mediaType: 'audio' });
// for video call
await requestCallPermissions('video');
await client.startCall({ calleeId: peerId, mediaType: 'video' });Related
- Call UI — product overview of the three paths
- Props — full prop tables
- Customization — theme & slots
- Incoming Calls — swipe-up + native wake
- Permissions · Quick Start