Talk to us
Talk to us
menu

How to Implement a Live Audio Room

How to Implement a Live Audio Room

In today’s fast-paced digital landscape, live audio rooms have emerged as a dynamic platform for real-time interaction, fostering connections, and engaging audiences in innovative ways. A live audio room is a virtual space where participants can join in and share their voices, creating an immersive experience that transcends traditional text-based communication. These rooms are becoming increasingly popular for various purposes, from hosting discussions and interviews to facilitating workshops and networking events.

Implementing a live audio room not only enhances user engagement but also provides an opportunity for brands, creators, and communities to cultivate a loyal following. In this blog, you will explore the essential steps to set up a live audio room and discuss the key features that make it effective based on ZEGOCLOUD Video Chat and In-app Chat . Join us as we uncover the potential of live audio rooms and guide you through the process of bringing your own to life!

Before You Start

Before you begin, make sure:

  • You have created a project in ZEGOCLOUD Console, and get the valid AppID and AppSign. For details, please refer to Admin Console – How to view project information.
  • You have downloaded the demo.
  • Your project has integrated ZEGO Express SDK , and your project has implemented basic real-time audio and video features. For details, please refer to Quick Start.
  • Your project has activated the In-app Chat service.
In-app Chat Service Activation

Preview the Effect You Can Achieve with This Demo

You can achieve the following effect with the demo provided in this doc:

Using the demo provided in this document, you can achieve the following results:

Home pageHost pageAudience pageAudience taps the speaker seatHost check the requests
Home Page  - Live Audio RoomHost Page  - Live Audio RoomAudience Page  - Live Audio RoomAudience taps the speaker seat  - Live Audio RoomHost check the requests  - Live Audio Room

The host can tap the Lock icon on the lower right to change the room mode.

  • Free mode: Audience became the speaker once click the speaker seat.
  • Request mode: Auidence has to wait for the host to agree with the seat-taking request that is triggered by clicking the speaker seat.

How Does It Work?

The usage of basic SDK functions has been introduced by Quick start. If you are not familiar with the concept of stream publishing/playing, please read the document carefully again.

In a live audio room:

  • All the audience can start playing streams after entering the room to listen to the speakers on the speaker seat in the room.
  • Speaker starts publishing streams after they are on the speaker seat to transmit local audio to the audience in the room.

How to manage speaker seats

In addition to implementing the above logic, the live audio room also needs to manage speaker seats. The speaker seat management function can usually be implemented using the room attribute feature of the ZIM SDK.

This feature allows app clients to set and synchronize custom room attributes in the room. Room attributes are stored on the ZEGOCLOUD server in a Key-Value manner, and the ZEGOCLOUD server handles write conflict arbitration and other issues to ensure data consistency.

At the same time, modifications made by app clients to room attributes are synchronized to all other audiences in the room in real time through the ZEGOCLOUD server.

Each room allows a maximum of 20 attributes to be set, with a key length limit of 16 bytes and a value length limit of 1024 bytes.

Taking Alice takes speaker seat as an example, the process is as follows:

Live Audio Room Sequence Diagram

Using Room Attributes to represent Speaker Seats:

You can use the speaker seat number in the live audio room as the key of the room attribute and use userID as the value of the room attribute to represent the speaker seat status of the room.

For example, if the user with userID “user123” is on the No.0 speaker seat and the user with userID “user456” is on the No.1 speaker seat, then the room attribute is represented as follows:

{
  "0":"user123", // Indicates te user123 is on the NO.0 speaker seat 
  "1":"user456", // Indicates te user456 is on the NO.1 speaker seat 
}

The design of the room attribute feature can solve some common problems in speaker seat management in live audio room scenario:

FeatureDescriptionUsage
OwnerThe first audience to set a key will become the owner of that key. By default, the key can only be modified by the owner.Can be used to avoid conflicts when grabbing the speaker seat.
Automatic DeletionWhen setting KV, the key can be configured as “automatically deleted after the owner leaves the room”.Can be used to achieve the function of “automatic update of speaker seat when speaker gets offline”, avoiding the problem of speaker seat disorder due to app client disconnection.
Forced ModificationSupports ignoring the owner and forcefully modifying KV.Can be used to achieve the function of “Host forcefully remove the audience from speaker seat”. 
Combined OperationsMultiple operations on different KVs can be combined into one combined operation to avoid conflicts caused by other users operating related KVs.Can be used to achieve the function of changing the speaker seat.

How to manage room mode

In the live audio room app, you may need to support the host to modify the room mode:

  1. Free mode: Audience became the speaker once click the speaker seat.
  2. Request mode: Auidence has to wait for the host to agree with the seat-taking request that is triggered by clicking the speaker seat.

The room mode is implemented using the setRoomExtraInfo. RoomExtraInfo is similar to the above RoomAttribute, also stored on the ZEGOCLOUD server, but the usage of RoomExtraInfo is simpler:
There are no complex parameters, only support for setting a key-value string (key maximum 10 bytes, value maximum 128 bytes), which is more suitable for simple business operations bound to the room, such as room mode, room announcements, etc.

You can encapsulate any business field into the JSON protocol and set it to RoomExtraInfo to implement business logic such as room mode.

When the host calls the setRoomExtraInfo method, the in-room users can receive the set RoomExtraInfo via onRoomExtraInfoUpdate.

Room Mode Management Sequence Diagram

How to request to take a speaker seat using roomrequest

What is roomrequest?

The process of co-hosting seat-taking request implemented based on roomrequest, roomrequest is a protocol or message to manage communication and connections in networks. ZEGOCLOUD packages all roomrequest capabilities into a SDK, providing you with a readily available real-time roomrequest API.

How to send & receive roomrequest messages through the ZIM SDK interface

The ZIM SDK provides rich functionality for sending and receiving messages, see Send & Receive messages (roomrequest). And here, you will need to use the customizable roomrequest message: ZIMCommandMessage

Complete demo code for this section can be found at ZIMService.java.

1. Send RoomRequests (ZIMCommandMessage) in the room by calling sendMessage with the following:

zim.sendMessage(commandMessage, mRoomID, ZIMConversationType.ROOM, config, new ZIMMessageSentCallback() {
    // ...
    @Override
    public void onMessageSent(ZIMMessage message, ZIMError errorInfo) {
        // ...
    }
});

2. After sending, other users in the room will receive the RoomRequest from the onReceiveRoomMessage callback. You can listen to this callback by following below:

zim.setEventHandler(new ZIMEventHandler() {
    @Override
    public void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromRoomID) {
        super.onReceiveRoomMessage(zim, messageList, fromRoomID);

        // ...
    }
});

How to customize business RoomRequests

Complete demo code for this section can be found at ZIMService.java and RoomRequest.java.

JSON RoomRequest encoding

Since a simple String itself is difficult to express complex information, RoomRequests can be encapsulated in JSON format, making it more convenient for you to organize the protocol content of the RoomRequests.

Taking the simplest JSON RoomRequest as an example: {"action_type": 0}, in such a JSON RoomRequest, you can use the action_type field to express different RoomRequest types, such as:

  • Sending a request: {"action_type": RoomRequestAction.ACTION_REQUEST}
  • Canceling a request: {"action_type": RoomRequestAction.ACTION_CANCEL}
  • Accepting a request: {"action_type": RoomRequestAction.ACTION_ACCEPT}
  • Rejecting a request: {"action_type": RoomRequestAction.ACTION_REJECT}

In addition, you can also extend other common fields for RoomRequests, such as senderIDreceiverID,extended_data:

public class RoomRequest {

    // ...
    public String toString() {
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("action_type", actionType);
            jsonObject.put("sender_id", sender);
            jsonObject.put("receiver_id", receiver);
            jsonObject.put("extended_data", extendedData);
            jsonObject.put("request_id", requestID);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        return jsonObject.toString();
    }

    // ...
}

