Skip to main content

Quickstart

This page provides a step-by-step guide on how to create a basic Voice Calling app using the Agora Voice SDK.

Understand the tech

To start a Voice Calling session, implement the following steps in your app:

  • Initialize the Agora Engine: Before calling other APIs, create and initialize an Agora Engine instance.

  • Join a channel: Call methods to create and join a channel.

  • Send and receive audio: All users can publish streams to the channel and subscribe to audio streams published by other users in the channel.

Video calling workflow

Prerequisites

  • React Native 0.60 or later. For more information, see Setting up the development environment.
  • Node 16 or later
  • The following, depending on your target platform:
    • A machine running macOS, Windows, or Linux
    • Java Development Kit (JDK) 11 or later
    • Latest version of Android Studio
    • A physical or virtual mobile device running Android 5.0 or later
  • A microphone

Set up your project

This section shows you how to set up your React Native project and install the Agora Voice SDK.

Create a project

To create a new application using React Native Community CLI, see Get Started Without a Framework.

Install the SDK

Download and add the Agora Voice SDK to your React Native project. Choose either of the following methods:

In your project folder, execute the following command:

npm i --save react-native-agora
Information
React Native 0.60.0 and later support automatic linking of native modules. Manual linking is not recommended. See Autolinking for details

Implement Voice Calling

This section guides you through the implementation of basic real-time audio interaction in your app.

The following figure illustrates the essential steps:

Quick start sequence

This guide includes complete sample code that demonstrates implementing basic real-time interaction. To understand the core API calls in the sample code, review the following implementation steps and use the code in your App.tsx file.

Import dependencies

Add the required Agora dependencies to your app.

import {
createAgoraRtcEngine,
ChannelProfileType,
ClientRoleType,
IRtcEngine,
RtcConnection,
IRtcEngineEventHandler,
} from 'react-native-agora';
Copy

Initialize the engine

For real-time communication, call createAgoraRtcEngine to create an RtcEngine instance, and then initialize the engine using RtcEngineContext to specify the App ID.

const appId = '<-- Insert app ID -->';

const setupVoiceSDKEngine = async () => {
if (Platform.OS === 'android') { await getPermission(); }
agoraEngineRef.current = createAgoraRtcEngine();
const agoraEngine = agoraEngineRef.current;
await agoraEngine.initialize({ appId: appId });
};
Copy

Join a channel

To join a channel, call joinChannel with the following parameters:

  • Channel name: The name of the channel to join. Clients that pass the same channel name join the same channel. If a channel with the specified name does not exist, it is created when the first user joins.

  • Authentication token: A dynamic key that authenticates a user when the client joins a channel. In a production environment, you obtain a token from a token server in your security infrastructure. For the purpose of this guide Generate a temporary token.

  • User ID: A 32-bit signed integer that identifies a user in the channel. You can specify a unique user ID for each user yourself. If you set the user ID to 0 when joining a channel, the SDK generates a random number for the user ID and returns the value in the onJoinChannelSuccess callback.

  • Channel media options: Configure ChannelMediaOptions to define publishing and subscription settings, optimize performance for your specific use-case, and set optional parameters.

For Voice Calling, set the channelProfile to ChannelProfileCommunication and the clientRoleType to ClientRoleBroadcaster.

const token = '<-- Insert token -->';
const channelName = '<-- Insert channel name -->';
const localUid = 0; // Local user UID, no need to modify

// Define the join method called after clicking the join channel button
const join = async () => {
if (isJoined) {
return;
}
// Join the channel as a broadcaster
agoraEngineRef.current?.joinChannel(token, channelName, localUid, {
// Set channel profile to live broadcast
channelProfile: ChannelProfileType.ChannelProfileCommunication,
// Set user role to broadcaster
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
// Publish audio collected by the microphone
publishMicrophoneTrack: true,
// Automatically subscribe to all audio streams
autoSubscribeAudio: true,
});
};
Copy
info

Since the Agora Engine runs locally, reloading the app using the Metro bundler may cause the engine reference to be lost, preventing channel joining. To resolve this issue, restart the app.

Subscribe to Voice SDK events

The Voice SDK provides an interface for subscribing to channel events. To use it, create an instance of IRtcEngineEventHandler and implement the event methods you want to handle. Call registerEventHandler to register your custom event handler.

const [remoteUid, setRsemoteUid] = useState(0); // Uid of the remote user

const setupEventHandler = () => {
eventHandler.current = {
// Triggered when the local user successfully joins a channel
onJoinChannelSuccess: () => {
setMessage('Successfully joined channel: ' + channelName);
setIsJoined(true);
},
// Triggered when a remote user joins the channel
onUserJoined: (_connection: RtcConnection, uid: number) => {
setMessage('Remote user ' + uid + ' joined');
setRemoteUid(uid);
},
// Triggered when a remote user leaves the channel
onUserOffline: (_connection: RtcConnection, uid: number) => {
setMessage('Remote user ' + uid + ' left the channel');
setRemoteUid(uid);
},
};
// Register the event handler
agoraEngineRef.current?.registerEventHandler(eventHandler.current);
};
Copy
info

