Skip to main content

You are looking at Interactive Live Streaming v3.x Docs. The newest version is  Interactive Live Streaming 4.x

Android
iOS
macOS
Windows C++
Windows C#
Unity
Flutter
React Native
Electron
Cocos Creator
Cocos2d-x

Start Interactive Live Audio Streaming

This article describes how to create a simple Cocos2d-x project and integrate the Agora Voice SDK to build an Android or iOS app with the basic live audio streaming function.

Understand the tech

The following figure shows the workflow to integrate into your app in order to add Interactive Live Streaming Premium functionality.

1625465916613

As shown in the figure, the workflow for adding Interactive Live Streaming Premium in your project is as follows:

  1. Set the client role Each user in an Interactive Live Streaming Premium channel is either a host or an audience member. Hosts publish streams to the channel, and the audience subscribe to the streams.

  2. Retrieve a token A token is the credential that authenticates a user when your app client joins a channel. In a test or production environment, your app client retrieves tokens from a server in your security infrastructure.

  3. Join a channel Call joinChannel to create and join a channel. App clients that pass the same channel name join the same channel.

  4. Publish and subscribe to audio and video in the channel After joining a channel, app clients with the role of the host can publish audio and video. For an auidence memeber to send audio and video, you can call setClientRole to switch the client role.

For an app client to join a channel, you need the following information:

  • The App ID: A randomly generated string provided by Agora for identifying your app. You can get the App ID from Agora Console.
  • The user ID: The unique identifier of a user. You need to specify the user ID yourself, and ensure that it is unique in the channel.
  • A token: In a test or production environment, your app client retrieves tokens from a server in your security infrastructure. For this page, you use a temporary token with a validity period of 24 hours that you retrieve from Agora Console.
  • The channel name: A string that identifies the channel for the live stream.

Prerequisites

Development environment

  • Cocos2d-x 3.0 or later.
  • Python 2.7.5 or later. (Cocos2d-x does not support Python 3 or later.)
  • For Android:
    • Android Studio 3.0 or later.
    • NDK r18b or later.
    • cmake.
  • For iOS:
    • Xcode 9.0 or later.

Deployment environment

  • For Android:A mobile device running Android 4.1 or later.
  • For iOS: A mobile device running iOS 9.0 or later. Agora recommends you run this sample project on a physical mobile device, as some simulators may not support the full features of this project.
This article uses Cocos2d-x 3.17.2 as an example. For more information about the environment requirements, see Cococ2d-x installation prerequisites. If you use Cocos2d-x 4.0 or later, please refer to the Cocos documentation to upgrade from v3 to v4.

Other Prerequisites

A valid Agora account.

If your network has a firewall, follow the instructions in Firewall Requirements to access Agora services.

Create a Cocos2d-x project

This section describes how to use the Cocos2d-x command line tool to create a new project.

This article uses Cocos2d-x 3.17.2 as an example.
  1. Go to the Cocos2d-x download page, select a version of Cocos2d-x, and then download it.

  2. Extract the files from the downloaded package, and run the setup.py script in the root directory to set the environmental variables.

    You can run cocos -v in the terminal to check whether the Cocos2d-x command line tool is set up correctly. You should see the following output if the setup is correct:

    cocos2d-x-3.17.2
    Cocos Console 2.3
    Copy
  3. Use the cocos new command to create a new project:

    cocos new <game name> -p <package identifier> -l <language> -d <location>
    Copy

    Where:

    • <game name>: Sets the project name.

    • -p <package identifier>: Sets the package name of the project. The package name should be in the format of com.MyCompany.MyGame, for example, io.agora.gaming.cocos2d.

    • -l <language>: Sets the programming language used by the project. Optional values include cpp, lua, and js.

      To integrate the Agora SDK, the <language> parameter must be set as cpp.

    • -d <location>: Sets the directory of the project.

On Windows, Agora recommends that you set the directory as the root directory of your working disk to shorten the project path; otherwise, the build of Android project may fail because the project path is too long.
For more information about creating a new project using the cocos new command, see the documentation for the Cocos command line tool.

Integrate the Agora Voice SDK

Follow these steps to integrate the Agora SDK into your project:

  1. Go to SDK Downloads, download the latest version of the Agora Voice SDK, and extract the files from the downloaded SDK package.

  2. Create an sdk folder in your project root directory for the Agora Voice SDK. You can create the folder and add subfolders in the following structure:

└─sdk
├─android
│ ├─agora
│ └─lib
└─ios
└─agora
Copy

You can also place the Agora Voice SDK in other paths of your project, but then you need to replace the ./sdk/android/agora or ./sdk/ios/agora path in all configuration files with your path for the Agora Voice SDK.
3.

  • For Android: Copy the following files or subfolders from the audio/libs/android folder of the downloaded SDK package to the path of your project:

    File or subfolderPath of your project
    agora-rtc-sdk.jar file./sdk/android/lib
    arm64-v8a folder./sdk/android/agora
    armeabi-v7a folder./sdk/android/agora
    include folder./sdk/android/agora
    x86_64 folder./sdk/android/agora
    x86 folder./sdk/android/agora
  • For iOS: Copy the following dynamic libraries from the audio/libs/ios folder of the downloaded SDK package to ./sdk/ios/agora of your project:

    • AgoraRtcKit.framework
    • Agorafdkaac.framework
    • Agoraffmpeg.framework
    • AgoraSoundTouch.framework
    For iOS, if you need to support a simulator, then copy the above dynamic libraries from the audio/libs/ios/ALL_ARCHITECTURE folder to ./sdk/ios/agora of your project instead.
    The dynamic libraries under this path contains the x86-64 architecture, which affects the distribution of your app in the App Store. Therefore, you need to remove the x86-64 architecture in the libraries before uploading the app to the App Store.
  1. (For Android only) Add the configuration of the .so libraries to the build files. You can choose any of the following methods:
  • Method one: If you use cmake as the build tool, that is, you set PROP_BUILD_TYPE=cmake in the ./proj.android/gradle.properties file, do the following:

    a. Add the following code to the CMakeLists.txt file in the project root directory:

    else()
    add_library(${APP_NAME} SHARED ${all_code_files})
    add_subdirectory(${COCOS2DX_ROOT_PATH}/cocos/platform/android ${ENGINE_BINARY_PATH}/cocos/platform)
    target_link_libraries(${APP_NAME} -Wl,--whole-archive cpp_android_spec -Wl,--no-whole-archive)
    // Add the following four lines:
    add_library(agora-rtc-sdk SHARED IMPORTED)
    set_target_properties(agora-rtc-sdk PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/sdk/android/agora/${ANDROID_ABI}/libagora-rtc-sdk.so)
    include_directories(${CMAKE_CURRENT_SOURCE_DIR}/sdk/android/agora/include/)
    target_link_libraries(${APP_NAME} agora-rtc-sdk)
    endif()
    Copy

    b. Add the following code after assets.srcDir "../../Resources" in the proj.android/app/build.gradle file to include the .so libraries:

    sourceSets.main {
    java.srcDir "src"
    res.srcDir "res"
    manifest.srcFile "AndroidManifest.xml"
    assets.srcDir "../../Resources"
    // Add the following two lines to include the .so libraries:
    if (PROP_BUILD_TYPE == 'cmake') {
    jniLibs.srcDirs "../../sdk/android/agora"
    }
    }
    ...
    dependencies {
    // Add the following dependencies:
    implementation fileTree(dir: '../../sdk/android/lib', include: ['*.jar'])
    implementation project(':libcocos2dx')
    implementation 'androidx.annotation:annotation:1.1.0'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    }
    Copy
  • Method two: If you use ndk-build as the build tool, that is, you set PROP_BUILD_TYPE=ndk-build in the ./proj.android/gradle.properties file, and then add the following code to the ./proj.android/app/jni/Android.mk file:

    LOCAL_PATH := $(call my-dir)
    // Add the following four lines to specify the source files for the shared libraries.
    include $(CLEAR_VARS)
    LOCAL_MODULE := agora-rtc-sdk
    LOCAL_SRC_FILES := $(LOCAL_PATH)/../../../sdk/android/agora/$(TARGET_ARCH_ABI)/libagora-rtc-sdk.so
    include $(PREBUILT_SHARED_LIBRARY)
    include $(CLEAR_VARS)
    LOCAL_MODULE := MyGame_shared
    LOCAL_MODULE_FILENAME := libMyGame
    LOCAL_SRC_FILES := $(LOCAL_PATH)/hellocpp/main.cpp \
    $(LOCAL_PATH)/../../../Classes/AppDelegate.cpp \
    $(LOCAL_PATH)/../../../Classes/HelloWorldScene.cpp \
    LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../Classes \
    // Add the following line to add ./sdk/android/agora/include to the include search path.
    $(LOCAL_PATH)/../../../sdk/android/agora/include
    # _COCOS_HEADER_ANDROID_BEGIN
    # _COCOS_HEADER_ANDROID_END
    LOCAL_STATIC_LIBRARIES := cc_static
    // Add the following line to link agora-rtc-sdk.
    LOCAL_SHARED_LIBRARIES := agora-rtc-sdk
    # _COCOS_LIB_ANDROID_BEGIN
    # _COCOS_LIB_ANDROID_END
    include $(BUILD_SHARED_LIBRARY)
    $(call import-module, cocos)
    # _COCOS_LIB_IMPORT_ANDROID_BEGIN
    # _COCOS_LIB_IMPORT_ANDROID_END
    Copy
    If you choose ndk-build, you do not need to set jniLibs.srcDirs, as ndk-build will automatically include the .so libraries.