public @interface RoomRequestAction {
    int ACTION_REQUEST = 0;
    int ACTION_ACCEPT = 1;
    int ACTION_REJECT = 2;
    int ACTION_CANCEL = 3;
}

JSON RoomRequest decoding

And users who receive RoomRequests can decode the JSON RoomRequest and know and process specific business logic based on the fields in it, such as:

zim.setEventHandler(new ZIMEventHandler() {
    @Override
    public void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromRoomID) {
        super.onReceiveRoomMessage(zim, messageList, fromRoomID);

        zimRoomService.onReceiveRoomMessage(zim, messageList, fromRoomID);
    }
    // ...
})

// ...
public void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromRoomID) {
    try {
        for (ZIMMessage zimMessage : messageList) {
            if (zimMessage instanceof ZIMCommandMessage) {
                ZIMCommandMessage commandMessage = (ZIMCommandMessage) zimMessage;
                String message = new String(commandMessage.message, StandardCharsets.UTF_8);
                JSONObject jsonObject = new JSONObject(message);
                ZIMUserInfo currentUser = zimUserService.getCurrentUser();
                if (jsonObject.has("action_type") && currentUser != null) {
                    String sender = jsonObject.getString("sender_id");
                    String receiver = jsonObject.getString("receiver_id");
                    int actionType = jsonObject.getInt("action_type");

                    if (currentUser.userID.equals(receiver)) {
                        // ...
                    }
                }
            }
        }
    } catch (JSONException e) {
       // ...
    }
}

Further extending RoomRequests

Based on this pattern, when you need to do any protocol extensions in your business, you only need to extend the extended_data field of the RoomRequest to easily implement new business logic, such as:

  • Muting audience: After receiving the corresponding RoomRequest, the UI blocks the user from sending live bullet messages.
  • Sending virtual gifts: After receiving the RoomRequest, show the gift special effects.
  • Removing audience: After receiving the RoomRequest, prompt the audience that they have been removed and exit the room.

Friendly reminder:
After reading the following text and further understanding the implementation of seat-taking request RoomRequests, you will be able to easily extend your business RoomRequests.

The demo in this document is a pure client API + ZEGOCLOUD solution. If you have your own business server and want to do more logical extensions, you can use our Server API to pass RoomRequests and combine your server’s room business logic to increase the reliability of your app.

Seat Taking Sequence Diagram

Implementation

Based on the above technical principles, we will explain the implementation details of the live audio room solution to you in detail.

Integrate and start to use the ZIM SDK

If you have not used the ZIM SDK before, you can read the following section:

Import the ZIM SDK

To import the ZIM SDK, do the following:

1. Set up repositories.
  • If your Android Gradle Plugin is v7.1.0 or later: go to the root directory of your project, open the settings.gradle file, and add the following line to the dependencyResolutionManagement:
...
dependencyResolutionManagement {
   repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
   repositories {
       maven { url 'https://storage.zego.im/maven' }
       mavenCentral()
       google()
   }
}

If you can not find the above fields in settings.gradle, it’s probably because your Android Gradle Plugin version is lower than v7.1.0. For more details, see Android Gradle Plugin Release Note v7.1.0.

  • If your Android Gradle Plugin is earlier than 7.1.0: go to the root directory of your project, open the build.gradle file, and add the following line to the allprojects:
...
allprojects {
repositories {
maven { url 'https://storage.zego.im/maven' }
mavenCentral()
google()
}
}
2. Declare dependencies