To ensure that you receive all Voice SDK events, register the event handler before joining a channel.

Handle permissions

To access the microphone, ensure that the user grants the necessary permissions when the app starts.

On Android devices, pop up a prompt box to obtain permission to use the microphone.

// Import components related to Android device permissionsimport {PermissionsAndroid, Platform} from 'react-native';const getPermission = async () => {    if (Platform.OS === 'android') {        await PermissionsAndroid.requestMultiple([            PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,        ]);    }};

Leave the channel

To exit a Voice Calling channel, call leaveChannel.

const leave = () => {
// Leave the channel
agoraEngineRef.current?.leaveChannel();
setIsJoined(false);
};
Copy

Clean up resources

Before closing your app, unregister the event handler and call release to free up resources.

const cleanupAgoraEngine = () => {
return () => {
agoraEngineRef.current?.unregisterEventHandler(eventHandler.current!);
agoraEngineRef.current?.release();
};
};
Copy
info

After calling release, methods and callbacks of the SDK are no longer available. To use the SDK functions again, create a new engine instance.

Complete sample code

A complete code sample demonstrating the basic process of real-time interaction is provided for your reference. To use the sample code, copy the code into ProjectName/App.tsx to quickly implement the basic functionality.

Complete sample code for real-time Voice Calling
// Import React Hooksimport React, { useRef, useState, useEffect } from 'react';// Import user interface elementsimport {    SafeAreaView,    StyleSheet,    Text,    View,} from 'react-native';// Import components related to obtaining Android device permissionsimport { PermissionsAndroid, Platform } from 'react-native';// Import Agora SDKimport {    createAgoraRtcEngine,    ChannelProfileType,    ClientRoleType,    IRtcEngine,    RtcConnection,    IRtcEngineEventHandler,} from 'react-native-agora';// Define basic informationconst appId = '<-- Insert App ID -->';const token = '<-- Insert Token -->';const channelName = '<-- Insert Channel Name -->';const localUid = 0; // Local user Uid, no need to modifyconst App = () => {    const agoraEngineRef = useRef<IRtcEngine>(); // IRtcEngine instance    const [isJoined, setIsJoined] = useState(false); // Whether the local user has joined the channel    const [remoteUid, setRemoteUid] = useState(0); // Uid of the remote user    const [message, setMessage] = useState(''); // User prompt message    const eventHandler = useRef<IRtcEngineEventHandler>(); // Implement callback functions    useEffect(() => {        const init = async () => {            await setupVoiceSDKEngine();            setupEventHandler();        };        init();        return () => {            cleanupAgoraEngine(); // Ensure this is synchronous        };    }, []); // Empty dependency array ensures it runs only once    const setupEventHandler = () => {        eventHandler.current = {            onJoinChannelSuccess: () => {                setMessage('Successfully joined channel: ' + channelName);                setIsJoined(true);            },            onUserJoined: (_connection: RtcConnection, uid: number) => {                setMessage('Remote user ' + uid + ' joined');                setRemoteUid(uid);            },            onUserOffline: (_connection: RtcConnection, uid: number) => {                setMessage('Remote user ' + uid + ' left the channel');                setRemoteUid(uid);            },        };        agoraEngineRef.current?.registerEventHandler(eventHandler.current);    };    const setupVoiceSDKEngine = async () => {        try {            if (Platform.OS === 'android') { await getPermission(); }            agoraEngineRef.current = createAgoraRtcEngine();            const agoraEngine = agoraEngineRef.current;            await agoraEngine.initialize({ appId: appId });        } catch (e) {            console.error(e);        }    };    // Define the join method called after clicking the join channel button    const join = async () => {        if (isJoined) {            return;        }        try {            // Join the channel as a broadcaster            agoraEngineRef.current?.joinChannel(token, channelName, localUid, {                // Set channel profile to live broadcast                channelProfile: ChannelProfileType.ChannelProfileCommunication,                // Set user role to broadcaster                clientRoleType: ClientRoleType.ClientRoleBroadcaster,                // Publish audio collected by the microphone                publishMicrophoneTrack: true,                // Automatically subscribe to all audio streams                autoSubscribeAudio: true,            });        } catch (e) {            console.log(e);        }    };    // Define the leave method called after clicking the leave channel button    const leave = () => {        try {            // Call leaveChannel method to leave the channel            agoraEngineRef.current?.leaveChannel();            setRemoteUid(0);            setIsJoined(false);            showMessage('Left the channel');        } catch (e) {            console.log(e);        }    };    const cleanupAgoraEngine = () => {        return () => {            agoraEngineRef.current?.unregisterEventHandler(eventHandler.current!);            agoraEngineRef.current?.release();        };    };    // Render user interface    return (        <SafeAreaView style={styles.main}>            <Text style={styles.head}>Agora Voice SDK Quickstart</Text>            <View style={styles.btnContainer}>                <Text onPress={join} style={styles.button}>                    Join Channel                </Text>                <Text onPress={leave} style={styles.button}>                    Leave Channel                </Text>            </View>            {isJoined ? (                <Text>You joined</Text>            ) : (                <Text>Join a channel</Text>            )}            {isJoined && remoteUid !== 0 ? (                <Text>{remoteUid} joined</Text>            ) : (                <Text>{isJoined ? 'Waiting for remote user to join' : ''}</Text>            )}            <View style={styles.messageContainer}>                <Text style={styles.info}>{message}</Text>            </View>            </SafeAreaView>    );    // Display information    function showMessage(msg: string) {        setMessage(msg);    }};const styles = StyleSheet.create({    button: {        paddingHorizontal: 25,        paddingVertical: 4,        fontWeight: 'bold',        color: '#ffffff',        backgroundColor: '#0055cc',        margin: 5,    },    main: {        flex: 1,        alignItems: 'center',    },    btnContainer: {        flexDirection: 'row',        justifyContent: 'center',    },    head: {        fontSize: 20,    },    messageContainer: {        position: 'absolute',        bottom: 20,        left: 0,        right: 0,        alignItems: 'center',    },    info: {        backgroundColor: '#ffffe0',        paddingHorizontal: 8,        paddingVertical: 4,        color: '#0000ff',        textAlign: 'center',    },});const getPermission = async () => {    if (Platform.OS === 'android') {        await PermissionsAndroid.requestMultiple([            PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,        ]);    }};export default App;