Add project permissions

  • For Android: Add the following permissions in the ./proj.android/app/AndroidManifest.xml file for device access according to your needs:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="io.agora.gaming.cocos2d"
    android:installLocation="auto">


    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    // Add the following permission if your scenario involves reading the external storage:
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    // For devices running Android 10.0 or later, you also need to add the following permission:
    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />

    ...
    </manifest>
    Copy
  • For iOS: Add the following permissions in the ./proj.ios_mac/ios/info.plist file for device access according to your needs:

    <key>NSMicrophoneUsageDescription</key>
    <string>Microphone</string>
    Copy

Get the device permission (Android only)

Add the following code in ./proj.android/app/src/org/cocos2dx/cpp/AppActivity.java to access the microphone of the Android device when launching the activity:

// Add the import of the following files:
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.List;

public class AppActivity extends Cocos2dxActivity {
// Load the agora-rtc-sdk .so library.
static {
System.loadLibrary("agora-rtc-sdk");
}

private final static int REQUEST_CODE = 200;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.setEnableVirtualButton(false);
super.onCreate(savedInstanceState);

// Ask for Android device permissions at runtime.
String[] needPermissions = {Manifest.permission.RECORD_AUDIO};
checkAndRequestAppPermission(this, needPermissions);
}

private void checkAndRequestAppPermission(@NonNull Activity activity, String[] permissions) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
List<String> permissionList = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED)
permissionList.add(permission);
}
if (permissionList.size() == 0) return;
String[] requestPermissions = permissionList.toArray(new String[0]);
activity.requestPermissions(requestPermissions, AppActivity.REQUEST_CODE);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
builder.append(permissions[i]);
builder.append(" ");
}
}
if (builder.length() > 0) {
builder.append("not permitted!");
Toast.makeText(this, builder.toString(), Toast.LENGTH_SHORT).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
Copy

Implement interactive live audio streaming

Now you can call the core APIs provided by the Agora Voice SDK to implement basic interactive live audio streaming.

1. Import classes and add declarations

Add the following code in HelloWorldScene.h to import classes and add declarations of variables and functions:

  1. Import AgoraRtcKit and IAgoraRtcEngine classes.

    #ifdef __APPLE__
    #include <AgoraRtcKit/IAgoraRtcEngine.h>
    #elif __ANDROID__
    #include "IAgoraRtcEngine.h"
    #endif
    Copy
  2. Define App ID and token. To create and initialize an IRtcEngine object, you need to pass in the App ID of your Agora project. See Get an App ID for details. To ensure communication security, you need to use tokens (dynamic keys) to authenticate users joining a channel.

    // Replace <#YOUR APP ID#> with the App ID of your Agora project and add quotation marks, such as "xxxxxx".
    #define AGORA_APP_ID <#YOUR APP ID#>
    // Replace <#YOUR TOKEN#> with your token and add quotation marks, such as "xxxxxxx".
    #define AGORA_TOKEN <#YOUR TOKEN#>
    Copy
  3. Add function declarations.

    class HelloWorld : public cocos2d::Scene {
    public:
    static cocos2d::Scene *createScene();

    bool init() override;
    // Occur when a user enters the HelloWorld scene.
    void onEnter() override;
    // Occur when a user exits the HelloWorld scene.
    void onExit() override;

    ...

    private:
    // Occur when a user clicks the join-channel button.
    void onJoinChannelClicked();
    // Occur when a user clicks the leave-channel button.
    void onLeaveChannelClicked();

    private:
    cocos2d::ui::EditBox *editBox;
    agora::rtc::IRtcEngine *engine;
    agora::rtc::IRtcEngineEventHandler *eventHandler;
    std::map<uid_t, bool> users;
    };
    Copy

2. Create the UI

Create the user interface (UI) for live audio streaming.

We recommend adding the following elements into the UI:

  • A channel name edit box
  • A join-channel button
  • A leave-channel button

In the Agora sample project Cocos2d-x, the code for creating the UI elements and handling the button click events is as follows:

  • The channel name edit box

    // Create an edit box to get the channel name entered by the user.
    // You need to add the TextBox.png image to the ./Resources folder.
    auto editBox = cocos2d::ui::EditBox::create(Size(120, 30), "TextBox.png");
    if (editBox==nullptr) {
    problemLoading("'TextBox.png'");
    } else {
    editBox->setPlaceHolder("Channel ID");
    editBox->setPosition(Vec2(origin.x + leftPadding + editBox->getContentSize().width/2,
    origin.y + visibleSize.height
    - editBox->getContentSize().height*1.5f));
    this->addChild(editBox, 0);
    }
    Copy
  • The join-channel button

    // Create a join-channel button. Clicking this button triggers the onJoinChannelClicked() function.
    // You need to add the Button.png and ButtonPressed.png images to the ./Resources folder.
    auto joinButton =
    cocos2d::ui::Button::create("Button.png", "ButtonPressed.png", "ButtonPressed.png");
    if (joinButton==nullptr) {
    problemLoading("'Button.png' and 'ButtonPressed.png'");
    } else {
    joinButton->setTitleText("Join Channel");

    joinButton->setPosition(Vec2(origin.x + leftPadding + joinButton->getContentSize().width/2,
    origin.y + visibleSize.height
    - 1*joinButton->getContentSize().height
    - 2*editBox->getContentSize().height));

    joinButton->addTouchEventListener([&](cocos2d::Ref *sender, ui::Widget::TouchEventType type) {
    switch (type) {
    case ui::Widget::TouchEventType::BEGAN:break;
    case ui::Widget::TouchEventType::ENDED:onJoinChannelClicked();
    break;
    default:break;
    }
    });

    this->addChild(joinButton, 0);
    }
    Copy
  • The leave-channel button

    // Create a leave-channel button. Clicking this button triggers the onLeaveChannelClicked() function.
    auto leaveButton = ui::Button::create("Button.png", "ButtonPressed.png", "ButtonPressed.png");
    if (leaveButton==nullptr) {
    problemLoading("'Button.png' and 'ButtonPressed.png'");
    } else {
    leaveButton->setTitleText("Leave Channel");

    leaveButton->setPosition(Vec2(origin.x + leftPadding + leaveButton->getContentSize().width/2,
    origin.y + visibleSize.height
    - 2*leaveButton->getContentSize().height
    - 2*editBox->getContentSize().height));

    leaveButton->addTouchEventListener([&](cocos2d::Ref *sender, ui::Widget::TouchEventType type) {
    switch (type) {
    case ui::Widget::TouchEventType::BEGAN:break;
    case ui::Widget::TouchEventType::ENDED:onLeaveChannelClicked();
    break;
    default:break;
    }
    });

    this->addChild(leaveButton, 0);
    }
    Copy

3. Initialize IRtcEngine

Create and initialize the IRtcEngine object before calling any other Agora APIs. Call the createAgoraRtcEngine and initialize methods, and pass in your App ID to initialize the IRtcEngine object.

class MyIGamingRtcEngineEventHandler : public agora::rtc::IRtcEngineEventHandler {
private:
HelloWorld *mUi;

public:
explicit MyIGamingRtcEngineEventHandler(HelloWorld *ui) : mUi(ui) {}
// Listen for the onJoinChannelSuccess callback.
// This callback occurs when the local user successfully joins the channel.
void onJoinChannelSuccess(const char *channel, uid_t uid, int elapsed) override {
}

// Listen for the onLeaveChannel callback.
// This callback occurs when the local user leaves the channel.
void onLeaveChannel(const agora::rtc::RtcStats &stats) override {
}
};

...

void HelloWorld::onEnter() {
cocos2d::Scene::onEnter();
eventHandler = new MyIGamingRtcEngineEventHandler(this);
// Create an IRtcEngine object.
engine = createAgoraRtcEngine();
// Define RtcEngineContext.
agora::rtc::RtcEngineContext context;
context.appId = AGORA_APP_ID;
context.eventHandler = eventHandler;
// Initialize the IRtcEngine object.
engine->initialize(context);
}
Copy

4. Set the channel profile

After initializing the IRtcEngine object, call setChannelProfile to set the channel profile as LIVE_BROADCASTING.

One IRtcEngine object uses one profile only. If you want to switch to another profile, release the current IRtcEngine object with the release method and create a new one before calling the setChannelProfile method.

void HelloWorld::onJoinChannelClicked() {
if (editBox == nullptr || strlen(editBox->getText()) == 0) {
return;
}
// Set the channel profile as live streaming.
engine->setChannelProfile(agora::rtc::CHANNEL_PROFILE_LIVE_BROADCASTING);
...
}
Copy

5. Set the user role

An interactive streaming channel has two client roles: BROADCASTER and AUDIENCE; and the default role is AUDIENCE. After setting the channel profile to LIVE_BROADCASTING, your app may use the following steps to set the client role:

  • Allow the user to set the role as BROADCASTER or AUDIENCE.
  • Call setClientRole and pass in the client role set by the user.

Note that during the interactive live audio streaming, only the host can be heard. If you want to switch the client role after joining the channel, call the setClientRole method.

void HelloWorld::onJoinChannelClicked() {
if (editBox == nullptr || strlen(editBox->getText()) == 0) {
return;
}
...
// Set the usr role as host.
engine->setClientRole(agora::rtc::CLIENT_ROLE_BROADCASTER);
...
}
Copy

6. Join a channel

After setting the client role, you can call joinChannel, pass in a token, channel name, and user ID to join a channel.

void HelloWorld::onJoinChannelClicked() {
if (editBox == nullptr || strlen(editBox->getText()) == 0) {
return;
}
...
// Pass in your token and channel name to join the channel.
// Set uid as 0, and the SDK assigns a user ID for the local user.
engine->joinChannel(AGORA_TOKEN, editBox->getText(), "Cocos2d", 0);
}
Copy
Once the user joins the channel, the user subscribes to the audio streams of all the other users in the channel by default, giving rise to usage and billing calculation. If you do not want to subscribe to a specified stream or all remote streams, call the mute methods accordingly.

7. Leave the channel

Call the leaveChannel method to leave the current live streaming according to your scenario.

void HelloWorld::onLeaveChannelClicked() { engine->leaveChannel(); }
Copy

8. Release IRtcEngine

if you want to release the memory of the Agora engine when exiting the HelloWorld scene, call release to destroy the Agora engine.

void HelloWorld::onExit() {
Node::onExit();
agora::rtc::IRtcEngine::release(true);
engine = nullptr;
delete eventHandler;
eventHandler = nullptr;
}
Copy

Run the project

For Android:

  1. Enable Developer options and USB Debugging on your Android device, and then connect it to your computer using a USB cable.
  2. Open the Cocos2d-x/proj.android folder with Android Studio.
  3. Select File > Project Structure > SDK Location, fill in the local path of your NDK under Android NDK Location, and then click Apply > OK.
  4. Click Sync Project with Gradle Files.
  5. After the Gradle synchronization finishes, click Build and run.

For iOS:

  1. Open Cocos2d-x/proj.ios_mac/Hello-Cocos2d-Agora.xcodeproj with Xcode.
  2. Connect your iOS device to your computer using a USB cable.
  3. Click the Build and run button in Xcode.

When the interactive live audio streaming starts successfully, audience members can hear the voice of hosts in the app.

See also

Agora provides an open-source Agora-Cocos-Quickstart/Cocos2d-x sample project on GitHub that implements a basic voice call. You can refer to this sample project and the sample code in this article to implement the interactive live audio streaming.

Interactive Live Streaming