Go to the app directory, open the build.gradle file, and add the following line to the dependencies. (x.y.z is the SDK version number. To obtain the latest version number, see ZIM Release Notes.

...
dependencies {
...
implementation 'im.zego:zim:x.y.z'
}

Create and Manage SDK instances

After successful integration, you can use the ZIM SDK like this:

import im.zego.zim.ZIM

Creating a ZIM instance is the very first step, an instance corresponds to a user logging in to the system as a client.

ZIMAppConfig appConfig = new ZIMAppConfig();
appConfig.appID = yourAppID;
appConfig.appSign = yourAppSign;
zim = ZIM.create(appConfig, application);

Later on, we will provide you with detailed instructions on how to use the ZIM SDK to develop the live audio room feature.

Manage Multiple SDKs More Easily

In most cases, you need to use multiple SDKs together. For example, in the live audio room scenario described in this doc, you need to use the ZIM SDK to implement the speak seat management feature, and then use the ZEGO Express Engine SDK to implement the live audio room feature.

If your app has direct calls to SDKs everywhere, it can make the code difficult to manage and troubleshoot. To make your app code more organized, we recommend the following way to manage these SDKs:

1. Create a wrapper layer for each SDK so that you can reuse the code to the greatest extent possible.

Create a ZIMService class for the ZIM SDK, which manages the interaction with the SDK and stores the necessary data. Please refer to the complete code in ZIMService.java.

public class ZIMService {

// ...

public void initSDK(Application application, long appID, String appSign) {
zimProxy.create(application, appID, appSign);
// ...
}
}

class ZIMProxy {

private SimpleZIMEventHandler zimEventHandler;

public void create(Application application, long appID, String appSign) {
ZIMAppConfig zimAppConfig = new ZIMAppConfig();
zimAppConfig.appID = appID;
zimAppConfig.appSign = appSign;
ZIM.create(zimAppConfig, application);

zimEventHandler = new SimpleZIMEventHandler();
if (getZIM() != null) {
ZIM.getInstance().setEventHandler(zimEventHandler);
}
}

}

Similarly, create an ExpressService class for the zego_express_engine sdk, which manages the interaction with the SDK and stores the necessary data. Please refer to the complete code in ExpressService.java.

public class ExpressService {

// ...
public void initSDK(Application application, long appID, String appSign, ZegoScenario scenario) {
ZegoEngineConfig config = new ZegoEngineConfig();
config.advancedConfig.put("notify_remote_device_unknown_status", "true");
config.advancedConfig.put("notify_remote_device_init_status", "true");
ZegoExpressEngine.setEngineConfig(config);
engineProxy.createEngine(application, appID, appSign, scenario);
// ...
}
}

class ExpressEngineProxy {

private SimpleExpressEventHandler expressEventHandler;

public void createEngine(Application application, long appID, String appSign, ZegoScenario scenario) {
ZegoEngineProfile profile = new ZegoEngineProfile();
profile.appID = appID;
profile.appSign = appSign;
profile.scenario = scenario;
profile.application = application;
expressEventHandler = new SimpleExpressEventHandler();
ZegoExpressEngine.createEngine(profile, expressEventHandler);
}
}

With the service, you can add methods to the service whenever you need to use any SDK interface.

For example: Easily add the connectUser method to the ZIMService when you need to implement login.
public class ZIMService {
// ...
public void connectUser(String userID, String userName, String token,ZIMLoggedInCallback callback) {
ZIMUserInfo zimUserInfo = new ZIMUserInfo();
zimUserInfo.userID = userID;
zimUserInfo.userName = userName;
zim.login(zimUserInfo,token, new ZIMLoggedInCallback() {
@Override
public void onLoggedIn(ZIMError errorInfo) {
// ...
}
});
}
}

2. After completing the service encapsulation, you can further simplify the code by creating a ZEGOSDKManager to manage these services, as shown below. Please refer to the complete code in ZEGOSDKManager.java.

public class ZEGOSDKManager {
public ExpressService expressService = new ExpressService();
public ZIMService zimService = new ZIMService();

private static final class Holder {
private static final ZEGOSDKManager INSTANCE = new ZEGOSDKManager();
}

public static ZEGOSDKManager getInstance() {
return Holder.INSTANCE;
}

public void initSDK(Application application, long appID, String appSign,ZegoScenario scenario) {
expressService.initSDK(application, appID, appSign,scenario);
zimService.initSDK(application, appID, appSign);
}
}

3. Now, you have implemented a singleton class that manages the SDK services you need. From now on, you can get an instance of this class anywhere in your project and use it to execute SDK-related logic, such as:

  • When the app starts up: call ZEGOSDKManager.getInstance().initSDK(application,appID,appSign);
  • When login : call ZEGOSDKManager.getInstance().connectUser(userID,userName,callback);

Later, we will introduce how to add a live audio room feature based on this.

Speaker seat management

Later, we will introduce how to add the speaker seat management feature based on that.

Take a speaker seat

  • For an audience to take a speaker seat, call the setRoomAttributes and set the speaker seat number as the key and the audience’s userID as the attribute value in the room’s additional attributes. If the setting is successful, the audience member has successfully taken a speaker seat and can start publishing streams.

Sample code:

public void takeSeat(int seatIndex, ZIMRoomAttributesOperatedCallback callback) {
    ZEGOSDKUser localUser = ZEGOSDKManager.getInstance().expressService.getCurrentUser();
    if (localUser == null || isTakeSeat) {
        return;
    }
    isTakeSeat = true;
    String key = String.valueOf(seatIndex);
    String value = localUser.userID;

    ZIMRoomAttributesSetConfig config = new ZIMRoomAttributesSetConfig();
    config.isDeleteAfterOwnerLeft = true;
    config.isForce = true;
    config.isUpdateOwner = true;
    ZEGOSDKManager.getInstance().zimService.setRoomAttributes(key, value, config,
        new ZIMRoomAttributesOperatedCallback() {
            @Override
            public void onRoomAttributesOperated(String roomID, ArrayList<String> errorKeys, ZIMError errorInfo) {
                isTakeSeat = false;
                if (callback != null) {
                    callback.onRoomAttributesOperated(roomID, errorKeys, errorInfo);
                }
            }
        });
}

The complete reference code can be found at RoomSeatService.java.

Instructions for grabbing the speaker seat: When taking the speaker seat, set the isForce attribute of ZIMRoomAttributesSetConfig to false. When multiple audiences try to take the same speaker seat at the same time, the server will receive the first request and return a successful response, setting the owner of that key to the user who made the request. Subsequent modification requests from other users will fail.

Leave the speaker seat

  • For a speaker to leave the speaker seat, call the deleteRoomAttributes to delete the speaker seat number that the speaker was using, and stop publishing streams.

Sample code:

public void leaveSeat(int seatIndex, ZIMRoomAttributesOperatedCallback callback) {
    ZEGOSDKUser localUser = ZEGOSDKManager.getInstance().expressService.getCurrentUser();
    if (localUser == null) {
        return;
    }
    List<String> list = Collections.singletonList(String.valueOf(seatIndex));
    ZEGOSDKManager.getInstance().zimService.deleteRoomAttributes(list, new ZIMRoomAttributesOperatedCallback() {
        @Override
        public void onRoomAttributesOperated(String roomID, ArrayList<String> errorKeys, ZIMError errorInfo) {
            if (callback != null) {
                callback.onRoomAttributesOperated(roomID, errorKeys, errorInfo);
            }
        }
    });
}

The complete reference code can be found at RoomSeatService.java.

Remove a speaker

When the host needs to remove a speaker from the speaker seat, call the deleteRoomAttributes, and set the isForce field of ZIMRoomAttributesDeleteConfig to true, to force clear the room attributes of the corresponding speaker seat, thereby removing the speaker from the seat.

public void removeSpeakerFromSeat(String userID, ZIMRoomAttributesOperatedCallback callback) {
    ZEGOSDKUser localUser = ZEGOSDKManager.getInstance().expressService.getCurrentUser();
    if (localUser == null) {
        return;
    }
    for (LiveAudioRoomSeat seat : seatList) {
        int seatIndex = seat.seatIndex;
        ZEGOSDKUser seatUser = seat.getUser();
        if (seatUser != null) {
            String seatUserID = seatUser.userID;
            if (Objects.equals(userID, seatUserID)) {
                leaveSeat(seatIndex, callback);
                break;
            }
        }
    }
}

The complete reference code can be found at RoomSeatService.java.

Changing speaker seat

Ignore this section if you are not going to implement the seat changing function.

When a speaker switches from one seat to another, for example, Speaker A switches from the No.2 seat to the No.3 seat, he needs to first delete the room attribute corresponding to the No.2 seat (to leave No.2 seat), and then set the value of the room attribute corresponding to No.3 seat to their own userID (to take No.3 seat). This process involves two steps. Consider the following extreme situation:

When Speaker A has just completed the first step (deleting the room attribute corresponding to the No.2 seat and leaving the No.2 seat), User B takes the No.3 seat ahead of Speaker A, causing Speaker A to successfully leave the No.2 seat but fail to take the No.3 seat.

In this situation, Speaker A loses the speaker seat, which obviously does not meet expectations.

To handle this situation, you need to prevent other users from operating on the relevant speaker seats before Speaker A completes the two-step operation. This can be achieved using the feature of combined operations:

// 1. Start the combined operations.
ZIMRoomAttributesBatchOperationConfig config = new ZIMRoomAttributesBatchOperationConfig();
config.isForce = true;
config.isDeleteAfterOwnerLeft = false;
config.isUpdateOwner = false;
zim.beginRoomAttributesBatchOperation(mRoomID, config);


// 2. Operation 1: leave the No.2 seat
List<String> keys = Collections.singletonList(String.valueOf(3));
ZIMRoomAttributesDeleteConfig config = new ZIMRoomAttributesDeleteConfig();
zim.deleteRoomAttributes(keys, mRoomID, config, callback);

// 3. Operation 2: take the No.3 seat
String key = String.valueOf(2);
String value = localUser.userID;
ZIMRoomAttributesSetConfig config = new ZIMRoomAttributesSetConfig();
config.isDeleteAfterOwnerLeft = true;
config.isForce = false;
HashMap<String, String> attributes = new HashMap<>();
attributes.put(key, value);
zim.setRoomAttributes(attributes, mRoomID, config, callback);


// 4. End the combined operations.
zim.endRoomAttributesBatchOperation(mRoomID, callback);
In the demo, the method is encapsulated as switchSeat.

The complete reference code is as follows:

public void switchSeat(int fromSeatIndex, int toSeatIndex, ZIMRoomAttributesBatchOperatedCallback callback) {
AudioRoomUser localUser = ZEGOSDKManager.getInstance().expressService.getLocalUser();
if (localUser == null) {
return;
}
if (!batchOperation) {
ZEGOSDKManager.getInstance().zimService.beginRoomPropertiesBatchOperation();
batchOperation = true;
tryTakeSeat(toSeatIndex, null);
leaveSeat(fromSeatIndex, null);
ZEGOSDKManager.getInstance().zimService.endRoomPropertiesBatchOperation(
new ZIMRoomAttributesBatchOperatedCallback() {
@Override
public void onRoomAttributesBatchOperated(String roomID, ZIMError errorInfo) {
batchOperation = false;
if (callback != null) {
callback.onRoomAttributesBatchOperated(roomID, errorInfo);
}
}
});
}
}

Room mode

We define the room mode as follows:

Free modeRequest mode
roomExtraInfo{"lockseat":false}{"lockseat":true}

The host can call the setRoomExtraInfo to switch between the Free mode and the Request mode.

public void setHostAndLockSeat() {
    JSONObject extraInfoValueJson = audioRoomExtraInfo.getExtraInfoValueJson();
    try {
        ZEGOSDKUser localUser = ZEGOSDKManager.getInstance().expressService.getCurrentUser();
        JSONObject jsonObject = new JSONObject(extraInfoValueJson.toString());
        jsonObject.put(EXTRA_INFO_VALUE_HOST, localUser.userID);
        jsonObject.put(EXTRA_INFO_VALUE_LOCK_SEAT, true);
        ZEGOSDKManager.getInstance().expressService.setRoomExtraInfo(EXTRA_INFO_KEY, jsonObject.toString());
    } catch (JSONException e) {
        throw new RuntimeException(e);
    }
}

The complete reference code can be found at RoomSeatService.java.

Request to take a speaker seat using roomrequest

Send & Cancel a seat-taking request

The implementation of sending and canceling seat-taking requests is similar, with only the type of RoomRequest being different. Here, sending will be used as an example to explain the implementation of the demo.

In the Demo, a seat-taking request button has been placed in the lower right corner of the LiveAudioRoomActivity as seen from the audience perspective. When the button is clicked, the following actions will be executed.

  1. Encode the JSON RoomRequest, where the action_type is defined as RoomRequestAction.ACTION_REQUEST in the demo.
  2. add room_request_type to extendedData, mark it as REQUEST_TAKE_SEAT;
  3. Call sendRoomRequest to send the RoomRequest. (sendRoomRequest simplifies the sendMessage interface of ZIM SDK.)
  • If the method call is successful: the applying status of the local end (i.e. the audience) will be switched to applying for take a seat, and the seat-taking request button will switch to Cancel Take Seat.
  • If the method call fails: an error message will be prompted. In actual app development, you should use a more user-friendly UI to prompt the failure of the seat-taking request.
@Override
protected void afterClick() {
    super.afterClick();
    // ...
    RoomRequestExtendedData extendedData = new RoomRequestExtendedData();
    extendedData.roomRequestType = RoomRequestType.REQUEST_TAKE_SEAT;
    ZEGOSDKManager.getInstance().zimService.sendRoomRequest(hostUser.userID, jsonObject.toString(),
        new RoomRequestCallback() {
            @Override
            public void onRoomRequestSend(int errorCode, String requestID) {
                if (errorCode == 0) {
                   mRequestID = requestID;
                }
            }
        });
// ... 
}

 public void sendRoomRequest(String receiverID, String extendedData, RoomRequestCallback callback) {
        if (zimProxy.getZIM() == null || currentRoom == null || currentUser == null) {
            return;
        }
        RoomRequest roomRequest = new RoomRequest();
        roomRequest.receiver = receiverID;
        roomRequest.sender = currentUser.userID;
        roomRequest.extendedData = extendedData;
        roomRequest.actionType = RoomRequestAction.ACTION_REQUEST;

        byte[] bytes = roomRequest.toString().getBytes(StandardCharsets.UTF_8);
        ZIMCommandMessage commandMessage = new ZIMCommandMessage(bytes);
        zimProxy.sendMessage(commandMessage, currentRoom.roomID, ZIMConversationType.ROOM, new ZIMMessageSendConfig(),
            new ZIMMessageSentCallback() {
                @Override
                public void onMessageAttached(ZIMMessage message) {

                }

                @Override
                public void onMessageSent(ZIMMessage message, ZIMError errorInfo) {
                    if (errorInfo.code == ZIMErrorCode.SUCCESS) {
                        roomRequest.requestID = String.valueOf(message.getMessageID());
                        roomRequestMap.put(roomRequest.requestID, roomRequest);
                    }
                //...
                }
            });
    }

public void updateUI() {
    RoomRequest roomRequest = ZEGOSDKManager.getInstance().zimService.getRoomRequestByRequestID(mRequestID);
    if (roomRequest == null) {
        setText("Apply to Take Seat");
    } else {
        setText("Cancel Take Seat");
    }
    setBackgroundResource(R.drawable.bg_cohost_btn);
    setCompoundDrawablesWithIntrinsicBounds(R.drawable.liveaudioroom_bottombar_cohost, 0, 0, 0);
}

The complete reference code can be found at TakeSeatButton.java.

Afterwards, the local end (audience end) will wait for the response from the host.

  • If the host rejects the seat-taking request: the applying status of the local end will be switched to not applying.
  • If the host accepts the seat-taking request: the audience became a speaker, and can start publishing streams.

Accept & Reject the seat-taking request

  1. In the demo, when the host receives a seat-taking request RoomRequest, the audience who requested will show in the request list, the host can check the list and choose to accept or reject the audience’s seat-taking request after clicking on the request list.
  2. After the host responds, a RoomRequest of acceptance or rejection will be sent. The related logic of sending RoomRequests will not be further described here.

The relevant code snippet is as follows, and the complete code can be found in RoomRequestListDialog.java and RoomRequestListAdapter.java.

Code snippet

1. Add the audience to the request list after receiving his seat-taking request.

ZEGOSDKManager.getInstance().zimService.addIncomingRoomRequestListener(incomingRoomRequestListener);

// ...

incomingRoomRequestListener = new IZIMEventHandler() {
    public void onInComingRoomRequestReceived(String requestID, String extendedData) {
        RoomRequestExtendedData data = RoomRequestExtendedData.parse(extendedData);
        if (data != null && data.roomRequestType == roomRequestType) {
            RoomRequest request = ZEGOSDKManager.getInstance().zimService.getRoomRequestByRequestID(requestID);
            if (request != null) {
                seatRequestAdapter.addItem(request.sender);
            }
        }
    }

    // ...
}

2. In the user list, the host can choose to click accept or reject.

Add the audience to the request list after receiving his seat-taking request.

ZEGOSDKManager.getInstance().zimService.addIncomingRoomRequestListener(incomingRoomRequestListener);

// ...

incomingRoomRequestListener = new IZIMEventHandler() {
public void onInComingRoomRequestReceived(String requestID, String extendedData) {
RoomRequestExtendedData data = RoomRequestExtendedData.parse(extendedData);
if (data != null && data.roomRequestType == roomRequestType) {
RoomRequest request = ZEGOSDKManager.getInstance().zimService.getRoomRequestByRequestID(requestID);
if (request != null) {
seatRequestAdapter.addItem(request.sender);
}
}
}

// ...
}

In the user list, the host can choose to click accept or reject.

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// ...

agree.setOnClickListener(v -> {
ZEGOSDKManager.getInstance().zimService.acceptRoomRequest(protocol, new RoomRequestCallback() {
@Override
public void onRoomRequestSend(int errorCode, String requestID) {

}
});
});

disagree.setOnClickListener(v -> {
ZEGOSDKManager.getInstance().zimService.rejectRoomRequest(protocol, new RoomRequestCallback() {
@Override
public void onRoomRequestSend(int errorCode, String requestID) {

}
});
});
}

