For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
CommunitySign Up
HomeGuidesVerbsAPI ReferenceSelf-HostingClient SDKsTutorialsChangelog
HomeGuidesVerbsAPI ReferenceSelf-HostingClient SDKsTutorialsChangelog
    • SDKs
    • WebRTC SDK
    • WebRTC Web Guide
    • WebRTC React Native Guide
    • WebRTC API Reference
    • Node.js SDK
    • Python SDK
    • Node-RED
    • nodeclient
    • nodeclientws
LogoLogo
CommunitySign Up

React Native Guide

Build an iOS + Android softphone with the jambonz WebRTC SDK

Was this page helpful?
Edit this page
Previous

API Reference

Complete API documentation for the jambonz WebRTC SDK
Next
Built with

This guide walks you through building a voice calling app for iOS and Android using React Native.

The SDK works on both simulators/emulators and physical devices. A physical device is recommended for real call testing with audio.

Step 1: Create a React Native Project

$npx @react-native-community/cli init MyJambonzApp
$cd MyJambonzApp

Step 2: Install the SDK

$npm install @jambonz/client-sdk-react-native react-native-webrtc

For iOS:

$cd ios && pod install && cd ..

Step 3: Android Permissions

Add to android/app/src/main/AndroidManifest.xml inside <manifest>:

1<uses-permission android:name="android.permission.INTERNET" />
2<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
3<uses-permission android:name="android.permission.RECORD_AUDIO" />
4<uses-permission android:name="android.permission.CAMERA" />
5<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

Step 4: iOS Permissions

Add to ios/MyJambonzApp/Info.plist:

1<key>NSMicrophoneUsageDescription</key>
2<string>Required for voice calls</string>

Step 5: Connect to the SBC

1// App.tsx
2import React, { useState } from 'react';
3import { View, Text, TextInput, Pressable } from 'react-native';
4import {
5 createJambonzClient,
6 JambonzClient,
7 ClientState,
8} from '@jambonz/client-sdk-react-native';
9
10function App() {
11 const [client, setClient] = useState<JambonzClient | null>(null);
12 const [state, setState] = useState<ClientState>(ClientState.Disconnected);
13
14 const connect = async () => {
15 const c = createJambonzClient({
16 server: 'wss://sbc.example.com:8443',
17 username: 'your-username',
18 password: 'your-password',
19 });
20
21 c.on('stateChanged', (s) => setState(s));
22 c.on('error', (err) => console.log('Error:', err.message));
23
24 await c.connect();
25 setClient(c);
26 };
27
28 return (
29 <View style={{ padding: 40 }}>
30 <Text>Status: {state}</Text>
31 <Pressable onPress={connect}>
32 <Text>Connect</Text>
33 </Pressable>
34 </View>
35 );
36}
37
38export default App;

Run on your device:

$# Android
$npx react-native run-android
$
$# iOS (physical device only)
$npx react-native run-ios --device

Step 6: Make an Outbound Call

1const [call, setCall] = useState(null);
2const [callState, setCallState] = useState(null);
3
4const makeCall = (target: string) => {
5 if (!client) return;
6
7 const newCall = client.call(target);
8 newCall.on('stateChanged', (s) => setCallState(s));
9 newCall.on('ended', () => {
10 setCall(null);
11 setCallState(null);
12 });
13 newCall.on('failed', () => {
14 setCall(null);
15 setCallState(null);
16 });
17
18 setCall(newCall);
19};
20
21// In your JSX:
22<Pressable onPress={() => makeCall('+15551234567')}>
23 <Text>Call</Text>
24</Pressable>
25<Pressable onPress={() => call?.hangup()}>
26 <Text>Hang Up</Text>
27</Pressable>

Step 7: Handle Incoming Calls

Use React Native’s Alert for a simple incoming call prompt:

1import { Alert } from 'react-native';
2
3// After creating the client:
4c.on('incoming', (incomingCall) => {
5 Alert.alert(
6 'Incoming Call',
7 `From: ${incomingCall.remoteIdentity}`,
8 [
9 {
10 text: 'Decline',
11 style: 'destructive',
12 onPress: () => incomingCall.hangup(),
13 },
14 {
15 text: 'Answer',
16 onPress: () => {
17 incomingCall.answer();
18 setCall(incomingCall);
19 // Bind call events...
20 },
21 },
22 ],
23 );
24});

Step 8: Add Call Controls

1const [isMuted, setIsMuted] = useState(false);
2const [isHeld, setIsHeld] = useState(false);
3
4// Bind events on the call:
5newCall.on('mute', (muted) => setIsMuted(muted));
6newCall.on('hold', (held) => setIsHeld(held));
7
8// In your JSX:
9<Pressable onPress={() => call?.toggleMute()}>
10 <Text>{isMuted ? 'Unmute' : 'Mute'}</Text>
11</Pressable>
12<Pressable onPress={() => isHeld ? call?.unhold() : call?.hold()}>
13 <Text>{isHeld ? 'Resume' : 'Hold'}</Text>
14</Pressable>