Create a user interface

Design a user interface for your project based on your application use-case. Add Join channel and Leave channel buttons to enable the user to join and leave a channel. To create such an interface, refer to the following code:

Sample code to create the user interface
// Import React Hooksimport React, { useState } from 'react';// Import user interface elementsimport {    SafeAreaView,    StyleSheet,    Text,    View,} from 'react-native';const localUid = 0; // Local user Uid, no need to modifyconst App = () => {    const [isJoined, setIsJoined] = useState(false); // Whether the local user has joined the channel    const [remoteUid, setRemoteUid] = useState(0); // Uid of the remote user    const [message, setMessage] = useState(''); // User prompt message    // Render user interface    return (        <SafeAreaView style={styles.main}>            <Text style={styles.head}>Agora Voice SDK Quickstart</Text>            <View style={styles.btnContainer}>                <Text onPress={join} style={styles.button}>                    Join Channel                </Text>                <Text onPress={leave} style={styles.button}>                    Leave Channel                </Text>            </View>            {isJoined ? (                <Text>You joined</Text>            ) : (                <Text>Join a channel</Text>            )}            {isJoined && remoteUid !== 0 ? (                <Text>{remoteUid} joined</Text>            ) : (                <Text>{isJoined ? 'Waiting for remote user to join' : ''}</Text>            )}            <View style={styles.messageContainer}>                <Text style={styles.info}>{message}</Text>            </View>            </SafeAreaView>    );};const styles = StyleSheet.create({    button: {        paddingHorizontal: 25,        paddingVertical: 4,        fontWeight: 'bold',        color: '#ffffff',        backgroundColor: '#0055cc',        margin: 5,    },    main: {        flex: 1,        alignItems: 'center',    },    btnContainer: {        flexDirection: 'row',        justifyContent: 'center',    },    head: {        fontSize: 20,    },    messageContainer: {        position: 'absolute',        bottom: 20,        left: 0,        right: 0,        alignItems: 'center',    },    info: {        backgroundColor: '#ffffe0',        paddingHorizontal: 8,        paddingVertical: 4,        color: '#0000ff',        textAlign: 'center',    },});export default App;

Test the sample code

Take the following steps to test the sample code:

  1. Update the values for appId, token, and channelName in your code.

  2. Run the app.

    Caution
    Some simulators may not support all the functions of this project. Best practice is to run the project on a physical device.

    To run the app on an Android device:

    1. Turn on the developer options of the Android device and connect the Android device to the computer through a USB cable.

    2. In the project root directory, execute npx react-native run-android.

    Information
    For detailed steps on running the app on a real Android or iOS device, please refer to Running On Device.
  3. Launch the app and click the Join channel button to join a channel.

  1. Invite a friend to install and run the app on a second device. Alternatively, use the Web demo to join the same channel. Once your friend joins the channel, you can talk to each other.

Reference

This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

  • If a firewall is deployed in your network environment, refer to Connect with Cloud Proxy to use Agora services normally.

Next steps

After implementing the quickstart sample, read the following documents to learn more:

  • To ensure communication security in a test or production environment, best practice is to obtain and use a token from an authentication server. For details, see Secure authentication with tokens.