FAQs

How to know if the speaker has turned on the microphone?

You can listen to the onRemoteMicStateUpdate callback notification of Express SDK to determine whether the microphone device of the remote publishing stream device is working normally or turned off, and preliminarily understand the cause of the device problem according to the corresponding state.

This callback will not be triggered when the remote stream is played from the CDN. How to know if a speaker is speaking

How to know if a speaker is speaking?

You can listen to the onRemoteSoundLevelUpdate callback notification of Express SDK to get the sound level of the speaker’s voice.

For details, refer to Visualize the sound level.

Conclusion

Live audio rooms are revolutionizing real-time interaction by fostering meaningful connections and engaging audiences in innovative ways. They provide a virtual space where participants can share their voices, creating immersive experiences that go beyond traditional text-based communication. By following this guide, you now have the tools to set up your own live audio room, equipped with essential features to ensure its success. This powerful medium allows for hosting discussions, facilitating workshops, and building vibrant communities, making your app more interactive and engaging. Sign up today and enjoy 10,000 minutes free of charge to start creating your live audio room today and unlock endless possibilities for connection and engagement! If you have any suggestions or comments, feel free to share them with us via Discord. We value your feedback.

Let’s Build APP Together

Start building with real-time video, voice & chat SDK for apps today!

Talk to us

Take your apps to the next level with our voice, video and chat APIs

Free Trial
  • 10,000 minutes for free
  • 4,000+ corporate clients
  • 3 Billion daily call minutes

Stay updated with us by signing up for our newsletter!

Don't miss out on important news and updates from ZEGOCLOUD!

* You may unsubscribe at any time using the unsubscribe link in the digest email. See our privacy policy for more information.