Step 9: Call Different Targets

1// Call another registered user
2client.callUser('alice');
3
4// Take a call from a queue
5client.callQueue('support');
6
7// Join a conference room
8client.callConference('standup-meeting');
9
10// Call a jambonz application
11client.callApplication('your-app-sid');

Step 10: Using React Hooks (Alternative)

1import { useJambonzClient, useCall } from '@jambonz/client-sdk-react-native';
2
3function Phone() {
4 const client = useJambonzClient({
5 server: 'wss://sbc.example.com:8443',
6 username: 'your-username',
7 password: 'your-password',
8 });
9
10 const call = useCall(client.client);
11
12 return (
13 <View>
14 <Text>Status: {client.state}</Text>
15
16 {!client.isRegistered && (
17 <Pressable onPress={client.connect}>
18 <Text>Connect</Text>
19 </Pressable>
20 )}
21
22 {client.isRegistered && !call.isActive && (
23 <Pressable onPress={() => call.makeCall('+15551234567')}>
24 <Text>Call</Text>
25 </Pressable>
26 )}
27
28 {call.isActive && (
29 <>
30 <Text>Call: {call.state}</Text>
31 <Pressable onPress={call.toggleMute}>
32 <Text>{call.isMuted ? 'Unmute' : 'Mute'}</Text>
33 </Pressable>
34 <Pressable onPress={call.hangup}>
35 <Text>Hang Up</Text>
36 </Pressable>
37 </>
38 )}
39 </View>
40 );
41}

Android Notes

  • JDK 17+ required — install via brew install --cask zulu@17
  • USB debugging must be enabled for physical devices
  • Works on both emulator and physical device

iOS Notes

  • Xcode 15+ required
  • You must configure code signing in Xcode (Signing & Capabilities tab)
  • Add microphone permission in Info.plist
  • Works on both simulator and physical device (physical device recommended for real calls)

Run the Full Example App

The repo includes a complete softphone example with a dark theme UI, DTMF dial pad, incoming call handling, mute/hold/hangup controls.

$# 1. Clone the repo
$git clone https://github.com/jambonz/webrtc-sdk.git
$cd webrtc-sdk
$
$# 2. Install and build the SDK
$npm install
$npm run build
$
$# 3. Install the React Native example
$cd examples/react-native
$npm install
$
$# 4. Generate the native projects
$npx @react-native-community/cli init JambonzExample --directory /tmp/JambonzExample --skip-install
$cp -r /tmp/JambonzExample/android ./android
$cp -r /tmp/JambonzExample/ios ./ios
$rm -rf /tmp/JambonzExample

After generating, add the required permissions:

Android — add to android/app/src/main/AndroidManifest.xml inside <manifest>:

1<uses-permission android:name="android.permission.INTERNET" />
2<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
3<uses-permission android:name="android.permission.RECORD_AUDIO" />
4<uses-permission android:name="android.permission.CAMERA" />
5<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

iOS — add to ios/JambonzExample/Info.plist before </dict>:

1<key>NSMicrophoneUsageDescription</key>
2<string>Required for voice calls</string>

Run on Android

$# Start Metro bundler
$npx react-native start
$
$# In another terminal — run on device or emulator
$npx react-native run-android

Run on iOS

$# Install CocoaPods
$cd ios && pod install && cd ..
$
$# Open Xcode to configure signing
$open ios/JambonzExample.xcworkspace
$# → Select your Team in Signing & Capabilities
$# → Change Bundle Identifier to something unique
$
$# Start Metro bundler
$npx react-native start
$
$# In another terminal — run on device or simulator
$npx react-native run-ios
$# Or for a specific device:
$npx react-native run-ios --device

What the example includes

The example app has clean separation between SDK logic and UI:

  • src/useJambonz.ts — all SDK interactions (connect, call, mute, hold, transfer, incoming calls). Read this file to learn the SDK.
  • src/App.tsx — wires SDK state to UI components
  • src/components/ — reusable UI: ConnectionForm, DialerView, ActiveCallView, IncomingCallView, DtmfPad
  • src/theme.ts — shared color palette

How to use it

  1. Enter your jambonz SBC WebSocket URL (e.g. wss://sbc.example.com:8443)
  2. Enter your SIP username and password
  3. Tap Connect — status dot turns green when registered
  4. Enter a number or SIP target and tap Call
  5. Use the in-call controls: mute, hold, DTMF pad, hang up
  6. Incoming calls show an answer/decline prompt

Source: github.com/jambonz/webrtc-sdk/tree/main/examples/react-native